diff options
Diffstat (limited to 'game/client/cstrike/VGUI/achievements_page.cpp')
| -rw-r--r-- | game/client/cstrike/VGUI/achievements_page.cpp | 1061 |
1 files changed, 1061 insertions, 0 deletions
diff --git a/game/client/cstrike/VGUI/achievements_page.cpp b/game/client/cstrike/VGUI/achievements_page.cpp new file mode 100644 index 0000000..bc6036e --- /dev/null +++ b/game/client/cstrike/VGUI/achievements_page.cpp @@ -0,0 +1,1061 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Display a list of achievements for the current game +// +//=============================================================================// + +#include "cbase.h" +#include "achievements_page.h" +#include "vgui_controls/Button.h" +#include "vgui/ILocalize.h" +#include "ixboxsystem.h" +#include "iachievementmgr.h" +#include "filesystem.h" +#include "vgui_controls/ImagePanel.h" +#include "vgui_controls/ComboBox.h" +#include "vgui_controls/CheckButton.h" +#include "fmtstr.h" +#include "c_cs_playerresource.h" +#include "stat_card.h" +#include <vgui/IInput.h> + +#include "../../../public/steam/steam_api.h" +#include "achievementmgr.h" +#include "../../../../public/vgui/IScheme.h" +#include "../vgui_controls/ScrollBar.h" +#include "achievements_cs.h" + +extern CAchievementMgr g_AchievementMgrCS; + +using namespace vgui; + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +KeyValues *g_pPreloadedCSAchievementPageItemLayout = NULL; +KeyValues *g_pPreloadedCSAchievementPageGroupLayout = NULL; + +// Shared helper functions so xbox and pc can share as much code as possible while coming from different bases. + +//----------------------------------------------------------------------------- +// Purpose: Sets the parameter pIconPanel to display the specified achievement's icon file. +//----------------------------------------------------------------------------- +bool CSLoadAchievementIconForPage( vgui::ImagePanel* pIconPanel, CCSBaseAchievement* pAchievement, const char *pszExt /*= NULL*/ ) +{ + char imagePath[_MAX_PATH]; + Q_strncpy( imagePath, "achievements\\", sizeof(imagePath) ); + Q_strncat( imagePath, pAchievement->GetName(), sizeof(imagePath), COPY_ALL_CHARACTERS ); + if ( pszExt ) + { + Q_strncat( imagePath, pszExt, sizeof(imagePath), COPY_ALL_CHARACTERS ); + } + Q_strncat( imagePath, ".vtf", sizeof(imagePath), COPY_ALL_CHARACTERS ); + + char checkFile[_MAX_PATH]; + Q_snprintf( checkFile, sizeof(checkFile), "materials\\vgui\\%s", imagePath ); + if ( !g_pFullFileSystem->FileExists( checkFile ) ) + { + Q_snprintf( imagePath, sizeof(imagePath), "hud\\icon_locked.vtf" ); + } + + pIconPanel->SetShouldScaleImage( true ); + pIconPanel->SetImage( imagePath ); + pIconPanel->SetVisible( true ); + + return pIconPanel->IsVisible(); +} + +//----------------------------------------------------------------------------- +// Purpose: Sets the parameter pIconPanel to display the specified achievement's icon file. +//----------------------------------------------------------------------------- +bool CSLoadIconForPage( vgui::ImagePanel* pIconPanel, const char* pFilename, const char *pszExt /*= NULL*/ ) +{ + char imagePath[_MAX_PATH]; + Q_strncpy( imagePath, "achievements\\", sizeof(imagePath) ); + Q_strncat( imagePath, pFilename, sizeof(imagePath), COPY_ALL_CHARACTERS ); + if ( pszExt ) + { + Q_strncat( imagePath, pszExt, sizeof(imagePath), COPY_ALL_CHARACTERS ); + } + Q_strncat( imagePath, ".vtf", sizeof(imagePath), COPY_ALL_CHARACTERS ); + + char checkFile[_MAX_PATH]; + Q_snprintf( checkFile, sizeof(checkFile), "materials\\vgui\\%s", imagePath ); + if ( !g_pFullFileSystem->FileExists( checkFile ) ) + { + Q_snprintf( imagePath, sizeof(imagePath), "hud\\icon_locked.vtf" ); + } + + pIconPanel->SetShouldScaleImage( true ); + pIconPanel->SetImage( imagePath ); + pIconPanel->SetVisible( true ); + + return pIconPanel->IsVisible(); +} + +//----------------------------------------------------------------------------- +// The bias is to ensure the percentage bar gets plenty orange before it reaches the text, +// as the white-on-grey is hard to read. +//----------------------------------------------------------------------------- +Color CSLerpColorsForPage ( Color cStart, Color cEnd, float flPercent ) +{ + float r = (float)((float)(cStart.r()) + (float)(cEnd.r() - cStart.r()) * Bias( flPercent, 0.75 ) ); + float g = (float)((float)(cStart.g()) + (float)(cEnd.g() - cStart.g()) * Bias( flPercent, 0.75 ) ); + float b = (float)((float)(cStart.b()) + (float)(cEnd.b() - cStart.b()) * Bias( flPercent, 0.75 ) ); + float a = (float)((float)(cStart.a()) + (float)(cEnd.a() - cStart.a()) * Bias( flPercent, 0.75 ) ); + return Color( r, g, b, a ); +} + +//----------------------------------------------------------------------------- +// Purpose: Shares common percentage bar calculations/color settings between xbox and pc. +// Not really intended for robustness or reuse across many panels. +// Input : pFrame - assumed to have certain child panels (see below) +// *pAchievement - source achievement to poll for progress. Non progress achievements will not show a percentage bar. +//----------------------------------------------------------------------------- +void CSUpdateProgressBarForPage( vgui::EditablePanel* pPanel, CCSBaseAchievement* pAchievement, Color clrProgressBar ) +{ + ///* + if ( pAchievement->GetGoal() > 1 ) + { + bool bShowProgress = true; + + // 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 + // for this achievement, don't show progress + if ( ( pAchievement->GetFlags() & ACH_SAVE_WITH_GAME ) && /*!GameUI().IsInLevel() &&*/ !pAchievement->IsAchieved() ) + { + bShowProgress = false; + } + + float flCompletion = 0.0f; + + // Once achieved, we can't rely on count. If they've completed the achievement just set to 100%. + int iCount = pAchievement->GetCount(); + if ( pAchievement->IsAchieved() ) + { + flCompletion = 1.0f; + iCount = pAchievement->GetGoal(); + } + else if ( bShowProgress ) + { + flCompletion = ( ((float)pAchievement->GetCount()) / ((float)pAchievement->GetGoal()) ); + // In rare cases count can exceed goal and not be achieved (switch local storage on X360, take saved game from different user on PC). + // These will self-correct with continued play, but if we're in that state don't show more than 100% achieved. + flCompletion = MIN( flCompletion, 1.0 ); + } + + char szPercentageText[ 256 ] = ""; + if ( bShowProgress ) + { + Q_snprintf( szPercentageText, 256, "%d/%d", iCount, pAchievement->GetGoal() ); + } + + pPanel->SetControlString( "PercentageText", szPercentageText ); + pPanel->SetControlVisible( "PercentageText", true ); + pPanel->SetControlVisible( "CompletionText", true ); + + vgui::ImagePanel *pPercentageBar = (vgui::ImagePanel*)pPanel->FindChildByName( "PercentageBar" ); + vgui::ImagePanel *pPercentageBarBkg = (vgui::ImagePanel*)pPanel->FindChildByName( "PercentageBarBackground" ); + + if ( pPercentageBar && pPercentageBarBkg ) + { + pPercentageBar->SetFillColor( clrProgressBar ); + pPercentageBar->SetWide( pPercentageBarBkg->GetWide() * flCompletion ); + + pPanel->SetControlVisible( "PercentageBarBackground", IsX360() ? bShowProgress : true ); + pPanel->SetControlVisible( "PercentageBar", true ); + } + } + //*/ +} + +// TODO: revisit this once other games are rebuilt using the updated IAchievement interface +bool CSGameSupportsAchievementTrackerForPage() +{ + const char *pGame = Q_UnqualifiedFileName( engine->GetGameDirectory() ); + return ( !Q_stricmp( pGame, "cstrike" ) ); +} + +////////////////////////////////////////////////////////////////////////// +// PC Implementation +////////////////////////////////////////////////////////////////////////// + + + +int AchivementSortPredicate( CCSBaseAchievement* const* pLeft, CCSBaseAchievement* const* pRight ) +{ + if ( (*pLeft)->IsAchieved() && !(*pRight)->IsAchieved() ) + return -1; + + if ( !(*pLeft)->IsAchieved() && (*pRight)->IsAchieved() ) + return 1; + + if ( (*pLeft)->GetAchievementID() < (*pRight)->GetAchievementID() ) + return -1; + + if ( (*pLeft)->GetAchievementID() > (*pRight)->GetAchievementID() ) + return 1; + + return 0; +} + + +//----------------------------------------------------------------------------- +// Purpose: creates child panels, passes down name to pick up any settings from res files. +//----------------------------------------------------------------------------- +CAchievementsPage::CAchievementsPage(vgui::Panel *parent, const char *name) : BaseClass(parent, "CSAchievementsDialog") +{ + m_iFixedWidth = 900; // Give this an initial value in order to set a proper size + SetBounds(0, 0, 900, 780); + SetMinimumSize( 256, 780 ); + + m_pStatCard = new StatCard(this, "ignored"); + + m_pAchievementsList = new vgui::PanelListPanel( this, "listpanel_achievements" ); + m_pAchievementsList->SetFirstColumnWidth( 0 ); + + m_pGroupsList = new vgui::PanelListPanel( this, "listpanel_groups" ); + m_pGroupsList->SetFirstColumnWidth( 0 ); + + m_pListBG = new vgui::ImagePanel( this, "listpanel_background" ); + + m_pPercentageBarBackground = SETUP_PANEL( new ImagePanel( this, "PercentageBarBackground" ) ); + m_pPercentageBar = SETUP_PANEL( new ImagePanel( this, "PercentageBar" ) ); + + ListenForGameEvent( "player_stats_updated" ); + ListenForGameEvent( "achievement_earned_local" ); + + // int that holds the highest number achievement id we've found + int iHighestAchievementIDSeen = -1; + int iNextGroupBoundary = 1000; + + Q_memset( m_AchievementGroups, 0, sizeof(m_AchievementGroups) ); + m_iNumAchievementGroups = 0; + + // Base groups + int iCount = g_AchievementMgrCS.GetAchievementCount(); + for ( int i = 0; i < iCount; ++i ) + { + CCSBaseAchievement* pAchievement = dynamic_cast<CCSBaseAchievement*>(g_AchievementMgrCS.GetAchievementByIndex( i )); + + if ( !pAchievement ) + continue; + + int iAchievementID = pAchievement->GetAchievementID(); + + if ( iAchievementID > iHighestAchievementIDSeen ) + { + // if it's crossed the next group boundary, create a new group + if ( iAchievementID >= iNextGroupBoundary ) + { + int iNewGroupBoundary = iAchievementID; + CreateNewAchievementGroup( iNewGroupBoundary, iNewGroupBoundary+99 ); + + iNextGroupBoundary = iNewGroupBoundary + 100; + } + + iHighestAchievementIDSeen = iAchievementID; + } + } + + LoadControlSettings("resource/ui/CSAchievementsDialog.res"); + UpdateTotalProgressDisplay(); + CreateOrUpdateComboItems( true ); + + // Default display shows the first achievement group + UpdateAchievementList(1001, 1100); + + m_bStatsDirty = true; + m_bAchievementsDirty = true; +} + +CAchievementsPage::~CAchievementsPage() +{ + g_AchievementMgrCS.SaveGlobalStateIfDirty( false ); // check for saving here to store achievements we want pinned to HUD + + m_pAchievementsList->DeleteAllItems(); + delete m_pAchievementsList; + delete m_pPercentageBarBackground; + delete m_pPercentageBar; +} + +void CAchievementsPage::CreateNewAchievementGroup( int iMinRange, int iMaxRange ) +{ + m_AchievementGroups[m_iNumAchievementGroups].m_iMinRange = iMinRange; + m_AchievementGroups[m_iNumAchievementGroups].m_iMaxRange = iMaxRange; + m_iNumAchievementGroups++; +} + +//---------------------------------------------------------- +// Get the width we're going to lock at +//---------------------------------------------------------- +void CAchievementsPage::ApplySettings( KeyValues *pResourceData ) +{ + m_iFixedWidth = pResourceData->GetInt( "wide", 512 ); + + BaseClass::ApplySettings( pResourceData ); +} + +//---------------------------------------------------------- +// Preserve our width to the one in the .res file +//---------------------------------------------------------- +void CAchievementsPage::OnSizeChanged(int newWide, int newTall) +{ + // Lock the width, but allow height scaling + if ( newWide != m_iFixedWidth ) + { + SetSize( m_iFixedWidth, newTall ); + return; + } + + BaseClass::OnSizeChanged(newWide, newTall); +} + +//---------------------------------------------------------- +// Re-populate the achievement list with the selected group +//---------------------------------------------------------- +void CAchievementsPage::UpdateAchievementList(CAchievementsPageGroupPanel* groupPanel) +{ + if (!groupPanel) + return; + + UpdateAchievementList( groupPanel->GetFirstAchievementID(), groupPanel->GetLastAchievementID() ); + + vgui::IScheme *pGroupScheme = scheme()->GetIScheme( GetScheme() ); + + // Update active status for button display + for (int i = 0; i < m_pGroupsList->GetItemCount(); i++) + { + CAchievementsPageGroupPanel *pPanel = (CAchievementsPageGroupPanel*)m_pGroupsList->GetItemPanel(i); + if ( pPanel ) + { + if ( pPanel != groupPanel ) + { + pPanel->SetGroupActive( false ); + } + else + { + pPanel->SetGroupActive( true ); + } + + pPanel->UpdateAchievementInfo( pGroupScheme ); + } + } +} + +void CAchievementsPage::UpdateTotalProgressDisplay() +{ + // Set up total completion percentage bar + float flCompletion = 0.0f; + + int iCount = g_AchievementMgrCS.GetAchievementCount(); + int nUnlocked = 0; + + if ( iCount > 0 ) + { + for ( int i = 0; i < iCount; ++i ) + { + CCSBaseAchievement* pAchievement = dynamic_cast<CCSBaseAchievement*>(g_AchievementMgrCS.GetAchievementByIndex( i )); + + if ( pAchievement && pAchievement->IsAchieved() ) + ++nUnlocked; + } + + flCompletion = (((float)nUnlocked) / ((float)g_AchievementMgrCS.GetAchievementCount())); + } + + char szPercentageText[64]; + V_sprintf_safe( szPercentageText, "%d / %d", + nUnlocked, g_AchievementMgrCS.GetAchievementCount() ); + + SetControlString( "PercentageText", szPercentageText ); + SetControlVisible( "PercentageText", true ); + SetControlVisible( "CompletionText", true ); + + vgui::IScheme *pScheme = scheme()->GetIScheme( GetScheme() ); + + Color clrHighlight = pScheme->GetColor( "NewGame.SelectionColor", Color(255, 255, 255, 255) ); + Color clrWhite(255, 255, 255, 255); + + Color cProgressBar = Color( static_cast<float>( clrHighlight.r() ) * ( 1.0f - flCompletion ) + static_cast<float>( clrWhite.r() ) * flCompletion, + static_cast<float>( clrHighlight.g() ) * ( 1.0f - flCompletion ) + static_cast<float>( clrWhite.g() ) * flCompletion, + static_cast<float>( clrHighlight.b() ) * ( 1.0f - flCompletion ) + static_cast<float>( clrWhite.b() ) * flCompletion, + static_cast<float>( clrHighlight.a() ) * ( 1.0f - flCompletion ) + static_cast<float>( clrWhite.a() ) * flCompletion ); + + m_pPercentageBar->SetFgColor( cProgressBar ); + m_pPercentageBar->SetWide( m_pPercentageBarBackground->GetWide() * flCompletion ); + + SetControlVisible( "PercentageBarBackground", true ); + SetControlVisible( "PercentageBar", true ); +} + +//---------------------------------------------------------- +// Re-populate the achievement list with the selected group +//---------------------------------------------------------- +void CAchievementsPage::UpdateAchievementList(int minID, int maxID) +{ + int iMinRange = minID; + int iMaxRange = maxID; + + int iCount = g_AchievementMgrCS.GetAchievementCount(); + + CUtlVector<CCSBaseAchievement*> sortedAchivementList; + sortedAchivementList.EnsureCapacity(iCount); + + for ( int i = 0; i < iCount; ++i ) + { + CCSBaseAchievement* pAchievement = dynamic_cast<CCSBaseAchievement*>(g_AchievementMgrCS.GetAchievementByIndex(i)); + + if ( !pAchievement ) + continue; + + int iAchievementID = pAchievement->GetAchievementID(); + + if ( iAchievementID < iMinRange || iAchievementID > iMaxRange ) + continue; + + // don't show hidden achievements if not achieved + if ( pAchievement->ShouldHideUntilAchieved() && !pAchievement->IsAchieved() ) + continue; + + sortedAchivementList.AddToTail(pAchievement); + } + + sortedAchivementList.Sort(AchivementSortPredicate); + + m_pAchievementsList->DeleteAllItems(); + + FOR_EACH_VEC(sortedAchivementList, i) + { + CCSBaseAchievement* pAchievement = sortedAchivementList[i]; + + CAchievementsPageItemPanel *pAchievementItemPanel = new CAchievementsPageItemPanel( m_pAchievementsList, "AchievementDialogItemPanel"); + pAchievementItemPanel->SetAchievementInfo(pAchievement); + + // force all our new panel to have the correct internal layout and size so that our parent container can layout properly + pAchievementItemPanel->InvalidateLayout(true, true); + + m_pAchievementsList->AddItem( NULL, pAchievementItemPanel ); + } + + m_pAchievementsList->MoveScrollBarToTop(); +} + +//----------------------------------------------------------------------------- +// Purpose: Loads settings from achievementsdialog.res in hl2/resource/ui/ +// Sets up progress bar displaying total achievement unlocking progress by the user. +//----------------------------------------------------------------------------- +void CAchievementsPage::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + m_pGroupsList->SetBgColor(Color(86,86,86,255)); + + SetBgColor(Color(86,86,86,255)); + + // Set text color for percentage + Panel *pPanel; + pPanel = FindChildByName("PercentageText"); + if (pPanel) + { + pPanel->SetFgColor(Color(157, 194, 80, 255)); + } + + // Set text color for achievement earned label + pPanel = FindChildByName("AchievementsEarnedLabel"); + if (pPanel) + { + pPanel->SetFgColor(Color(157, 194, 80, 255)); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Each sub-panel gets its data updated +//----------------------------------------------------------------------------- +void CAchievementsPage::UpdateAchievementDialogInfo( void ) +{ + // Hide the group list scrollbar + if (m_pGroupsList->GetScrollbar()) + { + m_pGroupsList->GetScrollbar()->SetWide(0); + } + + int iCount = m_pAchievementsList->GetItemCount(); + vgui::IScheme *pScheme = scheme()->GetIScheme( GetScheme() ); + + int i; + for ( i = 0; i < iCount; i++ ) + { + CAchievementsPageItemPanel *pPanel = (CAchievementsPageItemPanel*)m_pAchievementsList->GetItemPanel(i); + if ( pPanel ) + { + pPanel->UpdateAchievementInfo( pScheme ); + } + } + + // Update all group panels + int iGroupCount = m_pGroupsList->GetItemCount(); + for ( i = 0; i < iGroupCount; i++ ) + { + CAchievementsPageGroupPanel *pPanel = (CAchievementsPageGroupPanel*)m_pGroupsList->GetItemPanel(i); + if ( pPanel ) + { + pPanel->UpdateAchievementInfo( pScheme ); + + if ( pPanel->IsGroupActive() ) + { + UpdateAchievementList( pPanel ); + } + } + } + + // update the groups and overall progress bar + CreateOrUpdateComboItems( false ); // update them with new achieved counts + + UpdateTotalProgressDisplay(); + + m_pStatCard->UpdateInfo(); + + m_bAchievementsDirty = false; + m_bStatsDirty = false; +} + +void CAchievementsPage::CreateOrUpdateComboItems( bool bCreate ) +{ + // Build up achievement group names + for ( int i=0;i<m_iNumAchievementGroups;i++ ) + { + char buf[128]; + + int achievementRangeStart = (m_AchievementGroups[i].m_iMinRange / 1000) * 1000; + Q_snprintf( buf, sizeof(buf), "#Achievement_Group_%d", achievementRangeStart ); + + wchar_t *wzGroupName = g_pVGuiLocalize->Find( buf ); + + if ( !wzGroupName ) + { + wzGroupName = L"Need Title ( %s1 of %s2 )"; + } + + wchar_t wzGroupTitle[128]; + + if ( wzGroupName ) + { + // Determine number of achievements in the group which have been awarded + int numAwarded = 0; + int numTested = 0; + for (int j = m_AchievementGroups[i].m_iMinRange; j < m_AchievementGroups[i].m_iMaxRange; j++) + { + IAchievement* pCur = g_AchievementMgrCS.GetAchievementByID( j ); + + if ( !pCur ) + continue; + + numTested++; + + if ( pCur->IsAchieved() ) + { + numAwarded++; + } + } + + wchar_t wzNumUnlocked[8]; + V_snwprintf( wzNumUnlocked, ARRAYSIZE( wzNumUnlocked ), L"%d", numAwarded ); + + wchar_t wzNumAchievements[8]; + V_snwprintf( wzNumAchievements, ARRAYSIZE( wzNumAchievements ), L"%d", numTested ); + + g_pVGuiLocalize->ConstructString( wzGroupTitle, sizeof( wzGroupTitle ), wzGroupName, 0 ); + } + + KeyValues *pKV = new KeyValues( "grp" ); + pKV->SetInt( "minrange", m_AchievementGroups[i].m_iMinRange ); + pKV->SetInt( "maxrange", m_AchievementGroups[i].m_iMaxRange ); + + if ( bCreate ) + { + // Create an achievement group instance + CAchievementsPageGroupPanel *achievementGroupPanel = new CAchievementsPageGroupPanel( m_pGroupsList, this, "AchievementDialogGroupPanel", i ); + achievementGroupPanel->SetGroupInfo( wzGroupTitle, m_AchievementGroups[i].m_iMinRange, m_AchievementGroups[i].m_iMaxRange ); + + if (i == 0) + { + achievementGroupPanel->SetGroupActive(true); + } + else + { + achievementGroupPanel->SetGroupActive(false); + } + + m_pGroupsList->AddItem( NULL, achievementGroupPanel ); + } + } + + m_pStatCard->UpdateInfo(); +} + +//----------------------------------------------------------------------------- +// Purpose: creates child panels, passes down name to pick up any settings from res files. +//----------------------------------------------------------------------------- +CAchievementsPageItemPanel::CAchievementsPageItemPanel( vgui::PanelListPanel *parent, const char* name) : BaseClass( parent, name ) +{ + m_pParent = parent; + m_pSchemeSettings = NULL; + + m_pAchievementIcon = SETUP_PANEL(new vgui::ImagePanel( this, "AchievementIcon" )); + m_pAchievementNameLabel = new vgui::Label( this, "AchievementName", "name" ); + m_pAchievementDescLabel = new vgui::Label( this, "AchievementDesc", "desc" ); + m_pPercentageBar = SETUP_PANEL( new ImagePanel( this, "PercentageBar" ) ); + m_pPercentageText = new vgui::Label( this, "PercentageText", "" ); + m_pAwardDate = new vgui::Label( this, "AwardDate", "date" ); + m_pShowOnHUDButton = new vgui::CheckButton( this, "ShowOnHudToggle", "" ); + m_pShowOnHUDButton->SetMouseInputEnabled( true ); + m_pShowOnHUDButton->SetEnabled( true ); + m_pShowOnHUDButton->SetCheckButtonCheckable( true ); + m_pShowOnHUDButton->AddActionSignalTarget( this ); + + m_pHiddenHUDToggleButton = new CHiddenHUDToggleButton( this, "HiddenHUDToggle", "" ); + m_pHiddenHUDToggleButton->SetPaintBorderEnabled( false ); + + + SetMouseInputEnabled( true ); + parent->SetMouseInputEnabled( true ); +} + +CAchievementsPageItemPanel::~CAchievementsPageItemPanel() +{ + delete m_pAchievementIcon; + delete m_pAchievementNameLabel; + delete m_pAchievementDescLabel; + delete m_pPercentageBar; + delete m_pPercentageText; + delete m_pAwardDate; + delete m_pShowOnHUDButton; + delete m_pHiddenHUDToggleButton; +} + +void CAchievementsPageItemPanel::ToggleShowOnHUDButton() +{ + if (m_pShowOnHUDButton) + { + m_pShowOnHUDButton->SetSelected( !m_pShowOnHUDButton->IsSelected() ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Updates displayed achievement data. In applyschemesettings, and when gameui activates. +//----------------------------------------------------------------------------- +void CAchievementsPageItemPanel::UpdateAchievementInfo( vgui::IScheme* pScheme ) +{ + if ( m_pSourceAchievement && m_pSchemeSettings ) + { + //============================================================================= + // HPE_BEGIN: + // [dwenger] Get achievement name and description text from the localized file + //============================================================================= + + // Set name, description and unlocked state text + m_pAchievementNameLabel->SetText( ACHIEVEMENT_LOCALIZED_NAME( m_pSourceAchievement ) ); + m_pAchievementDescLabel->SetText( ACHIEVEMENT_LOCALIZED_DESC( m_pSourceAchievement ) ); + + //============================================================================= + // HPE_END + //============================================================================= + + // Setup icon + // get the vtfFilename from the path. + + // Display percentage completion for progressive achievements + // Set up total completion percentage bar. Goal > 1 means its a progress achievement. + CSUpdateProgressBarForPage( this, m_pSourceAchievement, m_clrProgressBar ); + + if ( m_pSourceAchievement->IsAchieved() ) + { + CSLoadAchievementIconForPage( m_pAchievementIcon, m_pSourceAchievement ); + + SetBgColor( pScheme->GetColor( "AchievementsLightGrey", Color(255, 0, 0, 255) ) ); + + m_pAchievementNameLabel->SetFgColor( pScheme->GetColor( "SteamLightGreen", Color(255, 255, 255, 255) ) ); + + Color fgColor = pScheme->GetColor( "Label.TextBrightColor", Color(255, 255, 255, 255) ); + m_pAchievementDescLabel->SetFgColor( fgColor ); + m_pPercentageText->SetFgColor( fgColor ); + m_pShowOnHUDButton->SetVisible( false ); + m_pShowOnHUDButton->SetSelected( false ); + m_pHiddenHUDToggleButton->SetVisible( false ); + m_pAwardDate->SetVisible( true ); + m_pAwardDate->SetFgColor( pScheme->GetColor( "SteamLightGreen", Color(255, 255, 255, 255) ) ); + + // Assign the award date text + int year, month, day, hour, minute, second; + if ( m_pSourceAchievement->GetAwardTime(year, month, day, hour, minute, second) ) + { + char dateBuffer[32] = ""; + Q_snprintf( dateBuffer, 32, "%4d-%02d-%02d", year, month, day ); + m_pAwardDate->SetText( dateBuffer ); + } + else + m_pAwardDate->SetText( "" ); + } + else + { + CSLoadAchievementIconForPage( m_pAchievementIcon, m_pSourceAchievement, "_bw" ); + + SetBgColor( pScheme->GetColor( "AchievementsDarkGrey", Color(255, 0, 0, 255) ) ); + + Color fgColor = pScheme->GetColor( "AchievementsInactiveFG", Color(255, 255, 255, 255) ); + m_pAchievementNameLabel->SetFgColor( fgColor ); + m_pAchievementDescLabel->SetFgColor( fgColor ); + m_pPercentageText->SetFgColor( fgColor ); + + if ( CSGameSupportsAchievementTrackerForPage() ) + { + m_pShowOnHUDButton->SetVisible( !m_pSourceAchievement->ShouldHideUntilAchieved() ); + m_pShowOnHUDButton->SetSelected( m_pSourceAchievement->ShouldShowOnHUD() ); + + m_pHiddenHUDToggleButton->SetVisible( !m_pSourceAchievement->ShouldHideUntilAchieved() ); + } + else + { + m_pShowOnHUDButton->SetVisible( false ); + m_pHiddenHUDToggleButton->SetVisible( false ); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Makes a local copy of a pointer to the achievement entity stored on the client. +//----------------------------------------------------------------------------- +void CAchievementsPageItemPanel::SetAchievementInfo( CCSBaseAchievement* pAchievement ) +{ + if ( !pAchievement ) + { + Assert( 0 ); + return; + } + + m_pSourceAchievement = pAchievement; + m_iSourceAchievementIndex = pAchievement->GetAchievementID(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CAchievementsPageItemPanel::PreloadResourceFile( void ) +{ + const char *controlResourceName = "resource/ui/AchievementItem.res"; + + g_pPreloadedCSAchievementPageItemLayout = new KeyValues(controlResourceName); + g_pPreloadedCSAchievementPageItemLayout->LoadFromFile(g_pFullFileSystem, controlResourceName); + +/* + // precache all achievement icons + int iCount = g_AchievementMgrCS.GetAchievementCount(); + for ( int i = 0; i < iCount; ++i ) + { + CCSBaseAchievement* pAchievement = dynamic_cast<CCSBaseAchievement*>(g_AchievementMgrCS.GetAchievementByIndex( i )); + char imagePath[_MAX_PATH]; + + Q_strncpy( imagePath, "achievements\\", sizeof(imagePath) ); + Q_strncat( imagePath, pAchievement->GetName(), sizeof(imagePath), COPY_ALL_CHARACTERS ); + Q_strncat( imagePath, "_bw", sizeof(imagePath), COPY_ALL_CHARACTERS ); + Q_strncat( imagePath, ".vtf", sizeof(imagePath), COPY_ALL_CHARACTERS ); + + scheme()->GetImage(imagePath, true); + + Q_strncpy( imagePath, "achievements\\", sizeof(imagePath) ); + Q_strncat( imagePath, pAchievement->GetName(), sizeof(imagePath), COPY_ALL_CHARACTERS ); + Q_strncat( imagePath, ".vtf", sizeof(imagePath), COPY_ALL_CHARACTERS ); + + scheme()->GetImage(imagePath, true); + } +*/ +} + +//----------------------------------------------------------------------------- +// Purpose: Loads settings from hl2/resource/ui/achievementitem.res +// Sets display info for this achievement item. +//----------------------------------------------------------------------------- +void CAchievementsPageItemPanel::ApplySchemeSettings( vgui::IScheme* pScheme ) +{ + if ( !g_pPreloadedCSAchievementPageItemLayout ) + { + PreloadResourceFile(); + } + + LoadControlSettings( "", NULL, g_pPreloadedCSAchievementPageItemLayout ); + + m_pSchemeSettings = pScheme; + + if ( !m_pSourceAchievement ) + { + return; + } + + BaseClass::ApplySchemeSettings( pScheme ); + + // m_pSchemeSettings must be set for this. + UpdateAchievementInfo( pScheme ); +} + +void CAchievementsPageItemPanel::OnCheckButtonChecked(Panel *panel) +{ + if ( CSGameSupportsAchievementTrackerForPage() && panel == m_pShowOnHUDButton && m_pSourceAchievement ) + { + m_pSourceAchievement->SetShowOnHUD( m_pShowOnHUDButton->IsSelected() ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: creates child panels, passes down name to pick up any settings from res files. +//----------------------------------------------------------------------------- +CAchievementsPageGroupPanel::CAchievementsPageGroupPanel( vgui::PanelListPanel *parent, CAchievementsPage *owner, const char* name, int iListItemID ) : BaseClass( parent, name ) +{ + m_pParent = parent; + m_pOwner = owner; + m_pSchemeSettings = NULL; + + m_pGroupIcon = SETUP_PANEL(new vgui::ImagePanel( this, "GroupIcon" )); + m_pAchievementGroupLabel = new vgui::Label( this, "GroupName", "name" ); + m_pPercentageText = new vgui::Label( this, "GroupPercentageText", "1/1" ); + m_pPercentageBar = SETUP_PANEL( new ImagePanel( this, "GroupPercentageBar" ) ); + m_pGroupButton = new CGroupButton( this, "GroupButton", "" ); + m_pGroupButton->SetPos( 0, 0 ); + m_pGroupButton->SetZPos( 20 ); + m_pGroupButton->SetWide( 256 ); + m_pGroupButton->SetTall( 64 ); + SetMouseInputEnabled( true ); + parent->SetMouseInputEnabled( true ); + + m_bActiveButton = false; +} + +CAchievementsPageGroupPanel::~CAchievementsPageGroupPanel() +{ + delete m_pAchievementGroupLabel; + delete m_pPercentageBar; + delete m_pPercentageText; + delete m_pGroupIcon; +} + +//----------------------------------------------------------------------------- +// Purpose: Loads settings from hl2/resource/ui/achievementitem.res +// Sets display info for this achievement item. +//----------------------------------------------------------------------------- +void CAchievementsPageGroupPanel::ApplySchemeSettings( vgui::IScheme* pScheme ) +{ + if ( !g_pPreloadedCSAchievementPageGroupLayout ) + { + PreloadResourceFile(); + } + + LoadControlSettings( "", NULL, g_pPreloadedCSAchievementPageGroupLayout ); + + m_pSchemeSettings = pScheme; + + BaseClass::ApplySchemeSettings( pScheme ); + + // m_pSchemeSettings must be set for this. + UpdateAchievementInfo( pScheme ); +} + +//----------------------------------------------------------------------------- +// Purpose: Updates displayed achievement data. In ApplySchemeSettings(), and +// when gameui activates. +//----------------------------------------------------------------------------- +void CAchievementsPageGroupPanel::UpdateAchievementInfo( vgui::IScheme* pScheme ) +{ + if ( m_pSchemeSettings ) + { + int numAwarded = 0; + int numTested = 0; + + char buf[128]; + int achievementRangeStart = (m_iFirstAchievementID / 1000) * 1000; + Q_snprintf( buf, sizeof(buf), "#Achievement_Group_%d", achievementRangeStart ); + + wchar_t *wzGroupName = g_pVGuiLocalize->Find( buf ); + + if ( !wzGroupName ) + { + wzGroupName = L"Need Title ( %s1 of %s2 )"; + } + + wchar_t wzGroupTitle[128]; + + if ( wzGroupName ) + { + // Determine number of achievements in the group which have been awarded + for (int i = m_iFirstAchievementID; i < m_iLastAchievementID; i++) + { + IAchievement* pCur = g_AchievementMgrCS.GetAchievementByID( i ); + + if ( !pCur ) + continue; + + numTested++; + + if ( pCur->IsAchieved() ) + { + numAwarded++; + } + } + + wchar_t wzNumUnlocked[8]; + V_snwprintf( wzNumUnlocked, ARRAYSIZE( wzNumUnlocked ), L"%d", numAwarded ); + + wchar_t wzNumAchievements[8]; + V_snwprintf( wzNumAchievements,ARRAYSIZE( wzNumAchievements ), L"%d", numTested ); + + g_pVGuiLocalize->ConstructString( wzGroupTitle, sizeof( wzGroupTitle ), wzGroupName, 2, wzNumUnlocked, wzNumAchievements ); + } + + // Set group name text + m_pAchievementGroupLabel->SetText( wzGroupTitle );//m_pGroupName ); + m_pAchievementGroupLabel->SetFgColor(Color(157, 194, 80, 255)); + + char* buff[32]; + Q_snprintf( (char*)buff, 32, "%d / %d", numAwarded, numTested ); + m_pPercentageText->SetText( (const char*)buff ); + m_pPercentageText->SetFgColor(Color(157, 194, 80, 255)); + + if ( !m_bActiveButton ) + { + CSLoadIconForPage( m_pGroupIcon, "achievement-btn-up" ); + } + else + { + CSLoadIconForPage( m_pGroupIcon, "achievement-btn-select" ); + } + + // Update the percentage complete bar + vgui::ImagePanel *pPercentageBar = (vgui::ImagePanel*)FindChildByName( "GroupPercentageBar" ); + vgui::ImagePanel *pPercentageBarBkg = (vgui::ImagePanel*)FindChildByName( "GroupPercentageBarBackground" ); + + if ( pPercentageBar && pPercentageBarBkg ) + { + float flCompletion = (float)numAwarded / (float)numTested; + pPercentageBar->SetFillColor( Color(157, 194, 80, 255) ); + pPercentageBar->SetWide( pPercentageBarBkg->GetWide() * flCompletion ); + + SetControlVisible( "GroupPercentageBarBackground", true ); + SetControlVisible( "GroupPercentageBar", true ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CAchievementsPageGroupPanel::PreloadResourceFile( void ) +{ + const char *controlResourceName = "resource/ui/AchievementGroup.res"; + + g_pPreloadedCSAchievementPageGroupLayout = new KeyValues(controlResourceName); + g_pPreloadedCSAchievementPageGroupLayout->LoadFromFile(g_pFullFileSystem, controlResourceName); + + +} + +//----------------------------------------------------------------------------- +// Purpose: Assigns a name and achievement id bounds for an achievement group. +//----------------------------------------------------------------------------- +void CAchievementsPageGroupPanel::SetGroupInfo( const wchar_t* name, int firstAchievementID, int lastAchievementID ) +{ + // Store away the group name + short _textLen = (short)wcslen(name) + 1; + m_pGroupName = new wchar_t[_textLen]; + Q_memcpy( m_pGroupName, name, _textLen * sizeof(wchar_t) ); + + // Store off the start & end achievement IDs + m_iFirstAchievementID = firstAchievementID; + m_iLastAchievementID = lastAchievementID; +} + +CGroupButton::CGroupButton( vgui::Panel *pParent, const char *pName, const char *pText ) : +BaseClass( pParent, pName, pText ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Handle the case where the user presses an achievement group button. +//----------------------------------------------------------------------------- +void CGroupButton::DoClick( void ) +{ + // Process when a group button is hit + CAchievementsPageGroupPanel* pParent = static_cast<CAchievementsPageGroupPanel*>(GetParent()); + + if (pParent) + { + CAchievementsPage* pAchievementsPage = static_cast<CAchievementsPage*>(pParent->GetOwner()); + + if (pAchievementsPage) + { + // Update the list of group achievements + pAchievementsPage->UpdateAchievementList( pParent ); + } + } +} + +void CAchievementsPage::OnPageShow() +{ + m_pGroupsList->GetScrollbar()->SetWide(0); +} + +void CAchievementsPage::FireGameEvent( IGameEvent *event ) +{ + const char *type = event->GetName(); + + if ( 0 == Q_strcmp( type, "achievement_earned_local" ) ) + m_bAchievementsDirty = true; + + if ( 0 == Q_strcmp( type, "player_stats_updated" ) ) + m_bStatsDirty = true; +} + +void CAchievementsPage::OnThink() +{ + vgui::IScheme *pScheme = scheme()->GetIScheme( GetScheme() ); + + if ( m_bAchievementsDirty ) + { + UpdateAchievementDialogInfo(); + } + else if ( m_bStatsDirty ) + { + // Update progress for currently displayed achievements + int itemId = m_pAchievementsList->FirstItem(); + + while (itemId != m_pAchievementsList->InvalidItemID() ) + { + CAchievementsPageItemPanel *pAchievementItem = dynamic_cast<CAchievementsPageItemPanel*>(m_pAchievementsList->GetItemPanel(itemId)); + pAchievementItem->UpdateAchievementInfo(pScheme); + + itemId = m_pAchievementsList->NextItem(itemId); + } + m_bStatsDirty = false; + } +} + +CHiddenHUDToggleButton::CHiddenHUDToggleButton( vgui::Panel *pParent, const char *pName, const char *pText ) : +BaseClass( pParent, pName, pText ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Handle the case where the user shift-clicks on an un-awarded achievement. +//----------------------------------------------------------------------------- +void CHiddenHUDToggleButton::DoClick( void ) +{ + if ( input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT) ) + { + // Process when a group button is hit + CAchievementsPageItemPanel* pParent = static_cast<CAchievementsPageItemPanel*>(GetParent()); + + if (pParent) + { + pParent->ToggleShowOnHUDButton(); + } + } +} |