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.

388 lines
12 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "c_tf_freeaccount.h"
  9. #include "gcsdk/sharedobjectcache.h"
  10. #include "tf_gcmessages.h"
  11. #include "econ_game_account_client.h"
  12. #include "tf_item_inventory.h"
  13. #include "tf_player_info.h"
  14. #include <vgui/ILocalize.h>
  15. #include "confirm_dialog.h"
  16. #include "econ/econ_notifications.h"
  17. #include "select_player_dialog.h"
  18. #include "gc_clientsystem.h"
  19. //-----------------------------------------------------------------------------
  20. class CSelectMostHelpfulFriendDialog : public CSelectPlayerDialog
  21. {
  22. public:
  23. CSelectMostHelpfulFriendDialog( vgui::Panel *parent )
  24. : CSelectPlayerDialog( parent )
  25. , m_iNumFriends( 0 )
  26. , m_bRefreshing( false )
  27. {
  28. }
  29. virtual void UpdatePlayerList()
  30. {
  31. CSelectPlayerDialog::UpdatePlayerList();
  32. vgui::Label *pLabelEmpty = dynamic_cast<vgui::Label*>( m_pStatePanels[m_iCurrentState]->FindChildByName("EmptyPlayerListLabel") );
  33. vgui::Label *pLabelQuery = dynamic_cast<vgui::Label*>( m_pStatePanels[m_iCurrentState]->FindChildByName("QueryLabel") );
  34. vgui::Label *pLabelRetrieving = dynamic_cast<vgui::Label*>( m_pStatePanels[m_iCurrentState]->FindChildByName("RetrievingPlayerListLabel") );
  35. if ( pLabelEmpty )
  36. {
  37. pLabelEmpty->SetVisible( m_bRefreshing == false && pLabelEmpty->IsVisible() );
  38. }
  39. if ( pLabelQuery )
  40. {
  41. pLabelQuery->SetVisible( m_bRefreshing == false && pLabelQuery->IsVisible() );
  42. }
  43. if ( pLabelRetrieving )
  44. {
  45. pLabelRetrieving->SetVisible( m_bRefreshing );
  46. }
  47. }
  48. virtual void Reset()
  49. {
  50. CSelectPlayerDialog::Reset();
  51. m_iNumFriends = 0;
  52. if ( m_bRefreshing == false )
  53. {
  54. RequestFriendsFromGC();
  55. }
  56. }
  57. virtual void SetupSelectFriends()
  58. {
  59. m_PlayerInfoList.Purge();
  60. if ( steamapicontext && steamapicontext->SteamFriends() )
  61. {
  62. // Get our game info so we can use that to test if our friends are connected to the same game as us
  63. FriendGameInfo_t myGameInfo;
  64. CSteamID mySteamID = steamapicontext->SteamUser()->GetSteamID();
  65. steamapicontext->SteamFriends()->GetFriendGamePlayed( mySteamID, &myGameInfo );
  66. int iFriends = steamapicontext->SteamFriends()->GetFriendCount( k_EFriendFlagImmediate );
  67. if ( m_iNumFriends != iFriends )
  68. {
  69. RequestFriendsFromGC();
  70. }
  71. else
  72. {
  73. m_PlayerInfoList = m_FriendsWhoOwnTF2;
  74. }
  75. }
  76. UpdatePlayerList();
  77. }
  78. virtual void OnSelectPlayer( const CSteamID &steamID )
  79. {
  80. GCSDK::CProtoBufMsg<CMsgTFFreeTrialChooseMostHelpfulFriend> msg( k_EMsgGCFreeTrial_ChooseMostHelpfulFriend );
  81. msg.Body().set_account_id_friend( steamID.GetAccountID() );
  82. GCClientSystem()->BSendMessage( msg );
  83. }
  84. void OnTF2FriendsReceived( GCSDK::CProtoBufMsg<CMsgTFRequestTF2FriendsResponse> &msg )
  85. {
  86. // populate the list of friends who own TF2
  87. m_bRefreshing = false;
  88. m_FriendsWhoOwnTF2.Purge();
  89. for ( int i = 0; i < msg.Body().account_ids_size(); ++i )
  90. {
  91. uint32 unAccountID = msg.Body().account_ids( i );
  92. FOR_EACH_VEC( m_EntireFriendsList, j )
  93. {
  94. partner_info_t &info = m_EntireFriendsList[j];
  95. if ( info.m_steamID.GetAccountID() == unAccountID )
  96. {
  97. int idx = m_FriendsWhoOwnTF2.AddToTail();
  98. partner_info_t &infoCopy = m_FriendsWhoOwnTF2[idx];
  99. infoCopy = info;
  100. break;
  101. }
  102. }
  103. }
  104. // update UI
  105. if ( m_iCurrentState == SPDS_SELECTING_FROM_FRIENDS )
  106. {
  107. m_PlayerInfoList = m_FriendsWhoOwnTF2;
  108. UpdatePlayerList();
  109. }
  110. }
  111. protected:
  112. virtual const char *GetResFile() { return "resource/ui/SelectMostHelpfulFriendDialog.res"; }
  113. void RequestFriendsFromGC()
  114. {
  115. // send a message to the GC requesting that it validate which friends own TF2
  116. m_bRefreshing = true;
  117. m_EntireFriendsList.Purge();
  118. m_FriendsWhoOwnTF2.Purge();
  119. if ( steamapicontext && steamapicontext->SteamFriends() )
  120. {
  121. // Get our game info so we can use that to test if our friends are connected to the same game as us
  122. FriendGameInfo_t myGameInfo;
  123. CSteamID mySteamID = steamapicontext->SteamUser()->GetSteamID();
  124. steamapicontext->SteamFriends()->GetFriendGamePlayed( mySteamID, &myGameInfo );
  125. m_iNumFriends = steamapicontext->SteamFriends()->GetFriendCount( k_EFriendFlagImmediate );
  126. if ( m_iNumFriends > 0 )
  127. {
  128. GCSDK::CProtoBufMsg<CMsgTFRequestTF2Friends> msg( k_EMsgGCRequestTF2Friends );
  129. for ( int i = 0; i < m_iNumFriends; i++ )
  130. {
  131. CSteamID friendSteamID = steamapicontext->SteamFriends()->GetFriendByIndex( i, k_EFriendFlagImmediate );
  132. const char *pszName = steamapicontext->SteamFriends()->GetFriendPersonaName( friendSteamID );
  133. int idx = m_EntireFriendsList.AddToTail();
  134. partner_info_t &info = m_EntireFriendsList[idx];
  135. info.m_steamID = friendSteamID;
  136. info.m_name = pszName;
  137. msg.Body().add_account_ids( friendSteamID.GetAccountID() );
  138. }
  139. GCClientSystem()->BSendMessage( msg );
  140. }
  141. else
  142. {
  143. m_bRefreshing = false;
  144. }
  145. }
  146. }
  147. // data
  148. bool m_bRefreshing;
  149. int m_iNumFriends;
  150. CUtlVector<partner_info_t> m_EntireFriendsList;
  151. CUtlVector<partner_info_t> m_FriendsWhoOwnTF2;
  152. };
  153. static vgui::DHANDLE<CSelectMostHelpfulFriendDialog> g_hSelectMostHelpfulFriendDialog;
  154. /**
  155. * Notification that the player should choose their most helpful friend.
  156. */
  157. class CSelectHelpfulFriendNotification : public CEconNotification
  158. {
  159. public:
  160. CSelectHelpfulFriendNotification() {}
  161. virtual void Accept()
  162. {
  163. OpenSelectMostHelpfulFriendDialog( NULL );
  164. MarkForDeletion();
  165. }
  166. virtual void Decline()
  167. {
  168. MarkForDeletion();
  169. }
  170. virtual EType NotificationType() { return eType_AcceptDecline; }
  171. void Trigger()
  172. {
  173. OpenSelectMostHelpfulFriendDialog( NULL );
  174. MarkForDeletion();
  175. }
  176. static bool RemoveOtherNotifications( CEconNotification *pNotification )
  177. {
  178. return dynamic_cast< CSelectHelpfulFriendNotification* >( pNotification ) != NULL;
  179. }
  180. };
  181. class CWasThankedBySomeoneNotification : public CEconNotification
  182. {
  183. public:
  184. CWasThankedBySomeoneNotification( const CSteamID& steamID )
  185. {
  186. SetText( "#TF_Trial_Alert_ThankedBySomeone" );
  187. SetLifetime( 30.0f );
  188. {
  189. extern void GetPlayerNameBySteamID( const CSteamID &steamID, OUT_Z_CAP(maxLenInChars) char *pDestBuffer, int maxLenInChars );
  190. wchar_t wszPlayerName[ MAX_PLAYER_NAME_LENGTH ];
  191. char szPlayerName[ MAX_PLAYER_NAME_LENGTH ];
  192. GetPlayerNameBySteamID( steamID, szPlayerName, sizeof( szPlayerName ) );
  193. g_pVGuiLocalize->ConvertANSIToUnicode( szPlayerName, wszPlayerName, sizeof( wszPlayerName ) );
  194. AddStringToken( "thanker", wszPlayerName );
  195. }
  196. }
  197. static bool RemoveOtherNotifications( CEconNotification *pNotification )
  198. {
  199. return dynamic_cast< CWasThankedBySomeoneNotification* >( pNotification ) != NULL;
  200. }
  201. };
  202. #ifdef _DEBUG
  203. CON_COMMAND( cl_free_trial_select_friend, "Bring up dialog to select most helpful friend" )
  204. {
  205. OpenSelectMostHelpfulFriendDialog( NULL );
  206. }
  207. CON_COMMAND( cl_thanks_test, "Tests the thanked ui notification." )
  208. {
  209. if ( steamapicontext == NULL || steamapicontext->SteamUser() == NULL )
  210. return;
  211. CSteamID steamID = steamapicontext->SteamUser()->GetSteamID();
  212. NotificationQueue_Add( new CWasThankedBySomeoneNotification( steamID ) );
  213. }
  214. #endif
  215. class CGCRequestTF2FriendsResponse : public GCSDK::CGCClientJob
  216. {
  217. public:
  218. CGCRequestTF2FriendsResponse( GCSDK::CGCClient *pClient ) : GCSDK::CGCClientJob( pClient ) {}
  219. virtual bool BYieldingRunGCJob( GCSDK::IMsgNetPacket *pNetPacket )
  220. {
  221. GCSDK::CProtoBufMsg<CMsgTFRequestTF2FriendsResponse> msg( pNetPacket );
  222. if ( g_hSelectMostHelpfulFriendDialog.Get() )
  223. {
  224. g_hSelectMostHelpfulFriendDialog->OnTF2FriendsReceived( msg );
  225. }
  226. return true;
  227. }
  228. };
  229. GC_REG_JOB( GCSDK::CGCClient, CGCRequestTF2FriendsResponse, "CGCRequestTF2FriendsResponse", k_EMsgGCRequestTF2FriendsResponse, GCSDK::k_EServerTypeGCClient );
  230. class CGCThankedBySomeone : public GCSDK::CGCClientJob
  231. {
  232. public:
  233. CGCThankedBySomeone( GCSDK::CGCClient *pClient ) : GCSDK::CGCClientJob( pClient ) {}
  234. virtual bool BYieldingRunGCJob( GCSDK::IMsgNetPacket *pNetPacket )
  235. {
  236. GCSDK::CProtoBufMsg<CMsgTFThankedBySomeone> msg( pNetPacket );
  237. NotificationQueue_Add( new CWasThankedBySomeoneNotification( CSteamID( msg.Body().thanker_steam_id() ) ) );
  238. return true;
  239. }
  240. };
  241. GC_REG_JOB( GCSDK::CGCClient, CGCThankedBySomeone, "CGCThankedBySomeone", k_EMsgGCFreeTrial_ThankedBySomeone, GCSDK::k_EServerTypeGCClient );
  242. class CGCThankedSomeone : public GCSDK::CGCClientJob
  243. {
  244. public:
  245. CGCThankedSomeone( GCSDK::CGCClient *pClient ) : GCSDK::CGCClientJob( pClient ) {}
  246. virtual bool BYieldingRunGCJob( GCSDK::IMsgNetPacket *pNetPacket )
  247. {
  248. ShowMessageBox( "#TF_Trial_ThankSuccess_Title", "#TF_Trial_ThankSuccess_Text", "#GameUI_OK" );
  249. return true;
  250. }
  251. };
  252. GC_REG_JOB( GCSDK::CGCClient, CGCThankedSomeone, "CGCThankedSomeone", k_EMsgGCFreeTrial_ThankedSomeone, GCSDK::k_EServerTypeGCClient );
  253. class CGCFreeTrialConvertedToPremium : public GCSDK::CGCClientJob
  254. {
  255. public:
  256. CGCFreeTrialConvertedToPremium( GCSDK::CGCClient *pClient ) : GCSDK::CGCClientJob( pClient ) {}
  257. virtual bool BYieldingRunGCJob( GCSDK::IMsgNetPacket *pNetPacket )
  258. {
  259. ShowMessageBox( "#TF_Trial_Converted_Title", "#TF_Trial_Converted_Text", "#GameUI_OK" );
  260. return true;
  261. }
  262. };
  263. GC_REG_JOB( GCSDK::CGCClient, CGCFreeTrialConvertedToPremium, "CGCFreeTrialConvertedToPremium", k_EMsgGCFreeTrial_ConvertedToPremium, GCSDK::k_EServerTypeGCClient );
  264. //-----------------------------------------------------------------------------
  265. // External API
  266. #if _DEBUG
  267. ConVar tf_forcetrialaccount( "tf_forcetrialaccount", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE );
  268. #endif
  269. #ifdef STAGING_ONLY
  270. ConVar tf_thank_a_friend_enabled( "tf_thank_a_friend_enabled", "1", FCVAR_CLIENTDLL | FCVAR_ARCHIVE );
  271. #endif // STAGING_ONLY
  272. bool IsFreeTrialAccount()
  273. {
  274. #if _DEBUG
  275. if ( tf_forcetrialaccount.GetBool() )
  276. return true;
  277. #endif
  278. if ( InventoryManager() && TFInventoryManager()->GetLocalTFInventory() && TFInventoryManager()->GetLocalTFInventory()->GetSOC() )
  279. {
  280. CEconGameAccountClient *pGameAccountClient = TFInventoryManager()->GetLocalTFInventory()->GetSOC()->GetSingleton<CEconGameAccountClient>();
  281. if ( pGameAccountClient )
  282. return pGameAccountClient->Obj().trial_account();
  283. }
  284. return false;
  285. }
  286. bool NeedsToChooseMostHelpfulFriend()
  287. {
  288. #ifdef STAGING_ONLY
  289. if ( tf_thank_a_friend_enabled.GetBool() )
  290. #endif // STAGING_ONLY
  291. {
  292. if ( InventoryManager() && TFInventoryManager()->GetLocalTFInventory() && TFInventoryManager()->GetLocalTFInventory()->GetSOC() )
  293. {
  294. CEconGameAccountClient *pGameAccountClient = TFInventoryManager()->GetLocalTFInventory()->GetSOC()->GetSingleton<CEconGameAccountClient>();
  295. if ( pGameAccountClient )
  296. {
  297. return !pGameAccountClient->Obj().trial_account()
  298. && pGameAccountClient->Obj().need_to_choose_most_helpful_friend();
  299. }
  300. }
  301. }
  302. return false;
  303. }
  304. void NotifyNeedsToChooseMostHelpfulFriend()
  305. {
  306. // remove duplicates
  307. NotificationQueue_Remove( &CSelectHelpfulFriendNotification::RemoveOtherNotifications );
  308. // add new notification
  309. CSelectHelpfulFriendNotification *pNotification = new CSelectHelpfulFriendNotification();
  310. pNotification->SetText( "#TF_Trial_Alert_SelectFriend" );
  311. pNotification->SetLifetime( 120.0f );
  312. NotificationQueue_Add( pNotification );
  313. }
  314. CSelectPlayerDialog *OpenSelectMostHelpfulFriendDialog( vgui::Panel *pParent )
  315. {
  316. if (!g_hSelectMostHelpfulFriendDialog.Get())
  317. {
  318. g_hSelectMostHelpfulFriendDialog = vgui::SETUP_PANEL( new CSelectMostHelpfulFriendDialog( pParent ) );
  319. }
  320. g_hSelectMostHelpfulFriendDialog->InvalidateLayout( false, true );
  321. g_hSelectMostHelpfulFriendDialog->Reset();
  322. g_hSelectMostHelpfulFriendDialog->SetVisible( true );
  323. g_hSelectMostHelpfulFriendDialog->MakePopup();
  324. g_hSelectMostHelpfulFriendDialog->MoveToFront();
  325. g_hSelectMostHelpfulFriendDialog->SetKeyBoardInputEnabled(true);
  326. g_hSelectMostHelpfulFriendDialog->SetMouseInputEnabled(true);
  327. TFModalStack()->PushModal( g_hSelectMostHelpfulFriendDialog );
  328. return g_hSelectMostHelpfulFriendDialog;
  329. }