Counter Strike : Global Offensive Source Code
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.

554 lines
18 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Draws achievement progress bars on the HUD
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "hudelement.h"
  9. #include "hud_macros.h"
  10. #include <game_controls/baseviewport.h>
  11. #include <vgui_controls/controls.h>
  12. #include <vgui_controls/panel.h>
  13. #include <vgui_controls/ImagePanel.h>
  14. #include <vgui_controls/TextImage.h>
  15. #include "vgui/ILocalize.h"
  16. #include "hud_baseachievement_tracker.h"
  17. #include "iachievementmgr.h"
  18. #include "baseachievement.h"
  19. #include "iclientmode.h"
  20. #include "cdll_int.h"
  21. #include <vgui/ISurface.h>
  22. #include <vgui_controls/AnimationController.h>
  23. #include "fmtstr.h"
  24. #include "engine/IEngineSound.h"
  25. #include "cdll_client_int.h"
  26. #include "steam/isteamuserstats.h"
  27. #include "steam/steam_api.h"
  28. // memdbgon must be the last include file in a .cpp file!!!
  29. #include "tier0/memdbgon.h"
  30. using namespace vgui;
  31. #define PROGRESS_BAR_NEEDS_UPDATE -1
  32. #define UNKNOWN_ACHIEVEMENT_ID -1
  33. void TrackerDescriptionChanged( IConVar *var, const char *pOldString, float flOldValue )
  34. {
  35. static int s_iTimesChanged = 0;
  36. if ( s_iTimesChanged > 0 )
  37. {
  38. engine->ClientCmd_Unrestricted( "hud_reloadscheme" );
  39. }
  40. s_iTimesChanged++;
  41. }
  42. ConVar hud_achievement_description("hud_achievement_description", "1", FCVAR_ARCHIVE, "Show full descriptions of achievements on the HUD", TrackerDescriptionChanged );
  43. #ifdef CSTRIKE_DLL
  44. ConVar hud_achievement_count("hud_achievement_count", "5", FCVAR_ARCHIVE, "Max number of achievements that can be shown on the HUD" );
  45. #else
  46. ConVar hud_achievement_count("hud_achievement_count", "8", FCVAR_ARCHIVE, "Max number of achievements that can be shown on the HUD" );
  47. #endif
  48. ConVar hud_achievement_glowtime("hud_achievement_glowtime", "2.5", FCVAR_NONE, "Duration of glow effect around incremented achievements" );
  49. ConVar hud_achievement_tracker("hud_achievement_tracker", "1", FCVAR_NONE, "Show or hide the achievement tracker" );
  50. //-----------------------------------------------------------------------------
  51. // Purpose:
  52. //-----------------------------------------------------------------------------
  53. CHudBaseAchievementTracker::CHudBaseAchievementTracker( const char *pElementName ) :
  54. CHudElement( pElementName ), BaseClass( NULL, "HudAchievementTracker" )
  55. {
  56. vgui::Panel *pParent = GetClientMode()->GetViewport();
  57. SetParent( pParent );
  58. SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD );
  59. for ( int i=0; i < GetMaxAchievementsShown(); i++ )
  60. {
  61. CAchievementTrackerItem *pNewItem = CreateAchievementPanel();
  62. pNewItem->SetAchievement( NULL );
  63. m_AchievementItem.AddToTail( pNewItem );
  64. }
  65. m_flNextThink = 0;
  66. }
  67. //-----------------------------------------------------------------------------
  68. // Purpose:
  69. //-----------------------------------------------------------------------------
  70. void CHudBaseAchievementTracker::Reset()
  71. {
  72. m_flNextThink = gpGlobals->curtime + 0.05f;
  73. }
  74. void CHudBaseAchievementTracker::LevelInit()
  75. {
  76. // clear out tracker items and floating numbers on level change
  77. for ( int i = 0; i < GetChildCount(); i++ )
  78. {
  79. GetChild( i )->SetVisible( false );
  80. GetChild( i )->MarkForDeletion();
  81. }
  82. m_AchievementItem.Purge();
  83. for ( int i=0; i < GetMaxAchievementsShown(); i++ )
  84. {
  85. CAchievementTrackerItem *pNewItem = CreateAchievementPanel();
  86. pNewItem->SetAchievement( NULL );
  87. m_AchievementItem.AddToTail( pNewItem );
  88. }
  89. CHudElement::LevelInit();
  90. }
  91. //-----------------------------------------------------------------------------
  92. // Purpose:
  93. //-----------------------------------------------------------------------------
  94. void CHudBaseAchievementTracker::ApplySchemeSettings( IScheme *pScheme )
  95. {
  96. BaseClass::ApplySchemeSettings( pScheme );
  97. }
  98. //-----------------------------------------------------------------------------
  99. // Purpose:
  100. //-----------------------------------------------------------------------------
  101. bool CHudBaseAchievementTracker::ShouldDraw()
  102. {
  103. return CHudElement::ShouldDraw();
  104. }
  105. //-----------------------------------------------------------------------------
  106. // Purpose:
  107. //-----------------------------------------------------------------------------
  108. void CHudBaseAchievementTracker::OnThink()
  109. {
  110. if ( m_flNextThink < gpGlobals->curtime )
  111. {
  112. UpdateAchievementItems();
  113. m_flNextThink = gpGlobals->curtime + 0.1f;
  114. }
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Purpose: Max number of achievements shown on the HUD
  118. //-----------------------------------------------------------------------------
  119. int CHudBaseAchievementTracker::GetMaxAchievementsShown()
  120. {
  121. return hud_achievement_count.GetInt();
  122. }
  123. bool CHudBaseAchievementTracker::ShouldShowAchievement( IAchievement *pAchievement )
  124. {
  125. return ( hud_achievement_tracker.GetBool() && pAchievement && pAchievement->ShouldShowOnHUD() && !pAchievement->IsAchieved() );
  126. }
  127. CAchievementTrackerItem* CHudBaseAchievementTracker::CreateAchievementPanel()
  128. {
  129. return new CAchievementTrackerItem( this, "HudAchievementTrackerItem" );
  130. }
  131. //-----------------------------------------------------------------------------
  132. // Purpose: create panels for each achievement the player wants shown on the HUD and assign achievements to each one
  133. //-----------------------------------------------------------------------------
  134. void CHudBaseAchievementTracker::UpdateAchievementItems()
  135. {
  136. IAchievementMgr *pAchievementMgr = engine->GetAchievementMgr();
  137. if ( !pAchievementMgr )
  138. return;
  139. // $FIXME(hpe): needs split screen support; use playerSlot 0 for now; should we be using m_AchievementItem slot?
  140. int playerSlot = 0;
  141. int iCount = pAchievementMgr->GetAchievementCount();
  142. int iShown = 0;
  143. for ( int i = 0; i < iCount; ++i )
  144. {
  145. IAchievement* pCur = pAchievementMgr->GetAchievementByIndex( i, playerSlot );
  146. if ( !ShouldShowAchievement( pCur) )
  147. {
  148. // don't remove achievements that are still glowing (typically a just completed achievement)
  149. if ( pCur && m_AchievementItem.Count() > iShown && m_AchievementItem[iShown]->GetAchievementID() == pCur->GetAchievementID()
  150. && m_AchievementItem[iShown]->GetGlow() > 0 )
  151. {
  152. iShown++;
  153. }
  154. continue;
  155. }
  156. if ( m_AchievementItem.Count() < iShown+1 )
  157. {
  158. CAchievementTrackerItem *pNewItem = CreateAchievementPanel();
  159. SETUP_PANEL( pNewItem );
  160. m_AchievementItem.AddToTail( pNewItem );
  161. }
  162. m_AchievementItem[iShown]->SetAchievement( pCur );
  163. m_AchievementItem[iShown]->SetSlot( iShown );
  164. m_AchievementItem[iShown]->SetVisible( true );
  165. iShown++;
  166. if ( iShown >= GetMaxAchievementsShown() )
  167. break;
  168. }
  169. // hide any extra panels we may have created from when the list was longer
  170. if ( iShown < m_AchievementItem.Count() )
  171. {
  172. for ( int i = m_AchievementItem.Count() - 1; i >= iShown ; i-- )
  173. {
  174. m_AchievementItem[i]->SetVisible( false );
  175. m_AchievementItem[i]->SetAchievement( NULL );
  176. }
  177. }
  178. }
  179. //-----------------------------------------------------------------------------
  180. // Purpose: Layout all child panels vertically
  181. //-----------------------------------------------------------------------------
  182. void CHudBaseAchievementTracker::PerformLayout()
  183. {
  184. // make sure all children are laid out first
  185. for ( int i=0; i < m_AchievementItem.Count(); i++ )
  186. {
  187. m_AchievementItem[i]->InvalidateLayout( true );
  188. }
  189. int iCurrentY = 0;
  190. int x, y;
  191. for ( int i=0; i< m_AchievementItem.Count(); i++ )
  192. {
  193. m_AchievementItem[i]->GetPos( x, y );
  194. m_AchievementItem[i]->SetPos( x, iCurrentY );
  195. iCurrentY += m_AchievementItem[i]->GetTall() + m_iItemPadding;
  196. }
  197. }
  198. CAchievementTrackerItem* CHudBaseAchievementTracker::GetAchievementPanel( int i )
  199. {
  200. if ( i < 0 || i >= m_AchievementItem.Count() )
  201. return NULL;
  202. return m_AchievementItem[i];
  203. }
  204. //-----------------------------------------------------------------------------
  205. // Purpose: The child panels
  206. //-----------------------------------------------------------------------------
  207. CAchievementTrackerItem::CAchievementTrackerItem( vgui::Panel* pParent, const char *pElementName ) :
  208. BaseClass( pParent, pElementName )
  209. {
  210. m_pAchievementNameGlow = new vgui::Label( this, "AchievementNameGlow", "" );
  211. m_pAchievementName = new vgui::Label( this, "AchievementName", "" );
  212. m_pAchievementDesc = new vgui::Label( this, "AchievementDesc", "" );
  213. m_pProgressBarBackground = SETUP_PANEL( new ImagePanel( this, "ProgressBarBG" ) );
  214. m_pProgressBar = SETUP_PANEL( new ImagePanel( this, "ProgressBar" ) );
  215. m_iAchievementID = UNKNOWN_ACHIEVEMENT_ID;
  216. m_iLastPaintedAchievementID = UNKNOWN_ACHIEVEMENT_ID;
  217. m_iAccumulatedIncrement = 0;
  218. m_flShowIncrementsTime = 0;
  219. m_iLastCount = 0;
  220. m_iPadding = 1;
  221. }
  222. CAchievementTrackerItem::~CAchievementTrackerItem()
  223. {
  224. delete m_pAchievementName;
  225. delete m_pAchievementNameGlow;
  226. delete m_pAchievementDesc;
  227. delete m_pProgressBarBackground;
  228. delete m_pProgressBar;
  229. }
  230. //-----------------------------------------------------------------------------
  231. // Purpose:
  232. //-----------------------------------------------------------------------------
  233. void CAchievementTrackerItem::ApplySchemeSettings( IScheme *pScheme )
  234. {
  235. BaseClass::ApplySchemeSettings( pScheme );
  236. LoadControlSettings( "resource/UI/HudAchievementTrackerItem.res" );
  237. m_pAchievementDesc->SetVisible( hud_achievement_description.GetBool() );
  238. m_iLastPaintedAchievementID = UNKNOWN_ACHIEVEMENT_ID;
  239. }
  240. //-----------------------------------------------------------------------------
  241. // Purpose:
  242. //-----------------------------------------------------------------------------
  243. void CAchievementTrackerItem::PerformLayout()
  244. {
  245. BaseClass::PerformLayout();
  246. int x, y, w, t;
  247. m_pAchievementName->GetContentSize( w, t ); // needed in order to load up font for the name
  248. m_pAchievementNameGlow->GetContentSize( w, t ); // needed in order to load up font for the glow
  249. if ( hud_achievement_description.GetBool() )
  250. {
  251. m_pAchievementDesc->GetContentSize( w, t );
  252. m_pAchievementDesc->SetTall( t );
  253. m_pAchievementDesc->GetBounds( x, y, w, t );
  254. }
  255. else
  256. {
  257. m_pAchievementName->GetBounds( x, y, w, t );
  258. }
  259. if ( m_pProgressBarBackground->IsVisible() )
  260. {
  261. // put progress bar after description
  262. int bx, by;
  263. m_pProgressBarBackground->GetPos( bx, by );
  264. m_pProgressBarBackground->SetPos( bx, y + t + m_iPadding );
  265. SetTall( y + t + m_pProgressBarBackground->GetTall() + m_iPadding * 2 );
  266. }
  267. else
  268. {
  269. SetTall( y + t + m_iPadding );
  270. }
  271. m_iLastProgressBarCount = m_iLastProgressBarGoal = PROGRESS_BAR_NEEDS_UPDATE;
  272. }
  273. //-----------------------------------------------------------------------------
  274. // Purpose:
  275. //-----------------------------------------------------------------------------
  276. void CAchievementTrackerItem::SetAchievement( IAchievement* pAchievement )
  277. {
  278. if ( !pAchievement )
  279. {
  280. m_iAchievementID = UNKNOWN_ACHIEVEMENT_ID;
  281. m_iLastCount = 0;
  282. return;
  283. }
  284. if ( m_iAchievementID != pAchievement->GetAchievementID() )
  285. {
  286. m_iAchievementID = pAchievement->GetAchievementID();
  287. m_iLastCount = pAchievement->GetCount();
  288. UpdateAchievementDisplay();
  289. }
  290. }
  291. void CAchievementTrackerItem::OnThink()
  292. {
  293. UpdateAchievementDisplay();
  294. }
  295. //-----------------------------------------------------------------------------
  296. // Purpose: Make sure our labels and progress bar are up to date
  297. //-----------------------------------------------------------------------------
  298. void CAchievementTrackerItem::UpdateAchievementDisplay()
  299. {
  300. IAchievementMgr *pAchievementMgr = engine->GetAchievementMgr();
  301. if ( !pAchievementMgr )
  302. return;
  303. // $FIXME(hpe): needs split screen support; use playerslot 0 for now
  304. int playerSlot = 0;
  305. CBaseAchievement* pAchievement = pAchievementMgr->GetAchievementByID( m_iAchievementID, playerSlot );
  306. if ( !pAchievement )
  307. return;
  308. if ( m_iAchievementID != m_iLastPaintedAchievementID )
  309. {
  310. // need to update labels
  311. m_pAchievementName->SetText( ACHIEVEMENT_LOCALIZED_NAME( pAchievement ) );
  312. m_pAchievementNameGlow->SetText( ACHIEVEMENT_LOCALIZED_NAME( pAchievement ) );
  313. m_pAchievementDesc->SetText( ACHIEVEMENT_LOCALIZED_DESC( pAchievement ) );
  314. m_pProgressBarBackground->SetVisible( pAchievement->GetGoal() > 1 );
  315. m_pProgressBar->SetVisible( pAchievement->GetGoal() > 1 );
  316. m_iLastPaintedAchievementID = m_iAchievementID;
  317. m_flGlow = 0.0f;
  318. m_flGlowTime = 0.0f;
  319. m_iAccumulatedIncrement = 0;
  320. //InvalidateLayout( true );
  321. GetParent()->InvalidateLayout( true );
  322. }
  323. if ( m_iAccumulatedIncrement > 0 && gpGlobals->curtime > m_flShowIncrementsTime )
  324. {
  325. ShowAccumulatedIncrements();
  326. }
  327. if ( pAchievement->GetCount() != m_iLastProgressBarCount || pAchievement->GetGoal() != m_iLastProgressBarGoal )
  328. {
  329. // need to update progress bar
  330. float flProgress = float ( pAchievement->GetCount() ) / float( pAchievement->GetGoal() );
  331. int x, y, w, t;
  332. m_pProgressBarBackground->GetBounds( x, y, w, t );
  333. m_pProgressBar->SetBounds( x, y, w * flProgress, t );
  334. m_iLastProgressBarCount = pAchievement->GetCount();
  335. m_iLastProgressBarGoal = pAchievement->GetGoal();
  336. AchievementIncremented( pAchievement->GetCount() );
  337. }
  338. if ( gpGlobals->curtime < m_flGlowTime )
  339. {
  340. m_flGlow = MIN( 1.0f, m_flGlow + gpGlobals->frametime * 5.0f );
  341. }
  342. else
  343. {
  344. m_flGlow = MAX( 0.0f, m_flGlow - gpGlobals->frametime * 5.0f );
  345. }
  346. m_pAchievementNameGlow->SetAlpha( m_flGlow * 255.0f );
  347. }
  348. //-----------------------------------------------------------------------------
  349. // Purpose: Achievement count has gone up, make it flash
  350. //-----------------------------------------------------------------------------
  351. void CAchievementTrackerItem::AchievementIncremented( int iNewCount )
  352. {
  353. int iIncrement = iNewCount - m_iLastCount;
  354. m_iLastCount = iNewCount;
  355. if ( iIncrement <= 0 )
  356. return;
  357. if ( m_iLastProgressBarGoal > 1500 )
  358. {
  359. // for achievements with very high counts, accumulate increments so we don't have too many +1s on screen
  360. // also don't play sounds as these achievements tend to increment constantly
  361. if ( m_flShowIncrementsTime < gpGlobals->curtime )
  362. {
  363. m_flShowIncrementsTime = gpGlobals->curtime + 2.0f;
  364. }
  365. m_iAccumulatedIncrement += iIncrement;
  366. }
  367. else
  368. {
  369. m_flGlowTime = gpGlobals->curtime + hud_achievement_glowtime.GetFloat();
  370. // create a floating +X to scroll up alongside this achievement
  371. if ( m_pProgressBarBackground->IsVisible() )
  372. {
  373. int px, py;
  374. GetPos( px, py );
  375. int x, y, w, t;
  376. m_pProgressBarBackground->GetBounds( x, y, w, t );
  377. x += w;
  378. new CFloatingAchievementNumber( iIncrement, px + x, py + y + ( t * 0.5f ), FN_DIR_RIGHT, GetParent() );
  379. }
  380. CLocalPlayerFilter filter;
  381. C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "Hud.AchievementIncremented" );
  382. }
  383. }
  384. //-----------------------------------------------------------------------------
  385. // Purpose: Show all the increments we've accumulated
  386. //-----------------------------------------------------------------------------
  387. void CAchievementTrackerItem::ShowAccumulatedIncrements()
  388. {
  389. int px, py;
  390. GetPos( px, py );
  391. int x, y, w, t;
  392. m_pProgressBarBackground->GetBounds( x, y, w, t );
  393. x += w;
  394. new CFloatingAchievementNumber( m_iAccumulatedIncrement, px + x, py + y + ( t * 0.5f ), FN_DIR_RIGHT, GetParent() );
  395. m_iAccumulatedIncrement = 0;
  396. m_flGlowTime = gpGlobals->curtime + hud_achievement_glowtime.GetFloat();
  397. }
  398. //-----------------------------------------------------------------------------
  399. // Purpose: Floating numbers showing how much achievement progress bars have gone up
  400. //-----------------------------------------------------------------------------
  401. CFloatingAchievementNumber::CFloatingAchievementNumber( int iProgress, int x, int y, floating_number_directions iDir, vgui::Panel* pParent )
  402. : BaseClass( pParent, "FloatingAchievementNumber" )
  403. {
  404. m_iStartX = x;
  405. m_iStartY = y;
  406. m_iProgress = iProgress;
  407. m_fStartTime = gpGlobals->curtime;
  408. m_iDirection = iDir;
  409. char szLabel[64];
  410. Q_snprintf( szLabel, sizeof( szLabel ), "+%d", iProgress );
  411. m_pNumberLabel = new vgui::Label( this, "FloatingNumberLabel", szLabel );
  412. }
  413. CFloatingAchievementNumber::~CFloatingAchievementNumber()
  414. {
  415. delete m_pNumberLabel;
  416. }
  417. void CFloatingAchievementNumber::ApplySchemeSettings( vgui::IScheme *scheme )
  418. {
  419. BaseClass::ApplySchemeSettings( scheme );
  420. LoadControlSettings( "resource/UI/HudAchievementFloatingNumber.res" );
  421. int fontHeight = surface()->GetFontTall( m_pNumberLabel->GetFont() );
  422. SetPos( m_iStartX, m_iStartY - ( fontHeight * 0.5f ) );
  423. m_pNumberLabel->SetAlpha( 0 );
  424. GetAnimationController()->RunAnimationCommand( m_pNumberLabel, "alpha", 255, 0, 0.3, vgui::AnimationController::INTERPOLATOR_LINEAR );
  425. switch ( m_iDirection )
  426. {
  427. default:
  428. case FN_DIR_UP:
  429. vgui::GetAnimationController()->RunAnimationCommand( this, "ypos", m_iStartY - m_iScrollDistance, 0, 2.0f, vgui::AnimationController::INTERPOLATOR_LINEAR );
  430. break;
  431. case FN_DIR_DOWN:
  432. vgui::GetAnimationController()->RunAnimationCommand( this, "ypos", m_iStartY + m_iScrollDistance, 0, 2.0f, vgui::AnimationController::INTERPOLATOR_LINEAR );
  433. break;
  434. case FN_DIR_LEFT:
  435. vgui::GetAnimationController()->RunAnimationCommand( this, "xpos", m_iStartX - m_iScrollDistance, 0, 2.0f, vgui::AnimationController::INTERPOLATOR_LINEAR );
  436. break;
  437. case FN_DIR_RIGHT:
  438. vgui::GetAnimationController()->RunAnimationCommand( this, "xpos", m_iStartX + m_iScrollDistance, 0, 2.0f, vgui::AnimationController::INTERPOLATOR_LINEAR );
  439. break;
  440. }
  441. }
  442. //-----------------------------------------------------------------------------
  443. // Purpose: Delete panel when floating number has faded out
  444. //-----------------------------------------------------------------------------
  445. void CFloatingAchievementNumber::OnThink()
  446. {
  447. if ( gpGlobals->curtime > m_fStartTime + 1.0f )
  448. {
  449. if ( m_pNumberLabel->GetAlpha() >= 255 )
  450. {
  451. m_pNumberLabel->SetAlpha( 254 );
  452. GetAnimationController()->RunAnimationCommand( m_pNumberLabel, "alpha", 0, 0.0, 1.0f, vgui::AnimationController::INTERPOLATOR_LINEAR );
  453. }
  454. else if ( m_pNumberLabel->GetAlpha() <= 0 )
  455. {
  456. MarkForDeletion();
  457. SetVisible( false );
  458. }
  459. }
  460. }
  461. //-----------------------------------------------------------------------------
  462. // Purpose: Debug command to make one of the achievement panels flash as though it just went up
  463. //-----------------------------------------------------------------------------
  464. class CHudAchievementTracker;
  465. void cc_TrackerAnim_f( const CCommand &args )
  466. {
  467. CHudBaseAchievementTracker *pTracker = ( CHudBaseAchievementTracker * )GET_HUDELEMENT( CHudAchievementTracker );
  468. if ( !pTracker )
  469. return;
  470. CAchievementTrackerItem *pItem = pTracker->GetAchievementPanel( atoi(args[1]) );
  471. if ( !pItem )
  472. return;
  473. pItem->AchievementIncremented( pItem->GetLastCount() + RandomInt(1, 1) );
  474. }
  475. ConCommand cc_TrackerAnim( "TrackerAnim", cc_TrackerAnim_f, "Test animation of the achievement tracker. Parameter is achievement number on HUD to flash", FCVAR_NONE );