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.

278 lines
9.9 KiB

  1. //========= Copyright � 1996-2002, Valve LLC, All rights reserved. ============
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================
  7. #include "cbase.h"
  8. #include "hud.h"
  9. #include "hud_macros.h"
  10. #include "hudelement.h"
  11. #include "iclientmode.h"
  12. #include "ienginevgui.h"
  13. #include <vgui/ILocalize.h>
  14. #include <vgui/ISurface.h>
  15. #include <vgui/IVGUI.h>
  16. #include <vgui_controls/EditablePanel.h>
  17. #include <vgui_controls/Label.h>
  18. #include <vgui_controls/ImagePanel.h>
  19. #include "achievement_notification_panel.h"
  20. #ifndef NO_STEAM
  21. #include "steam/steam_api.h"
  22. #endif
  23. #include "iachievementmgr.h"
  24. #include "fmtstr.h"
  25. // memdbgon must be the last include file in a .cpp file!!!
  26. #include "tier0/memdbgon.h"
  27. using namespace vgui;
  28. #define ACHIEVEMENT_NOTIFICATION_DURATION 10.0f
  29. //-----------------------------------------------------------------------------
  30. // Purpose:
  31. //-----------------------------------------------------------------------------
  32. DECLARE_HUDELEMENT_DEPTH( CAchievementNotificationPanel, 100 );
  33. //-----------------------------------------------------------------------------
  34. // Purpose:
  35. //-----------------------------------------------------------------------------
  36. CAchievementNotificationPanel::CAchievementNotificationPanel( const char *pElementName ) : CHudElement( pElementName ), BaseClass( NULL, "AchievementNotificationPanel" )
  37. {
  38. Panel *pParent = GetClientMode()->GetViewport();
  39. SetParent( pParent );
  40. SetScheme( "basemodui_scheme" );
  41. m_flHideTime = 0;
  42. m_pPanelBackground = new EditablePanel( this, "Notification_Background" );
  43. m_pIcon = new ImagePanel( this, "Notification_Icon" );
  44. m_pLabelHeading = new Label( this, "HeadingLabel", "" );
  45. m_pLabelTitle = new Label( this, "TitleLabel", "" );
  46. m_pIcon->SetShouldScaleImage( true );
  47. vgui::ivgui()->AddTickSignal( GetVPanel() );
  48. }
  49. //-----------------------------------------------------------------------------
  50. // Purpose:
  51. //-----------------------------------------------------------------------------
  52. void CAchievementNotificationPanel::Init()
  53. {
  54. ListenForGameEvent( "achievement_event" );
  55. }
  56. //-----------------------------------------------------------------------------
  57. // Purpose:
  58. //-----------------------------------------------------------------------------
  59. void CAchievementNotificationPanel::ApplySchemeSettings( IScheme *pScheme )
  60. {
  61. // load control settings...
  62. LoadControlSettings( "resource/UI/AchievementNotification.res" );
  63. BaseClass::ApplySchemeSettings( pScheme );
  64. }
  65. //-----------------------------------------------------------------------------
  66. // Purpose:
  67. //-----------------------------------------------------------------------------
  68. void CAchievementNotificationPanel::PerformLayout( void )
  69. {
  70. BaseClass::PerformLayout();
  71. // Set background color of various elements. Need to do this in code, if we do it in res file it gets slammed by the
  72. // scheme. (Incl. label background: some products don't have label background colors set in their scheme and helpfully slam it to white.)
  73. SetBgColor( Color( 0, 0, 0, 0 ) );
  74. m_pLabelHeading->SetBgColor( Color( 0, 0, 0, 0 ) );
  75. m_pLabelTitle->SetBgColor( Color( 0, 0, 0, 0 ) );
  76. m_pPanelBackground->SetBgColor( Color( 62,70,55, 200 ) );
  77. }
  78. //-----------------------------------------------------------------------------
  79. // Purpose:
  80. //-----------------------------------------------------------------------------
  81. void CAchievementNotificationPanel::FireGameEvent( IGameEvent * event )
  82. {
  83. const char *name = event->GetName();
  84. if ( 0 == Q_strcmp( name, "achievement_event" ) )
  85. {
  86. const char *pchName = event->GetString( "achievement_name" );
  87. int iCur = event->GetInt( "cur_val" );
  88. int iMax = event->GetInt( "max_val" );
  89. wchar_t szLocalizedName[256]=L"";
  90. #ifndef NO_STEAM
  91. if ( IsPC() )
  92. {
  93. // shouldn't ever get achievement progress if steam not running and user logged in, but check just in case
  94. if ( !steamapicontext->SteamUserStats() )
  95. {
  96. Msg( "Steam not running, achievement progress notification not displayed\n" );
  97. }
  98. else
  99. {
  100. // use Steam to show achievement progress UI
  101. steamapicontext->SteamUserStats()->IndicateAchievementProgress( pchName, iCur, iMax );
  102. }
  103. }
  104. else
  105. #endif
  106. {
  107. // on X360 we need to show our own achievement progress UI
  108. const wchar_t *pchLocalizedName = ACHIEVEMENT_LOCALIZED_NAME_FROM_STR( pchName );
  109. Assert( pchLocalizedName );
  110. if ( !pchLocalizedName || !pchLocalizedName[0] )
  111. return;
  112. Q_wcsncpy( szLocalizedName, pchLocalizedName, sizeof( szLocalizedName ) );
  113. // this is achievement progress, compose the message of form: "<name> (<#>/<max>)"
  114. wchar_t szFmt[128]=L"";
  115. wchar_t szText[512]=L"";
  116. wchar_t szNumFound[16]=L"";
  117. wchar_t szNumTotal[16]=L"";
  118. Q_snwprintf( szNumFound, ARRAYSIZE( szNumFound ), L"%i", iCur );
  119. Q_snwprintf( szNumTotal, ARRAYSIZE( szNumTotal ), L"%i", iMax );
  120. const wchar_t *pchFmt = g_pVGuiLocalize->Find( "#GameUI_Achievement_Progress_Fmt" );
  121. if ( !pchFmt || !pchFmt[0] )
  122. return;
  123. Q_wcsncpy( szFmt, pchFmt, sizeof( szFmt ) );
  124. g_pVGuiLocalize->ConstructString( szText, sizeof( szText ), szFmt, 3, szLocalizedName, szNumFound, szNumTotal );
  125. AddNotification( pchName, g_pVGuiLocalize->FindSafe( "#GameUI_Achievement_Progress" ), szText );
  126. }
  127. }
  128. }
  129. //-----------------------------------------------------------------------------
  130. // Purpose: Called on each tick
  131. //-----------------------------------------------------------------------------
  132. void CAchievementNotificationPanel::OnTick( void )
  133. {
  134. if ( ( m_flHideTime > 0 ) && ( m_flHideTime < gpGlobals->curtime ) )
  135. {
  136. m_flHideTime = 0;
  137. ShowNextNotification();
  138. }
  139. }
  140. //-----------------------------------------------------------------------------
  141. // Purpose:
  142. //-----------------------------------------------------------------------------
  143. bool CAchievementNotificationPanel::ShouldDraw( void )
  144. {
  145. return ( ( m_flHideTime > 0 ) && ( m_flHideTime > gpGlobals->curtime ) && CHudElement::ShouldDraw() );
  146. }
  147. //-----------------------------------------------------------------------------
  148. // Purpose:
  149. //-----------------------------------------------------------------------------
  150. void CAchievementNotificationPanel::AddNotification( const char *szIconBaseName, const wchar_t *pHeading, const wchar_t *pTitle )
  151. {
  152. // put this notification in our queue
  153. int iQueueItem = m_queueNotification.AddToTail();
  154. Notification_t &notification = m_queueNotification[iQueueItem];
  155. Q_strncpy( notification.szIconBaseName, szIconBaseName, ARRAYSIZE( notification.szIconBaseName ) );
  156. Q_wcsncpy( notification.szHeading, pHeading, sizeof( notification.szHeading ) );
  157. Q_wcsncpy( notification.szTitle, pTitle, sizeof( notification.szTitle ) );
  158. // if we are not currently displaying a notification, go ahead and show this one
  159. if ( 0 == m_flHideTime )
  160. {
  161. ShowNextNotification();
  162. }
  163. }
  164. //-----------------------------------------------------------------------------
  165. // Purpose: Shows next notification in queue if there is one
  166. //-----------------------------------------------------------------------------
  167. void CAchievementNotificationPanel::ShowNextNotification()
  168. {
  169. // see if we have anything to do
  170. if ( 0 == m_queueNotification.Count() )
  171. {
  172. m_flHideTime = 0;
  173. return;
  174. }
  175. Notification_t &notification = m_queueNotification[ m_queueNotification.Head() ];
  176. m_flHideTime = gpGlobals->curtime + ACHIEVEMENT_NOTIFICATION_DURATION;
  177. // set the text and icon in the dialog
  178. SetDialogVariable( "heading", notification.szHeading );
  179. SetDialogVariable( "title", notification.szTitle );
  180. const char *pchIconBaseName = notification.szIconBaseName;
  181. if ( pchIconBaseName && pchIconBaseName[0] )
  182. {
  183. m_pIcon->SetImage( CFmtStr( "achievements/%s.vmt", pchIconBaseName ) );
  184. }
  185. // resize the panel so it always looks good
  186. // get fonts
  187. HFont hFontHeading = m_pLabelHeading->GetFont();
  188. HFont hFontTitle = m_pLabelTitle->GetFont();
  189. // determine how wide the text strings are
  190. int iHeadingWidth = UTIL_ComputeStringWidth( hFontHeading, notification.szHeading );
  191. int iTitleWidth = UTIL_ComputeStringWidth( hFontTitle, notification.szTitle );
  192. // use the widest string
  193. int iTextWidth = MAX( iHeadingWidth, iTitleWidth );
  194. // don't let it be insanely wide
  195. iTextWidth = MIN( iTextWidth, XRES( 300 ) );
  196. int iIconWidth = m_pIcon->GetWide();
  197. int iSpacing = XRES( 10 );
  198. int iPanelWidth = iSpacing + iIconWidth + iSpacing + iTextWidth + iSpacing;
  199. int iPanelX = GetWide() - iPanelWidth;
  200. int iIconX = iPanelX + iSpacing;
  201. int iTextX = iIconX + iIconWidth + iSpacing;
  202. // resize all the elements
  203. SetXAndWide( m_pPanelBackground, iPanelX, iPanelWidth );
  204. SetXAndWide( m_pIcon, iIconX, iIconWidth );
  205. SetXAndWide( m_pLabelHeading, iTextX, iTextWidth );
  206. SetXAndWide( m_pLabelTitle, iTextX, iTextWidth );
  207. m_queueNotification.Remove( m_queueNotification.Head() );
  208. }
  209. //-----------------------------------------------------------------------------
  210. // Purpose:
  211. //-----------------------------------------------------------------------------
  212. void CAchievementNotificationPanel::SetXAndWide( Panel *pPanel, int x, int wide )
  213. {
  214. int xCur, yCur;
  215. pPanel->GetPos( xCur, yCur );
  216. pPanel->SetPos( x, yCur );
  217. pPanel->SetWide( wide );
  218. }
  219. CON_COMMAND_F( achievement_notification_test, "Test the hud notification UI", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY )
  220. {
  221. static int iCount=0;
  222. CAchievementNotificationPanel *pPanel = GET_HUDELEMENT( CAchievementNotificationPanel );
  223. if ( pPanel )
  224. {
  225. pPanel->AddNotification( "HL2_KILL_ODESSAGUNSHIP", L"Achievement Progress", ( 0 == ( iCount % 2 ) ? L"Test Notification Message A (1/10)" :
  226. L"Test Message B" ) );
  227. }
  228. #if 0
  229. IGameEvent *event = gameeventmanager->CreateEvent( "achievement_event" );
  230. if ( event )
  231. {
  232. const char *szTestStr[] = { "TF_GET_HEADSHOTS", "TF_PLAY_GAME_EVERYMAP", "TF_PLAY_GAME_EVERYCLASS", "TF_GET_HEALPOINTS" };
  233. event->SetString( "achievement_name", szTestStr[iCount%ARRAYSIZE(szTestStr)] );
  234. event->SetInt( "cur_val", ( iCount%9 ) + 1 );
  235. event->SetInt( "max_val", 10 );
  236. gameeventmanager->FireEvent( event );
  237. }
  238. #endif
  239. iCount++;
  240. }