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.

1061 lines
38 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Display a list of achievements for the current game
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "achievements_page.h"
  8. #include "vgui_controls/Button.h"
  9. #include "vgui/ILocalize.h"
  10. #include "ixboxsystem.h"
  11. #include "iachievementmgr.h"
  12. #include "filesystem.h"
  13. #include "vgui_controls/ImagePanel.h"
  14. #include "vgui_controls/ComboBox.h"
  15. #include "vgui_controls/CheckButton.h"
  16. #include "fmtstr.h"
  17. #include "c_cs_playerresource.h"
  18. #include "stat_card.h"
  19. #include <vgui/IInput.h>
  20. #include "../../../public/steam/steam_api.h"
  21. #include "achievementmgr.h"
  22. #include "../../../../public/vgui/IScheme.h"
  23. #include "../vgui_controls/ScrollBar.h"
  24. #include "achievements_cs.h"
  25. extern CAchievementMgr g_AchievementMgrCS;
  26. using namespace vgui;
  27. // memdbgon must be the last include file in a .cpp file!!!
  28. #include "tier0/memdbgon.h"
  29. KeyValues *g_pPreloadedCSAchievementPageItemLayout = NULL;
  30. KeyValues *g_pPreloadedCSAchievementPageGroupLayout = NULL;
  31. // Shared helper functions so xbox and pc can share as much code as possible while coming from different bases.
  32. //-----------------------------------------------------------------------------
  33. // Purpose: Sets the parameter pIconPanel to display the specified achievement's icon file.
  34. //-----------------------------------------------------------------------------
  35. bool CSLoadAchievementIconForPage( vgui::ImagePanel* pIconPanel, CCSBaseAchievement* pAchievement, const char *pszExt /*= NULL*/ )
  36. {
  37. char imagePath[_MAX_PATH];
  38. Q_strncpy( imagePath, "achievements\\", sizeof(imagePath) );
  39. Q_strncat( imagePath, pAchievement->GetName(), sizeof(imagePath), COPY_ALL_CHARACTERS );
  40. if ( pszExt )
  41. {
  42. Q_strncat( imagePath, pszExt, sizeof(imagePath), COPY_ALL_CHARACTERS );
  43. }
  44. Q_strncat( imagePath, ".vtf", sizeof(imagePath), COPY_ALL_CHARACTERS );
  45. char checkFile[_MAX_PATH];
  46. Q_snprintf( checkFile, sizeof(checkFile), "materials\\vgui\\%s", imagePath );
  47. if ( !g_pFullFileSystem->FileExists( checkFile ) )
  48. {
  49. Q_snprintf( imagePath, sizeof(imagePath), "hud\\icon_locked.vtf" );
  50. }
  51. pIconPanel->SetShouldScaleImage( true );
  52. pIconPanel->SetImage( imagePath );
  53. pIconPanel->SetVisible( true );
  54. return pIconPanel->IsVisible();
  55. }
  56. //-----------------------------------------------------------------------------
  57. // Purpose: Sets the parameter pIconPanel to display the specified achievement's icon file.
  58. //-----------------------------------------------------------------------------
  59. bool CSLoadIconForPage( vgui::ImagePanel* pIconPanel, const char* pFilename, const char *pszExt /*= NULL*/ )
  60. {
  61. char imagePath[_MAX_PATH];
  62. Q_strncpy( imagePath, "achievements\\", sizeof(imagePath) );
  63. Q_strncat( imagePath, pFilename, sizeof(imagePath), COPY_ALL_CHARACTERS );
  64. if ( pszExt )
  65. {
  66. Q_strncat( imagePath, pszExt, sizeof(imagePath), COPY_ALL_CHARACTERS );
  67. }
  68. Q_strncat( imagePath, ".vtf", sizeof(imagePath), COPY_ALL_CHARACTERS );
  69. char checkFile[_MAX_PATH];
  70. Q_snprintf( checkFile, sizeof(checkFile), "materials\\vgui\\%s", imagePath );
  71. if ( !g_pFullFileSystem->FileExists( checkFile ) )
  72. {
  73. Q_snprintf( imagePath, sizeof(imagePath), "hud\\icon_locked.vtf" );
  74. }
  75. pIconPanel->SetShouldScaleImage( true );
  76. pIconPanel->SetImage( imagePath );
  77. pIconPanel->SetVisible( true );
  78. return pIconPanel->IsVisible();
  79. }
  80. //-----------------------------------------------------------------------------
  81. // The bias is to ensure the percentage bar gets plenty orange before it reaches the text,
  82. // as the white-on-grey is hard to read.
  83. //-----------------------------------------------------------------------------
  84. Color CSLerpColorsForPage ( Color cStart, Color cEnd, float flPercent )
  85. {
  86. float r = (float)((float)(cStart.r()) + (float)(cEnd.r() - cStart.r()) * Bias( flPercent, 0.75 ) );
  87. float g = (float)((float)(cStart.g()) + (float)(cEnd.g() - cStart.g()) * Bias( flPercent, 0.75 ) );
  88. float b = (float)((float)(cStart.b()) + (float)(cEnd.b() - cStart.b()) * Bias( flPercent, 0.75 ) );
  89. float a = (float)((float)(cStart.a()) + (float)(cEnd.a() - cStart.a()) * Bias( flPercent, 0.75 ) );
  90. return Color( r, g, b, a );
  91. }
  92. //-----------------------------------------------------------------------------
  93. // Purpose: Shares common percentage bar calculations/color settings between xbox and pc.
  94. // Not really intended for robustness or reuse across many panels.
  95. // Input : pFrame - assumed to have certain child panels (see below)
  96. // *pAchievement - source achievement to poll for progress. Non progress achievements will not show a percentage bar.
  97. //-----------------------------------------------------------------------------
  98. void CSUpdateProgressBarForPage( vgui::EditablePanel* pPanel, CCSBaseAchievement* pAchievement, Color clrProgressBar )
  99. {
  100. ///*
  101. if ( pAchievement->GetGoal() > 1 )
  102. {
  103. bool bShowProgress = true;
  104. // if this achievement gets saved with game and we're not in a level and have not achieved it, then we do not have any state
  105. // for this achievement, don't show progress
  106. if ( ( pAchievement->GetFlags() & ACH_SAVE_WITH_GAME ) && /*!GameUI().IsInLevel() &&*/ !pAchievement->IsAchieved() )
  107. {
  108. bShowProgress = false;
  109. }
  110. float flCompletion = 0.0f;
  111. // Once achieved, we can't rely on count. If they've completed the achievement just set to 100%.
  112. int iCount = pAchievement->GetCount();
  113. if ( pAchievement->IsAchieved() )
  114. {
  115. flCompletion = 1.0f;
  116. iCount = pAchievement->GetGoal();
  117. }
  118. else if ( bShowProgress )
  119. {
  120. flCompletion = ( ((float)pAchievement->GetCount()) / ((float)pAchievement->GetGoal()) );
  121. // In rare cases count can exceed goal and not be achieved (switch local storage on X360, take saved game from different user on PC).
  122. // These will self-correct with continued play, but if we're in that state don't show more than 100% achieved.
  123. flCompletion = MIN( flCompletion, 1.0 );
  124. }
  125. char szPercentageText[ 256 ] = "";
  126. if ( bShowProgress )
  127. {
  128. Q_snprintf( szPercentageText, 256, "%d/%d", iCount, pAchievement->GetGoal() );
  129. }
  130. pPanel->SetControlString( "PercentageText", szPercentageText );
  131. pPanel->SetControlVisible( "PercentageText", true );
  132. pPanel->SetControlVisible( "CompletionText", true );
  133. vgui::ImagePanel *pPercentageBar = (vgui::ImagePanel*)pPanel->FindChildByName( "PercentageBar" );
  134. vgui::ImagePanel *pPercentageBarBkg = (vgui::ImagePanel*)pPanel->FindChildByName( "PercentageBarBackground" );
  135. if ( pPercentageBar && pPercentageBarBkg )
  136. {
  137. pPercentageBar->SetFillColor( clrProgressBar );
  138. pPercentageBar->SetWide( pPercentageBarBkg->GetWide() * flCompletion );
  139. pPanel->SetControlVisible( "PercentageBarBackground", IsX360() ? bShowProgress : true );
  140. pPanel->SetControlVisible( "PercentageBar", true );
  141. }
  142. }
  143. //*/
  144. }
  145. // TODO: revisit this once other games are rebuilt using the updated IAchievement interface
  146. bool CSGameSupportsAchievementTrackerForPage()
  147. {
  148. const char *pGame = Q_UnqualifiedFileName( engine->GetGameDirectory() );
  149. return ( !Q_stricmp( pGame, "cstrike" ) );
  150. }
  151. //////////////////////////////////////////////////////////////////////////
  152. // PC Implementation
  153. //////////////////////////////////////////////////////////////////////////
  154. int AchivementSortPredicate( CCSBaseAchievement* const* pLeft, CCSBaseAchievement* const* pRight )
  155. {
  156. if ( (*pLeft)->IsAchieved() && !(*pRight)->IsAchieved() )
  157. return -1;
  158. if ( !(*pLeft)->IsAchieved() && (*pRight)->IsAchieved() )
  159. return 1;
  160. if ( (*pLeft)->GetAchievementID() < (*pRight)->GetAchievementID() )
  161. return -1;
  162. if ( (*pLeft)->GetAchievementID() > (*pRight)->GetAchievementID() )
  163. return 1;
  164. return 0;
  165. }
  166. //-----------------------------------------------------------------------------
  167. // Purpose: creates child panels, passes down name to pick up any settings from res files.
  168. //-----------------------------------------------------------------------------
  169. CAchievementsPage::CAchievementsPage(vgui::Panel *parent, const char *name) : BaseClass(parent, "CSAchievementsDialog")
  170. {
  171. m_iFixedWidth = 900; // Give this an initial value in order to set a proper size
  172. SetBounds(0, 0, 900, 780);
  173. SetMinimumSize( 256, 780 );
  174. m_pStatCard = new StatCard(this, "ignored");
  175. m_pAchievementsList = new vgui::PanelListPanel( this, "listpanel_achievements" );
  176. m_pAchievementsList->SetFirstColumnWidth( 0 );
  177. m_pGroupsList = new vgui::PanelListPanel( this, "listpanel_groups" );
  178. m_pGroupsList->SetFirstColumnWidth( 0 );
  179. m_pListBG = new vgui::ImagePanel( this, "listpanel_background" );
  180. m_pPercentageBarBackground = SETUP_PANEL( new ImagePanel( this, "PercentageBarBackground" ) );
  181. m_pPercentageBar = SETUP_PANEL( new ImagePanel( this, "PercentageBar" ) );
  182. ListenForGameEvent( "player_stats_updated" );
  183. ListenForGameEvent( "achievement_earned_local" );
  184. // int that holds the highest number achievement id we've found
  185. int iHighestAchievementIDSeen = -1;
  186. int iNextGroupBoundary = 1000;
  187. Q_memset( m_AchievementGroups, 0, sizeof(m_AchievementGroups) );
  188. m_iNumAchievementGroups = 0;
  189. // Base groups
  190. int iCount = g_AchievementMgrCS.GetAchievementCount();
  191. for ( int i = 0; i < iCount; ++i )
  192. {
  193. CCSBaseAchievement* pAchievement = dynamic_cast<CCSBaseAchievement*>(g_AchievementMgrCS.GetAchievementByIndex( i ));
  194. if ( !pAchievement )
  195. continue;
  196. int iAchievementID = pAchievement->GetAchievementID();
  197. if ( iAchievementID > iHighestAchievementIDSeen )
  198. {
  199. // if it's crossed the next group boundary, create a new group
  200. if ( iAchievementID >= iNextGroupBoundary )
  201. {
  202. int iNewGroupBoundary = iAchievementID;
  203. CreateNewAchievementGroup( iNewGroupBoundary, iNewGroupBoundary+99 );
  204. iNextGroupBoundary = iNewGroupBoundary + 100;
  205. }
  206. iHighestAchievementIDSeen = iAchievementID;
  207. }
  208. }
  209. LoadControlSettings("resource/ui/CSAchievementsDialog.res");
  210. UpdateTotalProgressDisplay();
  211. CreateOrUpdateComboItems( true );
  212. // Default display shows the first achievement group
  213. UpdateAchievementList(1001, 1100);
  214. m_bStatsDirty = true;
  215. m_bAchievementsDirty = true;
  216. }
  217. CAchievementsPage::~CAchievementsPage()
  218. {
  219. g_AchievementMgrCS.SaveGlobalStateIfDirty( false ); // check for saving here to store achievements we want pinned to HUD
  220. m_pAchievementsList->DeleteAllItems();
  221. delete m_pAchievementsList;
  222. delete m_pPercentageBarBackground;
  223. delete m_pPercentageBar;
  224. }
  225. void CAchievementsPage::CreateNewAchievementGroup( int iMinRange, int iMaxRange )
  226. {
  227. m_AchievementGroups[m_iNumAchievementGroups].m_iMinRange = iMinRange;
  228. m_AchievementGroups[m_iNumAchievementGroups].m_iMaxRange = iMaxRange;
  229. m_iNumAchievementGroups++;
  230. }
  231. //----------------------------------------------------------
  232. // Get the width we're going to lock at
  233. //----------------------------------------------------------
  234. void CAchievementsPage::ApplySettings( KeyValues *pResourceData )
  235. {
  236. m_iFixedWidth = pResourceData->GetInt( "wide", 512 );
  237. BaseClass::ApplySettings( pResourceData );
  238. }
  239. //----------------------------------------------------------
  240. // Preserve our width to the one in the .res file
  241. //----------------------------------------------------------
  242. void CAchievementsPage::OnSizeChanged(int newWide, int newTall)
  243. {
  244. // Lock the width, but allow height scaling
  245. if ( newWide != m_iFixedWidth )
  246. {
  247. SetSize( m_iFixedWidth, newTall );
  248. return;
  249. }
  250. BaseClass::OnSizeChanged(newWide, newTall);
  251. }
  252. //----------------------------------------------------------
  253. // Re-populate the achievement list with the selected group
  254. //----------------------------------------------------------
  255. void CAchievementsPage::UpdateAchievementList(CAchievementsPageGroupPanel* groupPanel)
  256. {
  257. if (!groupPanel)
  258. return;
  259. UpdateAchievementList( groupPanel->GetFirstAchievementID(), groupPanel->GetLastAchievementID() );
  260. vgui::IScheme *pGroupScheme = scheme()->GetIScheme( GetScheme() );
  261. // Update active status for button display
  262. for (int i = 0; i < m_pGroupsList->GetItemCount(); i++)
  263. {
  264. CAchievementsPageGroupPanel *pPanel = (CAchievementsPageGroupPanel*)m_pGroupsList->GetItemPanel(i);
  265. if ( pPanel )
  266. {
  267. if ( pPanel != groupPanel )
  268. {
  269. pPanel->SetGroupActive( false );
  270. }
  271. else
  272. {
  273. pPanel->SetGroupActive( true );
  274. }
  275. pPanel->UpdateAchievementInfo( pGroupScheme );
  276. }
  277. }
  278. }
  279. void CAchievementsPage::UpdateTotalProgressDisplay()
  280. {
  281. // Set up total completion percentage bar
  282. float flCompletion = 0.0f;
  283. int iCount = g_AchievementMgrCS.GetAchievementCount();
  284. int nUnlocked = 0;
  285. if ( iCount > 0 )
  286. {
  287. for ( int i = 0; i < iCount; ++i )
  288. {
  289. CCSBaseAchievement* pAchievement = dynamic_cast<CCSBaseAchievement*>(g_AchievementMgrCS.GetAchievementByIndex( i ));
  290. if ( pAchievement && pAchievement->IsAchieved() )
  291. ++nUnlocked;
  292. }
  293. flCompletion = (((float)nUnlocked) / ((float)g_AchievementMgrCS.GetAchievementCount()));
  294. }
  295. char szPercentageText[64];
  296. V_sprintf_safe( szPercentageText, "%d / %d",
  297. nUnlocked, g_AchievementMgrCS.GetAchievementCount() );
  298. SetControlString( "PercentageText", szPercentageText );
  299. SetControlVisible( "PercentageText", true );
  300. SetControlVisible( "CompletionText", true );
  301. vgui::IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
  302. Color clrHighlight = pScheme->GetColor( "NewGame.SelectionColor", Color(255, 255, 255, 255) );
  303. Color clrWhite(255, 255, 255, 255);
  304. Color cProgressBar = Color( static_cast<float>( clrHighlight.r() ) * ( 1.0f - flCompletion ) + static_cast<float>( clrWhite.r() ) * flCompletion,
  305. static_cast<float>( clrHighlight.g() ) * ( 1.0f - flCompletion ) + static_cast<float>( clrWhite.g() ) * flCompletion,
  306. static_cast<float>( clrHighlight.b() ) * ( 1.0f - flCompletion ) + static_cast<float>( clrWhite.b() ) * flCompletion,
  307. static_cast<float>( clrHighlight.a() ) * ( 1.0f - flCompletion ) + static_cast<float>( clrWhite.a() ) * flCompletion );
  308. m_pPercentageBar->SetFgColor( cProgressBar );
  309. m_pPercentageBar->SetWide( m_pPercentageBarBackground->GetWide() * flCompletion );
  310. SetControlVisible( "PercentageBarBackground", true );
  311. SetControlVisible( "PercentageBar", true );
  312. }
  313. //----------------------------------------------------------
  314. // Re-populate the achievement list with the selected group
  315. //----------------------------------------------------------
  316. void CAchievementsPage::UpdateAchievementList(int minID, int maxID)
  317. {
  318. int iMinRange = minID;
  319. int iMaxRange = maxID;
  320. int iCount = g_AchievementMgrCS.GetAchievementCount();
  321. CUtlVector<CCSBaseAchievement*> sortedAchivementList;
  322. sortedAchivementList.EnsureCapacity(iCount);
  323. for ( int i = 0; i < iCount; ++i )
  324. {
  325. CCSBaseAchievement* pAchievement = dynamic_cast<CCSBaseAchievement*>(g_AchievementMgrCS.GetAchievementByIndex(i));
  326. if ( !pAchievement )
  327. continue;
  328. int iAchievementID = pAchievement->GetAchievementID();
  329. if ( iAchievementID < iMinRange || iAchievementID > iMaxRange )
  330. continue;
  331. // don't show hidden achievements if not achieved
  332. if ( pAchievement->ShouldHideUntilAchieved() && !pAchievement->IsAchieved() )
  333. continue;
  334. sortedAchivementList.AddToTail(pAchievement);
  335. }
  336. sortedAchivementList.Sort(AchivementSortPredicate);
  337. m_pAchievementsList->DeleteAllItems();
  338. FOR_EACH_VEC(sortedAchivementList, i)
  339. {
  340. CCSBaseAchievement* pAchievement = sortedAchivementList[i];
  341. CAchievementsPageItemPanel *pAchievementItemPanel = new CAchievementsPageItemPanel( m_pAchievementsList, "AchievementDialogItemPanel");
  342. pAchievementItemPanel->SetAchievementInfo(pAchievement);
  343. // force all our new panel to have the correct internal layout and size so that our parent container can layout properly
  344. pAchievementItemPanel->InvalidateLayout(true, true);
  345. m_pAchievementsList->AddItem( NULL, pAchievementItemPanel );
  346. }
  347. m_pAchievementsList->MoveScrollBarToTop();
  348. }
  349. //-----------------------------------------------------------------------------
  350. // Purpose: Loads settings from achievementsdialog.res in hl2/resource/ui/
  351. // Sets up progress bar displaying total achievement unlocking progress by the user.
  352. //-----------------------------------------------------------------------------
  353. void CAchievementsPage::ApplySchemeSettings( vgui::IScheme *pScheme )
  354. {
  355. BaseClass::ApplySchemeSettings( pScheme );
  356. m_pGroupsList->SetBgColor(Color(86,86,86,255));
  357. SetBgColor(Color(86,86,86,255));
  358. // Set text color for percentage
  359. Panel *pPanel;
  360. pPanel = FindChildByName("PercentageText");
  361. if (pPanel)
  362. {
  363. pPanel->SetFgColor(Color(157, 194, 80, 255));
  364. }
  365. // Set text color for achievement earned label
  366. pPanel = FindChildByName("AchievementsEarnedLabel");
  367. if (pPanel)
  368. {
  369. pPanel->SetFgColor(Color(157, 194, 80, 255));
  370. }
  371. }
  372. //-----------------------------------------------------------------------------
  373. // Purpose: Each sub-panel gets its data updated
  374. //-----------------------------------------------------------------------------
  375. void CAchievementsPage::UpdateAchievementDialogInfo( void )
  376. {
  377. // Hide the group list scrollbar
  378. if (m_pGroupsList->GetScrollbar())
  379. {
  380. m_pGroupsList->GetScrollbar()->SetWide(0);
  381. }
  382. int iCount = m_pAchievementsList->GetItemCount();
  383. vgui::IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
  384. int i;
  385. for ( i = 0; i < iCount; i++ )
  386. {
  387. CAchievementsPageItemPanel *pPanel = (CAchievementsPageItemPanel*)m_pAchievementsList->GetItemPanel(i);
  388. if ( pPanel )
  389. {
  390. pPanel->UpdateAchievementInfo( pScheme );
  391. }
  392. }
  393. // Update all group panels
  394. int iGroupCount = m_pGroupsList->GetItemCount();
  395. for ( i = 0; i < iGroupCount; i++ )
  396. {
  397. CAchievementsPageGroupPanel *pPanel = (CAchievementsPageGroupPanel*)m_pGroupsList->GetItemPanel(i);
  398. if ( pPanel )
  399. {
  400. pPanel->UpdateAchievementInfo( pScheme );
  401. if ( pPanel->IsGroupActive() )
  402. {
  403. UpdateAchievementList( pPanel );
  404. }
  405. }
  406. }
  407. // update the groups and overall progress bar
  408. CreateOrUpdateComboItems( false ); // update them with new achieved counts
  409. UpdateTotalProgressDisplay();
  410. m_pStatCard->UpdateInfo();
  411. m_bAchievementsDirty = false;
  412. m_bStatsDirty = false;
  413. }
  414. void CAchievementsPage::CreateOrUpdateComboItems( bool bCreate )
  415. {
  416. // Build up achievement group names
  417. for ( int i=0;i<m_iNumAchievementGroups;i++ )
  418. {
  419. char buf[128];
  420. int achievementRangeStart = (m_AchievementGroups[i].m_iMinRange / 1000) * 1000;
  421. Q_snprintf( buf, sizeof(buf), "#Achievement_Group_%d", achievementRangeStart );
  422. wchar_t *wzGroupName = g_pVGuiLocalize->Find( buf );
  423. if ( !wzGroupName )
  424. {
  425. wzGroupName = L"Need Title ( %s1 of %s2 )";
  426. }
  427. wchar_t wzGroupTitle[128];
  428. if ( wzGroupName )
  429. {
  430. // Determine number of achievements in the group which have been awarded
  431. int numAwarded = 0;
  432. int numTested = 0;
  433. for (int j = m_AchievementGroups[i].m_iMinRange; j < m_AchievementGroups[i].m_iMaxRange; j++)
  434. {
  435. IAchievement* pCur = g_AchievementMgrCS.GetAchievementByID( j );
  436. if ( !pCur )
  437. continue;
  438. numTested++;
  439. if ( pCur->IsAchieved() )
  440. {
  441. numAwarded++;
  442. }
  443. }
  444. wchar_t wzNumUnlocked[8];
  445. V_snwprintf( wzNumUnlocked, ARRAYSIZE( wzNumUnlocked ), L"%d", numAwarded );
  446. wchar_t wzNumAchievements[8];
  447. V_snwprintf( wzNumAchievements, ARRAYSIZE( wzNumAchievements ), L"%d", numTested );
  448. g_pVGuiLocalize->ConstructString( wzGroupTitle, sizeof( wzGroupTitle ), wzGroupName, 0 );
  449. }
  450. KeyValues *pKV = new KeyValues( "grp" );
  451. pKV->SetInt( "minrange", m_AchievementGroups[i].m_iMinRange );
  452. pKV->SetInt( "maxrange", m_AchievementGroups[i].m_iMaxRange );
  453. if ( bCreate )
  454. {
  455. // Create an achievement group instance
  456. CAchievementsPageGroupPanel *achievementGroupPanel = new CAchievementsPageGroupPanel( m_pGroupsList, this, "AchievementDialogGroupPanel", i );
  457. achievementGroupPanel->SetGroupInfo( wzGroupTitle, m_AchievementGroups[i].m_iMinRange, m_AchievementGroups[i].m_iMaxRange );
  458. if (i == 0)
  459. {
  460. achievementGroupPanel->SetGroupActive(true);
  461. }
  462. else
  463. {
  464. achievementGroupPanel->SetGroupActive(false);
  465. }
  466. m_pGroupsList->AddItem( NULL, achievementGroupPanel );
  467. }
  468. }
  469. m_pStatCard->UpdateInfo();
  470. }
  471. //-----------------------------------------------------------------------------
  472. // Purpose: creates child panels, passes down name to pick up any settings from res files.
  473. //-----------------------------------------------------------------------------
  474. CAchievementsPageItemPanel::CAchievementsPageItemPanel( vgui::PanelListPanel *parent, const char* name) : BaseClass( parent, name )
  475. {
  476. m_pParent = parent;
  477. m_pSchemeSettings = NULL;
  478. m_pAchievementIcon = SETUP_PANEL(new vgui::ImagePanel( this, "AchievementIcon" ));
  479. m_pAchievementNameLabel = new vgui::Label( this, "AchievementName", "name" );
  480. m_pAchievementDescLabel = new vgui::Label( this, "AchievementDesc", "desc" );
  481. m_pPercentageBar = SETUP_PANEL( new ImagePanel( this, "PercentageBar" ) );
  482. m_pPercentageText = new vgui::Label( this, "PercentageText", "" );
  483. m_pAwardDate = new vgui::Label( this, "AwardDate", "date" );
  484. m_pShowOnHUDButton = new vgui::CheckButton( this, "ShowOnHudToggle", "" );
  485. m_pShowOnHUDButton->SetMouseInputEnabled( true );
  486. m_pShowOnHUDButton->SetEnabled( true );
  487. m_pShowOnHUDButton->SetCheckButtonCheckable( true );
  488. m_pShowOnHUDButton->AddActionSignalTarget( this );
  489. m_pHiddenHUDToggleButton = new CHiddenHUDToggleButton( this, "HiddenHUDToggle", "" );
  490. m_pHiddenHUDToggleButton->SetPaintBorderEnabled( false );
  491. SetMouseInputEnabled( true );
  492. parent->SetMouseInputEnabled( true );
  493. }
  494. CAchievementsPageItemPanel::~CAchievementsPageItemPanel()
  495. {
  496. delete m_pAchievementIcon;
  497. delete m_pAchievementNameLabel;
  498. delete m_pAchievementDescLabel;
  499. delete m_pPercentageBar;
  500. delete m_pPercentageText;
  501. delete m_pAwardDate;
  502. delete m_pShowOnHUDButton;
  503. delete m_pHiddenHUDToggleButton;
  504. }
  505. void CAchievementsPageItemPanel::ToggleShowOnHUDButton()
  506. {
  507. if (m_pShowOnHUDButton)
  508. {
  509. m_pShowOnHUDButton->SetSelected( !m_pShowOnHUDButton->IsSelected() );
  510. }
  511. }
  512. //-----------------------------------------------------------------------------
  513. // Purpose: Updates displayed achievement data. In applyschemesettings, and when gameui activates.
  514. //-----------------------------------------------------------------------------
  515. void CAchievementsPageItemPanel::UpdateAchievementInfo( vgui::IScheme* pScheme )
  516. {
  517. if ( m_pSourceAchievement && m_pSchemeSettings )
  518. {
  519. //=============================================================================
  520. // HPE_BEGIN:
  521. // [dwenger] Get achievement name and description text from the localized file
  522. //=============================================================================
  523. // Set name, description and unlocked state text
  524. m_pAchievementNameLabel->SetText( ACHIEVEMENT_LOCALIZED_NAME( m_pSourceAchievement ) );
  525. m_pAchievementDescLabel->SetText( ACHIEVEMENT_LOCALIZED_DESC( m_pSourceAchievement ) );
  526. //=============================================================================
  527. // HPE_END
  528. //=============================================================================
  529. // Setup icon
  530. // get the vtfFilename from the path.
  531. // Display percentage completion for progressive achievements
  532. // Set up total completion percentage bar. Goal > 1 means its a progress achievement.
  533. CSUpdateProgressBarForPage( this, m_pSourceAchievement, m_clrProgressBar );
  534. if ( m_pSourceAchievement->IsAchieved() )
  535. {
  536. CSLoadAchievementIconForPage( m_pAchievementIcon, m_pSourceAchievement );
  537. SetBgColor( pScheme->GetColor( "AchievementsLightGrey", Color(255, 0, 0, 255) ) );
  538. m_pAchievementNameLabel->SetFgColor( pScheme->GetColor( "SteamLightGreen", Color(255, 255, 255, 255) ) );
  539. Color fgColor = pScheme->GetColor( "Label.TextBrightColor", Color(255, 255, 255, 255) );
  540. m_pAchievementDescLabel->SetFgColor( fgColor );
  541. m_pPercentageText->SetFgColor( fgColor );
  542. m_pShowOnHUDButton->SetVisible( false );
  543. m_pShowOnHUDButton->SetSelected( false );
  544. m_pHiddenHUDToggleButton->SetVisible( false );
  545. m_pAwardDate->SetVisible( true );
  546. m_pAwardDate->SetFgColor( pScheme->GetColor( "SteamLightGreen", Color(255, 255, 255, 255) ) );
  547. // Assign the award date text
  548. int year, month, day, hour, minute, second;
  549. if ( m_pSourceAchievement->GetAwardTime(year, month, day, hour, minute, second) )
  550. {
  551. char dateBuffer[32] = "";
  552. Q_snprintf( dateBuffer, 32, "%4d-%02d-%02d", year, month, day );
  553. m_pAwardDate->SetText( dateBuffer );
  554. }
  555. else
  556. m_pAwardDate->SetText( "" );
  557. }
  558. else
  559. {
  560. CSLoadAchievementIconForPage( m_pAchievementIcon, m_pSourceAchievement, "_bw" );
  561. SetBgColor( pScheme->GetColor( "AchievementsDarkGrey", Color(255, 0, 0, 255) ) );
  562. Color fgColor = pScheme->GetColor( "AchievementsInactiveFG", Color(255, 255, 255, 255) );
  563. m_pAchievementNameLabel->SetFgColor( fgColor );
  564. m_pAchievementDescLabel->SetFgColor( fgColor );
  565. m_pPercentageText->SetFgColor( fgColor );
  566. if ( CSGameSupportsAchievementTrackerForPage() )
  567. {
  568. m_pShowOnHUDButton->SetVisible( !m_pSourceAchievement->ShouldHideUntilAchieved() );
  569. m_pShowOnHUDButton->SetSelected( m_pSourceAchievement->ShouldShowOnHUD() );
  570. m_pHiddenHUDToggleButton->SetVisible( !m_pSourceAchievement->ShouldHideUntilAchieved() );
  571. }
  572. else
  573. {
  574. m_pShowOnHUDButton->SetVisible( false );
  575. m_pHiddenHUDToggleButton->SetVisible( false );
  576. }
  577. }
  578. }
  579. }
  580. //-----------------------------------------------------------------------------
  581. // Purpose: Makes a local copy of a pointer to the achievement entity stored on the client.
  582. //-----------------------------------------------------------------------------
  583. void CAchievementsPageItemPanel::SetAchievementInfo( CCSBaseAchievement* pAchievement )
  584. {
  585. if ( !pAchievement )
  586. {
  587. Assert( 0 );
  588. return;
  589. }
  590. m_pSourceAchievement = pAchievement;
  591. m_iSourceAchievementIndex = pAchievement->GetAchievementID();
  592. }
  593. //-----------------------------------------------------------------------------
  594. // Purpose:
  595. //-----------------------------------------------------------------------------
  596. void CAchievementsPageItemPanel::PreloadResourceFile( void )
  597. {
  598. const char *controlResourceName = "resource/ui/AchievementItem.res";
  599. g_pPreloadedCSAchievementPageItemLayout = new KeyValues(controlResourceName);
  600. g_pPreloadedCSAchievementPageItemLayout->LoadFromFile(g_pFullFileSystem, controlResourceName);
  601. /*
  602. // precache all achievement icons
  603. int iCount = g_AchievementMgrCS.GetAchievementCount();
  604. for ( int i = 0; i < iCount; ++i )
  605. {
  606. CCSBaseAchievement* pAchievement = dynamic_cast<CCSBaseAchievement*>(g_AchievementMgrCS.GetAchievementByIndex( i ));
  607. char imagePath[_MAX_PATH];
  608. Q_strncpy( imagePath, "achievements\\", sizeof(imagePath) );
  609. Q_strncat( imagePath, pAchievement->GetName(), sizeof(imagePath), COPY_ALL_CHARACTERS );
  610. Q_strncat( imagePath, "_bw", sizeof(imagePath), COPY_ALL_CHARACTERS );
  611. Q_strncat( imagePath, ".vtf", sizeof(imagePath), COPY_ALL_CHARACTERS );
  612. scheme()->GetImage(imagePath, true);
  613. Q_strncpy( imagePath, "achievements\\", sizeof(imagePath) );
  614. Q_strncat( imagePath, pAchievement->GetName(), sizeof(imagePath), COPY_ALL_CHARACTERS );
  615. Q_strncat( imagePath, ".vtf", sizeof(imagePath), COPY_ALL_CHARACTERS );
  616. scheme()->GetImage(imagePath, true);
  617. }
  618. */
  619. }
  620. //-----------------------------------------------------------------------------
  621. // Purpose: Loads settings from hl2/resource/ui/achievementitem.res
  622. // Sets display info for this achievement item.
  623. //-----------------------------------------------------------------------------
  624. void CAchievementsPageItemPanel::ApplySchemeSettings( vgui::IScheme* pScheme )
  625. {
  626. if ( !g_pPreloadedCSAchievementPageItemLayout )
  627. {
  628. PreloadResourceFile();
  629. }
  630. LoadControlSettings( "", NULL, g_pPreloadedCSAchievementPageItemLayout );
  631. m_pSchemeSettings = pScheme;
  632. if ( !m_pSourceAchievement )
  633. {
  634. return;
  635. }
  636. BaseClass::ApplySchemeSettings( pScheme );
  637. // m_pSchemeSettings must be set for this.
  638. UpdateAchievementInfo( pScheme );
  639. }
  640. void CAchievementsPageItemPanel::OnCheckButtonChecked(Panel *panel)
  641. {
  642. if ( CSGameSupportsAchievementTrackerForPage() && panel == m_pShowOnHUDButton && m_pSourceAchievement )
  643. {
  644. m_pSourceAchievement->SetShowOnHUD( m_pShowOnHUDButton->IsSelected() );
  645. }
  646. }
  647. //-----------------------------------------------------------------------------
  648. // Purpose: creates child panels, passes down name to pick up any settings from res files.
  649. //-----------------------------------------------------------------------------
  650. CAchievementsPageGroupPanel::CAchievementsPageGroupPanel( vgui::PanelListPanel *parent, CAchievementsPage *owner, const char* name, int iListItemID ) : BaseClass( parent, name )
  651. {
  652. m_pParent = parent;
  653. m_pOwner = owner;
  654. m_pSchemeSettings = NULL;
  655. m_pGroupIcon = SETUP_PANEL(new vgui::ImagePanel( this, "GroupIcon" ));
  656. m_pAchievementGroupLabel = new vgui::Label( this, "GroupName", "name" );
  657. m_pPercentageText = new vgui::Label( this, "GroupPercentageText", "1/1" );
  658. m_pPercentageBar = SETUP_PANEL( new ImagePanel( this, "GroupPercentageBar" ) );
  659. m_pGroupButton = new CGroupButton( this, "GroupButton", "" );
  660. m_pGroupButton->SetPos( 0, 0 );
  661. m_pGroupButton->SetZPos( 20 );
  662. m_pGroupButton->SetWide( 256 );
  663. m_pGroupButton->SetTall( 64 );
  664. SetMouseInputEnabled( true );
  665. parent->SetMouseInputEnabled( true );
  666. m_bActiveButton = false;
  667. }
  668. CAchievementsPageGroupPanel::~CAchievementsPageGroupPanel()
  669. {
  670. delete m_pAchievementGroupLabel;
  671. delete m_pPercentageBar;
  672. delete m_pPercentageText;
  673. delete m_pGroupIcon;
  674. }
  675. //-----------------------------------------------------------------------------
  676. // Purpose: Loads settings from hl2/resource/ui/achievementitem.res
  677. // Sets display info for this achievement item.
  678. //-----------------------------------------------------------------------------
  679. void CAchievementsPageGroupPanel::ApplySchemeSettings( vgui::IScheme* pScheme )
  680. {
  681. if ( !g_pPreloadedCSAchievementPageGroupLayout )
  682. {
  683. PreloadResourceFile();
  684. }
  685. LoadControlSettings( "", NULL, g_pPreloadedCSAchievementPageGroupLayout );
  686. m_pSchemeSettings = pScheme;
  687. BaseClass::ApplySchemeSettings( pScheme );
  688. // m_pSchemeSettings must be set for this.
  689. UpdateAchievementInfo( pScheme );
  690. }
  691. //-----------------------------------------------------------------------------
  692. // Purpose: Updates displayed achievement data. In ApplySchemeSettings(), and
  693. // when gameui activates.
  694. //-----------------------------------------------------------------------------
  695. void CAchievementsPageGroupPanel::UpdateAchievementInfo( vgui::IScheme* pScheme )
  696. {
  697. if ( m_pSchemeSettings )
  698. {
  699. int numAwarded = 0;
  700. int numTested = 0;
  701. char buf[128];
  702. int achievementRangeStart = (m_iFirstAchievementID / 1000) * 1000;
  703. Q_snprintf( buf, sizeof(buf), "#Achievement_Group_%d", achievementRangeStart );
  704. wchar_t *wzGroupName = g_pVGuiLocalize->Find( buf );
  705. if ( !wzGroupName )
  706. {
  707. wzGroupName = L"Need Title ( %s1 of %s2 )";
  708. }
  709. wchar_t wzGroupTitle[128];
  710. if ( wzGroupName )
  711. {
  712. // Determine number of achievements in the group which have been awarded
  713. for (int i = m_iFirstAchievementID; i < m_iLastAchievementID; i++)
  714. {
  715. IAchievement* pCur = g_AchievementMgrCS.GetAchievementByID( i );
  716. if ( !pCur )
  717. continue;
  718. numTested++;
  719. if ( pCur->IsAchieved() )
  720. {
  721. numAwarded++;
  722. }
  723. }
  724. wchar_t wzNumUnlocked[8];
  725. V_snwprintf( wzNumUnlocked, ARRAYSIZE( wzNumUnlocked ), L"%d", numAwarded );
  726. wchar_t wzNumAchievements[8];
  727. V_snwprintf( wzNumAchievements,ARRAYSIZE( wzNumAchievements ), L"%d", numTested );
  728. g_pVGuiLocalize->ConstructString( wzGroupTitle, sizeof( wzGroupTitle ), wzGroupName, 2, wzNumUnlocked, wzNumAchievements );
  729. }
  730. // Set group name text
  731. m_pAchievementGroupLabel->SetText( wzGroupTitle );//m_pGroupName );
  732. m_pAchievementGroupLabel->SetFgColor(Color(157, 194, 80, 255));
  733. char* buff[32];
  734. Q_snprintf( (char*)buff, 32, "%d / %d", numAwarded, numTested );
  735. m_pPercentageText->SetText( (const char*)buff );
  736. m_pPercentageText->SetFgColor(Color(157, 194, 80, 255));
  737. if ( !m_bActiveButton )
  738. {
  739. CSLoadIconForPage( m_pGroupIcon, "achievement-btn-up" );
  740. }
  741. else
  742. {
  743. CSLoadIconForPage( m_pGroupIcon, "achievement-btn-select" );
  744. }
  745. // Update the percentage complete bar
  746. vgui::ImagePanel *pPercentageBar = (vgui::ImagePanel*)FindChildByName( "GroupPercentageBar" );
  747. vgui::ImagePanel *pPercentageBarBkg = (vgui::ImagePanel*)FindChildByName( "GroupPercentageBarBackground" );
  748. if ( pPercentageBar && pPercentageBarBkg )
  749. {
  750. float flCompletion = (float)numAwarded / (float)numTested;
  751. pPercentageBar->SetFillColor( Color(157, 194, 80, 255) );
  752. pPercentageBar->SetWide( pPercentageBarBkg->GetWide() * flCompletion );
  753. SetControlVisible( "GroupPercentageBarBackground", true );
  754. SetControlVisible( "GroupPercentageBar", true );
  755. }
  756. }
  757. }
  758. //-----------------------------------------------------------------------------
  759. // Purpose:
  760. //-----------------------------------------------------------------------------
  761. void CAchievementsPageGroupPanel::PreloadResourceFile( void )
  762. {
  763. const char *controlResourceName = "resource/ui/AchievementGroup.res";
  764. g_pPreloadedCSAchievementPageGroupLayout = new KeyValues(controlResourceName);
  765. g_pPreloadedCSAchievementPageGroupLayout->LoadFromFile(g_pFullFileSystem, controlResourceName);
  766. }
  767. //-----------------------------------------------------------------------------
  768. // Purpose: Assigns a name and achievement id bounds for an achievement group.
  769. //-----------------------------------------------------------------------------
  770. void CAchievementsPageGroupPanel::SetGroupInfo( const wchar_t* name, int firstAchievementID, int lastAchievementID )
  771. {
  772. // Store away the group name
  773. short _textLen = (short)wcslen(name) + 1;
  774. m_pGroupName = new wchar_t[_textLen];
  775. Q_memcpy( m_pGroupName, name, _textLen * sizeof(wchar_t) );
  776. // Store off the start & end achievement IDs
  777. m_iFirstAchievementID = firstAchievementID;
  778. m_iLastAchievementID = lastAchievementID;
  779. }
  780. CGroupButton::CGroupButton( vgui::Panel *pParent, const char *pName, const char *pText ) :
  781. BaseClass( pParent, pName, pText )
  782. {
  783. }
  784. //-----------------------------------------------------------------------------
  785. // Purpose: Handle the case where the user presses an achievement group button.
  786. //-----------------------------------------------------------------------------
  787. void CGroupButton::DoClick( void )
  788. {
  789. // Process when a group button is hit
  790. CAchievementsPageGroupPanel* pParent = static_cast<CAchievementsPageGroupPanel*>(GetParent());
  791. if (pParent)
  792. {
  793. CAchievementsPage* pAchievementsPage = static_cast<CAchievementsPage*>(pParent->GetOwner());
  794. if (pAchievementsPage)
  795. {
  796. // Update the list of group achievements
  797. pAchievementsPage->UpdateAchievementList( pParent );
  798. }
  799. }
  800. }
  801. void CAchievementsPage::OnPageShow()
  802. {
  803. m_pGroupsList->GetScrollbar()->SetWide(0);
  804. }
  805. void CAchievementsPage::FireGameEvent( IGameEvent *event )
  806. {
  807. const char *type = event->GetName();
  808. if ( 0 == Q_strcmp( type, "achievement_earned_local" ) )
  809. m_bAchievementsDirty = true;
  810. if ( 0 == Q_strcmp( type, "player_stats_updated" ) )
  811. m_bStatsDirty = true;
  812. }
  813. void CAchievementsPage::OnThink()
  814. {
  815. vgui::IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
  816. if ( m_bAchievementsDirty )
  817. {
  818. UpdateAchievementDialogInfo();
  819. }
  820. else if ( m_bStatsDirty )
  821. {
  822. // Update progress for currently displayed achievements
  823. int itemId = m_pAchievementsList->FirstItem();
  824. while (itemId != m_pAchievementsList->InvalidItemID() )
  825. {
  826. CAchievementsPageItemPanel *pAchievementItem = dynamic_cast<CAchievementsPageItemPanel*>(m_pAchievementsList->GetItemPanel(itemId));
  827. pAchievementItem->UpdateAchievementInfo(pScheme);
  828. itemId = m_pAchievementsList->NextItem(itemId);
  829. }
  830. m_bStatsDirty = false;
  831. }
  832. }
  833. CHiddenHUDToggleButton::CHiddenHUDToggleButton( vgui::Panel *pParent, const char *pName, const char *pText ) :
  834. BaseClass( pParent, pName, pText )
  835. {
  836. }
  837. //-----------------------------------------------------------------------------
  838. // Purpose: Handle the case where the user shift-clicks on an un-awarded achievement.
  839. //-----------------------------------------------------------------------------
  840. void CHiddenHUDToggleButton::DoClick( void )
  841. {
  842. if ( input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT) )
  843. {
  844. // Process when a group button is hit
  845. CAchievementsPageItemPanel* pParent = static_cast<CAchievementsPageItemPanel*>(GetParent());
  846. if (pParent)
  847. {
  848. pParent->ToggleShowOnHUDButton();
  849. }
  850. }
  851. }