summaryrefslogtreecommitdiff
path: root/game/client/hud_baseachievement_tracker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/client/hud_baseachievement_tracker.cpp')
-rw-r--r--game/client/hud_baseachievement_tracker.cpp608
1 files changed, 608 insertions, 0 deletions
diff --git a/game/client/hud_baseachievement_tracker.cpp b/game/client/hud_baseachievement_tracker.cpp
new file mode 100644
index 0000000..4a128b2
--- /dev/null
+++ b/game/client/hud_baseachievement_tracker.cpp
@@ -0,0 +1,608 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Draws achievement progress bars on the HUD
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hudelement.h"
+#include "hud_macros.h"
+#include <game_controls/baseviewport.h>
+#include <vgui_controls/Controls.h>
+#include <vgui_controls/Panel.h>
+#include <vgui_controls/ImagePanel.h>
+#include <vgui_controls/TextImage.h>
+#include "vgui/ILocalize.h"
+#include "hud_baseachievement_tracker.h"
+#include "iachievementmgr.h"
+#include "baseachievement.h"
+#include "iclientmode.h"
+#include "cdll_int.h"
+#include <vgui/ISurface.h>
+#include <vgui_controls/AnimationController.h>
+#include "fmtstr.h"
+#include "engine/IEngineSound.h"
+
+//=============================================================================
+// HPE_BEGIN
+// [dwenger] Necessary for HUD Achievement display
+//=============================================================================
+
+#include "cdll_client_int.h"
+#include "steam/isteamuserstats.h"
+#include "steam/steam_api.h"
+
+//=============================================================================
+// HPE_END
+//=============================================================================
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+#define PROGRESS_BAR_NEEDS_UPDATE -1
+#define UNKNOWN_ACHIEVEMENT_ID -1
+
+void TrackerDescriptionChanged( IConVar *var, const char *pOldString, float flOldValue )
+{
+ static int s_iTimesChanged = 0;
+ if ( s_iTimesChanged > 0 )
+ {
+ engine->ClientCmd_Unrestricted( "hud_reloadscheme" );
+ }
+ s_iTimesChanged++;
+}
+ConVar hud_achievement_description("hud_achievement_description", "1", FCVAR_ARCHIVE, "Show full descriptions of achievements on the HUD", TrackerDescriptionChanged );
+#ifdef CSTRIKE_DLL
+ConVar hud_achievement_count("hud_achievement_count", "5", FCVAR_ARCHIVE, "Max number of achievements that can be shown on the HUD" );
+#else
+ConVar hud_achievement_count("hud_achievement_count", "8", FCVAR_ARCHIVE, "Max number of achievements that can be shown on the HUD" );
+#endif
+ConVar hud_achievement_glowtime("hud_achievement_glowtime", "2.5", FCVAR_NONE, "Duration of glow effect around incremented achievements" );
+ConVar hud_achievement_tracker("hud_achievement_tracker", "1", FCVAR_NONE, "Show or hide the achievement tracker" );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHudBaseAchievementTracker::CHudBaseAchievementTracker( const char *pElementName ) :
+ CHudElement( pElementName ), BaseClass( NULL, "HudAchievementTracker" )
+{
+ vgui::Panel *pParent = g_pClientMode->GetViewport();
+ SetParent( pParent );
+
+ SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD );
+
+ for ( int i=0; i < GetMaxAchievementsShown(); i++ )
+ {
+ CAchievementTrackerItem *pNewItem = CreateAchievementPanel();
+ pNewItem->SetAchievement( NULL );
+ m_AchievementItem.AddToTail( pNewItem );
+ }
+
+ m_flNextThink = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudBaseAchievementTracker::Reset()
+{
+ m_flNextThink = gpGlobals->curtime + 0.05f;
+}
+
+void CHudBaseAchievementTracker::LevelInit()
+{
+ // clear out tracker items and floating numbers on level change
+ for ( int i = 0; i < GetChildCount(); i++ )
+ {
+ GetChild( i )->SetVisible( false );
+ GetChild( i )->MarkForDeletion();
+ }
+ m_AchievementItem.Purge();
+
+ for ( int i=0; i < GetMaxAchievementsShown(); i++ )
+ {
+ CAchievementTrackerItem *pNewItem = CreateAchievementPanel();
+ pNewItem->SetAchievement( NULL );
+ m_AchievementItem.AddToTail( pNewItem );
+ }
+
+
+ CHudElement::LevelInit();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudBaseAchievementTracker::ApplySchemeSettings( IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CHudBaseAchievementTracker::ShouldDraw()
+{
+ if ( engine->IsPlayingDemo() )
+ return false;
+
+ return CHudElement::ShouldDraw();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudBaseAchievementTracker::OnThink()
+{
+ if ( m_flNextThink < gpGlobals->curtime )
+ {
+ UpdateAchievementItems();
+ m_flNextThink = gpGlobals->curtime + 0.5f;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Max number of achievements shown on the HUD
+//-----------------------------------------------------------------------------
+int CHudBaseAchievementTracker::GetMaxAchievementsShown()
+{
+ return hud_achievement_count.GetInt();
+}
+
+bool CHudBaseAchievementTracker::ShouldShowAchievement( IAchievement *pAchievement )
+{
+ return ( hud_achievement_tracker.GetBool() && pAchievement && pAchievement->ShouldShowOnHUD() && !pAchievement->IsAchieved() );
+}
+
+CAchievementTrackerItem* CHudBaseAchievementTracker::CreateAchievementPanel()
+{
+ return new CAchievementTrackerItem( this, "HudAchievementTrackerItem" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: create panels for each achievement the player wants shown on the HUD and assign achievements to each one
+//-----------------------------------------------------------------------------
+void CHudBaseAchievementTracker::UpdateAchievementItems()
+{
+ IAchievementMgr *pAchievementMgr = engine->GetAchievementMgr();
+ if ( !pAchievementMgr )
+ return;
+
+ int iCount = pAchievementMgr->GetAchievementCount();
+ int iShown = 0;
+ for ( int i = 0; i < iCount; ++i )
+ {
+ IAchievement* pCur = pAchievementMgr->GetAchievementByIndex( i );
+ if ( !ShouldShowAchievement( pCur ) )
+ {
+ // don't remove achievements that are still glowing (typically a just completed achievement)
+ if ( pCur && m_AchievementItem.Count() > iShown && m_AchievementItem[iShown]->GetAchievementID() == pCur->GetAchievementID()
+ && m_AchievementItem[iShown]->GetGlow() > 0 )
+ {
+ iShown++;
+ }
+ continue;
+ }
+
+ if ( m_AchievementItem.Count() < iShown+1 )
+ {
+ CAchievementTrackerItem *pNewItem = CreateAchievementPanel();
+ SETUP_PANEL( pNewItem );
+ m_AchievementItem.AddToTail( pNewItem );
+ }
+
+ m_AchievementItem[iShown]->SetAchievement( pCur );
+ m_AchievementItem[iShown]->SetSlot( iShown );
+ m_AchievementItem[iShown]->SetVisible( true );
+ iShown++;
+
+ if ( iShown >= GetMaxAchievementsShown() )
+ break;
+ }
+
+ // hide any extra panels we may have created from when the list was longer
+ if ( iShown < m_AchievementItem.Count() )
+ {
+ for ( int i = m_AchievementItem.Count() - 1; i >= iShown ; i-- )
+ {
+ m_AchievementItem[i]->SetVisible( false );
+ m_AchievementItem[i]->SetAchievement( NULL );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Layout all child panels vertically
+//-----------------------------------------------------------------------------
+void CHudBaseAchievementTracker::PerformLayout()
+{
+ // make sure all children are laid out first
+ for ( int i=0; i < m_AchievementItem.Count(); i++ )
+ {
+ m_AchievementItem[i]->InvalidateLayout( true );
+ }
+
+ int iCurrentY = 0;
+ int x, y;
+ for ( int i=0; i< m_AchievementItem.Count(); i++ )
+ {
+ m_AchievementItem[i]->GetPos( x, y );
+ m_AchievementItem[i]->SetPos( x, iCurrentY );
+ iCurrentY += m_AchievementItem[i]->GetTall() + m_iItemPadding;
+ }
+}
+
+CAchievementTrackerItem* CHudBaseAchievementTracker::GetAchievementPanel( int i )
+{
+ if ( i < 0 || i >= m_AchievementItem.Count() )
+ return NULL;
+
+ return m_AchievementItem[i];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: The child panels
+//-----------------------------------------------------------------------------
+
+CAchievementTrackerItem::CAchievementTrackerItem( vgui::Panel* pParent, const char *pElementName ) :
+ BaseClass( pParent, pElementName )
+{
+ m_pAchievementNameGlow = new vgui::Label( this, "AchievementNameGlow", "" );
+ m_pAchievementName = new vgui::Label( this, "AchievementName", "" );
+ m_pAchievementDesc = new vgui::Label( this, "AchievementDesc", "" );
+ m_pProgressBarBackground = SETUP_PANEL( new ImagePanel( this, "ProgressBarBG" ) );
+ m_pProgressBar = SETUP_PANEL( new ImagePanel( this, "ProgressBar" ) );
+
+ m_iAchievementID = UNKNOWN_ACHIEVEMENT_ID;
+ m_iLastPaintedAchievementID = UNKNOWN_ACHIEVEMENT_ID;
+ m_iAccumulatedIncrement = 0;
+ m_flShowIncrementsTime = 0;
+ m_iLastCount = 0;
+ m_iPadding = 1;
+}
+
+CAchievementTrackerItem::~CAchievementTrackerItem()
+{
+ if ( m_pAchievementName )
+ {
+ m_pAchievementName->MarkForDeletion();
+ m_pAchievementName = NULL;
+ }
+
+ if ( m_pAchievementNameGlow )
+ {
+ m_pAchievementNameGlow->MarkForDeletion();
+ m_pAchievementNameGlow = NULL;
+ }
+
+ if ( m_pAchievementDesc )
+ {
+ m_pAchievementDesc->MarkForDeletion();
+ m_pAchievementDesc = NULL;
+ }
+
+ if ( m_pProgressBarBackground )
+ {
+ m_pProgressBarBackground->MarkForDeletion();
+ m_pProgressBarBackground = NULL;
+ }
+
+ if ( m_pProgressBar )
+ {
+ m_pProgressBar->MarkForDeletion();
+ m_pProgressBar = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CAchievementTrackerItem::ApplySchemeSettings( IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ LoadControlSettings( "resource/UI/HudAchievementTrackerItem.res" );
+ m_pAchievementDesc->SetVisible( hud_achievement_description.GetBool() );
+ m_iLastPaintedAchievementID = UNKNOWN_ACHIEVEMENT_ID;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CAchievementTrackerItem::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ int x, y, w, t;
+
+ //=============================================================================
+ // HPE_BEGIN
+ // [dwenger] Necessary for HUD Achievement display
+ //=============================================================================
+
+ m_pAchievementName->GetContentSize( w, t ); // needed in order to load up font for the name
+ m_pAchievementNameGlow->GetContentSize( w, t ); // needed in order to load up font for the glow
+
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+
+ if ( hud_achievement_description.GetBool() )
+ {
+ m_pAchievementDesc->GetContentSize( w, t );
+ m_pAchievementDesc->SetTall( t );
+ m_pAchievementDesc->GetBounds( x, y, w, t );
+ }
+ else
+ {
+ m_pAchievementName->GetBounds( x, y, w, t );
+ }
+
+ if ( m_pProgressBarBackground->IsVisible() )
+ {
+ // put progress bar after description
+ int bx, by;
+ m_pProgressBarBackground->GetPos( bx, by );
+ m_pProgressBarBackground->SetPos( bx, y + t + m_iPadding );
+
+ SetTall( y + t + m_pProgressBarBackground->GetTall() + m_iPadding * 2 );
+ }
+ else
+ {
+ SetTall( y + t + m_iPadding );
+ }
+
+ m_iLastProgressBarCount = m_iLastProgressBarGoal = PROGRESS_BAR_NEEDS_UPDATE;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CAchievementTrackerItem::SetAchievement( IAchievement* pAchievement )
+{
+ if ( !pAchievement )
+ {
+ m_iAchievementID = UNKNOWN_ACHIEVEMENT_ID;
+ m_iLastCount = 0;
+ return;
+
+ }
+ if ( m_iAchievementID != pAchievement->GetAchievementID() )
+ {
+ m_iAchievementID = pAchievement->GetAchievementID();
+ m_iLastCount = pAchievement->GetCount();
+ UpdateAchievementDisplay();
+ }
+}
+
+void CAchievementTrackerItem::OnThink()
+{
+ UpdateAchievementDisplay();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Make sure our labels and progress bar are up to date
+//-----------------------------------------------------------------------------
+void CAchievementTrackerItem::UpdateAchievementDisplay()
+{
+ IAchievementMgr *pAchievementMgr = engine->GetAchievementMgr();
+ if ( !pAchievementMgr )
+ return;
+
+ CBaseAchievement* pAchievement = pAchievementMgr->GetAchievementByID( m_iAchievementID );
+ if ( !pAchievement )
+ return;
+
+ if ( m_iAchievementID != m_iLastPaintedAchievementID )
+ {
+ // need to update labels
+
+ //=============================================================================
+ // HPE_BEGIN
+ // [dwenger] Necessary for HUD Achievement display
+ //=============================================================================
+
+ m_pAchievementName->SetText( ACHIEVEMENT_LOCALIZED_NAME( pAchievement ) );
+ m_pAchievementNameGlow->SetText( ACHIEVEMENT_LOCALIZED_NAME( pAchievement ) );
+ m_pAchievementDesc->SetText( ACHIEVEMENT_LOCALIZED_DESC( pAchievement ) );
+
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+
+ m_pProgressBarBackground->SetVisible( pAchievement->GetGoal() > 1 );
+ m_pProgressBar->SetVisible( pAchievement->GetGoal() > 1 );
+
+ m_iLastPaintedAchievementID = m_iAchievementID;
+ m_flGlow = 0.0f;
+ m_flGlowTime = 0.0f;
+ m_iAccumulatedIncrement = 0;
+ //InvalidateLayout( true );
+ GetParent()->InvalidateLayout( true );
+ }
+
+ if ( m_iAccumulatedIncrement > 0 && gpGlobals->curtime > m_flShowIncrementsTime )
+ {
+ ShowAccumulatedIncrements();
+ }
+
+ if ( pAchievement->GetCount() != m_iLastProgressBarCount || pAchievement->GetGoal() != m_iLastProgressBarGoal )
+ {
+ // need to update progress bar
+ float flProgress = float ( pAchievement->GetCount() ) / float( pAchievement->GetGoal() );
+ int x, y, w, t;
+ m_pProgressBarBackground->GetBounds( x, y, w, t );
+ m_pProgressBar->SetBounds( x, y, w * flProgress, t );
+
+ m_iLastProgressBarCount = pAchievement->GetCount();
+ m_iLastProgressBarGoal = pAchievement->GetGoal();
+
+ AchievementIncremented( pAchievement->GetCount() );
+ }
+
+ if ( gpGlobals->curtime < m_flGlowTime )
+ {
+ m_flGlow = MIN( 1.0f, m_flGlow + gpGlobals->frametime * 5.0f );
+ }
+ else
+ {
+ m_flGlow = MAX( 0.0f, m_flGlow - gpGlobals->frametime * 5.0f );
+ }
+ m_pAchievementNameGlow->SetAlpha( m_flGlow * 255.0f );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Achievement count has gone up, make it flash
+//-----------------------------------------------------------------------------
+void CAchievementTrackerItem::AchievementIncremented( int iNewCount )
+{
+ int iIncrement = iNewCount - m_iLastCount;
+ m_iLastCount = iNewCount;
+
+ if ( iIncrement <= 0 )
+ return;
+
+ if ( m_iLastProgressBarGoal > 1500 )
+ {
+ // for achievements with very high counts, accumulate increments so we don't have too many +1s on screen
+ // also don't play sounds as these achievements tend to increment constantly
+
+ if ( m_flShowIncrementsTime < gpGlobals->curtime )
+ {
+ m_flShowIncrementsTime = gpGlobals->curtime + 2.0f;
+ }
+ m_iAccumulatedIncrement += iIncrement;
+ }
+ else
+ {
+ m_flGlowTime = gpGlobals->curtime + hud_achievement_glowtime.GetFloat();
+
+ // create a floating +X to scroll up alongside this achievement
+ if ( m_pProgressBarBackground->IsVisible() )
+ {
+ int px, py;
+ GetPos( px, py );
+ int x, y, w, t;
+ m_pProgressBarBackground->GetBounds( x, y, w, t );
+ x += w;
+ new CFloatingAchievementNumber( iIncrement, px + x, py + y + ( t * 0.5f ), FN_DIR_RIGHT, GetParent() );
+ }
+
+ CLocalPlayerFilter filter;
+ C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "Hud.AchievementIncremented" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Show all the increments we've accumulated
+//-----------------------------------------------------------------------------
+void CAchievementTrackerItem::ShowAccumulatedIncrements()
+{
+ int px, py;
+ GetPos( px, py );
+ int x, y, w, t;
+ m_pProgressBarBackground->GetBounds( x, y, w, t );
+ x += w;
+ new CFloatingAchievementNumber( m_iAccumulatedIncrement, px + x, py + y + ( t * 0.5f ), FN_DIR_RIGHT, GetParent() );
+
+ m_iAccumulatedIncrement = 0;
+ m_flGlowTime = gpGlobals->curtime + hud_achievement_glowtime.GetFloat();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Floating numbers showing how much achievement progress bars have gone up
+//-----------------------------------------------------------------------------
+
+CFloatingAchievementNumber::CFloatingAchievementNumber( int iProgress, int x, int y, floating_number_directions iDir, vgui::Panel* pParent )
+ : BaseClass( pParent, "FloatingAchievementNumber" )
+{
+ m_iStartX = x;
+ m_iStartY = y;
+ m_iProgress = iProgress;
+ m_fStartTime = gpGlobals->curtime;
+ m_iDirection = iDir;
+
+ char szLabel[64];
+ Q_snprintf( szLabel, sizeof( szLabel ), "+%d", iProgress );
+ m_pNumberLabel = new vgui::Label( this, "FloatingNumberLabel", szLabel );
+}
+
+CFloatingAchievementNumber::~CFloatingAchievementNumber()
+{
+ if ( m_pNumberLabel )
+ {
+ m_pNumberLabel->MarkForDeletion();
+ m_pNumberLabel = NULL;
+ }
+}
+
+void CFloatingAchievementNumber::ApplySchemeSettings( vgui::IScheme *scheme )
+{
+ BaseClass::ApplySchemeSettings( scheme );
+
+ LoadControlSettings( "resource/UI/HudAchievementFloatingNumber.res" );
+
+ int fontHeight = surface()->GetFontTall( m_pNumberLabel->GetFont() );
+ SetPos( m_iStartX, m_iStartY - ( fontHeight * 0.5f ) );
+ m_pNumberLabel->SetAlpha( 0 );
+ GetAnimationController()->RunAnimationCommand( m_pNumberLabel, "alpha", 255, 0, 0.3, vgui::AnimationController::INTERPOLATOR_LINEAR );
+
+ switch ( m_iDirection )
+ {
+ default:
+ case FN_DIR_UP:
+ vgui::GetAnimationController()->RunAnimationCommand( this, "ypos", m_iStartY - m_iScrollDistance, 0, 2.0f, vgui::AnimationController::INTERPOLATOR_LINEAR );
+ break;
+ case FN_DIR_DOWN:
+ vgui::GetAnimationController()->RunAnimationCommand( this, "ypos", m_iStartY + m_iScrollDistance, 0, 2.0f, vgui::AnimationController::INTERPOLATOR_LINEAR );
+ break;
+ case FN_DIR_LEFT:
+ vgui::GetAnimationController()->RunAnimationCommand( this, "xpos", m_iStartX - m_iScrollDistance, 0, 2.0f, vgui::AnimationController::INTERPOLATOR_LINEAR );
+ break;
+ case FN_DIR_RIGHT:
+ vgui::GetAnimationController()->RunAnimationCommand( this, "xpos", m_iStartX + m_iScrollDistance, 0, 2.0f, vgui::AnimationController::INTERPOLATOR_LINEAR );
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Delete panel when floating number has faded out
+//-----------------------------------------------------------------------------
+void CFloatingAchievementNumber::OnThink()
+{
+ if ( gpGlobals->curtime > m_fStartTime + 1.0f )
+ {
+ if ( m_pNumberLabel->GetAlpha() >= 255 )
+ {
+ m_pNumberLabel->SetAlpha( 254 );
+ GetAnimationController()->RunAnimationCommand( m_pNumberLabel, "alpha", 0, 0.0, 1.0f, vgui::AnimationController::INTERPOLATOR_LINEAR );
+ }
+ else if ( m_pNumberLabel->GetAlpha() <= 0 )
+ {
+ MarkForDeletion();
+ SetVisible( false );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Debug command to make one of the achievement panels flash as though it just went up
+//-----------------------------------------------------------------------------
+class CHudAchievementTracker;
+void cc_TrackerAnim_f( const CCommand &args )
+{
+ CHudBaseAchievementTracker *pTracker = ( CHudBaseAchievementTracker * )GET_HUDELEMENT( CHudAchievementTracker );
+ if ( !pTracker )
+ return;
+
+ CAchievementTrackerItem *pItem = pTracker->GetAchievementPanel( atoi(args[1]) );
+ if ( !pItem )
+ return;
+
+ pItem->AchievementIncremented( pItem->GetLastCount() + RandomInt(1, 1) );
+}
+
+ConCommand cc_TrackerAnim( "TrackerAnim", cc_TrackerAnim_f, "Test animation of the achievement tracker. Parameter is achievement number on HUD to flash", FCVAR_NONE );