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.

434 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include <vgui_controls/EditablePanel.h>
  9. #include <game/client/iviewport.h>
  10. #include <vgui/IScheme.h>
  11. #include "hud.h"
  12. #include "hudelement.h"
  13. #include "tf_hud_statpanel.h"
  14. #include "tf_spectatorgui.h"
  15. #include "vgui_controls/AnimationController.h"
  16. #include "iclientmode.h"
  17. #include "engine/IEngineSound.h"
  18. #include "c_tf_playerresource.h"
  19. #include "c_team.h"
  20. #include "tf_clientscoreboard.h"
  21. #include <vgui_controls/Label.h>
  22. #include <vgui_controls/ImagePanel.h>
  23. #include <vgui/ILocalize.h>
  24. #include <vgui/ISurface.h>
  25. #include "vgui/IInput.h"
  26. #include "vgui_avatarimage.h"
  27. #include "fmtstr.h"
  28. #include "teamplayroundbased_gamerules.h"
  29. #include "tf_gamerules.h"
  30. #include "tf_hud_training.h"
  31. #include "tf_hud_mainmenuoverride.h"
  32. #include "achievementmgr.h"
  33. // memdbgon must be the last include file in a .cpp file!!!
  34. #include "tier0/memdbgon.h"
  35. using namespace vgui;
  36. static const int TEMP_STRING_SIZE = 256;
  37. static const float UPDATE_DELAY = 0.1f;
  38. static const float DELAY_TO_SHOW_BUTTONS = 5.0f;
  39. extern CAchievementMgr g_AchievementMgrTF; // global achievement mgr for TF
  40. class CTFTrainingComplete : public EditablePanel, public CHudElement
  41. {
  42. private:
  43. DECLARE_CLASS_SIMPLE( CTFTrainingComplete, EditablePanel );
  44. public:
  45. CTFTrainingComplete( const char *pElementName );
  46. virtual void Reset();
  47. virtual void Init();
  48. virtual void PerformLayout();
  49. virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
  50. virtual void ApplySettings( KeyValues *inResourceData );
  51. virtual void FireGameEvent( IGameEvent * event );
  52. virtual void OnThink();
  53. virtual bool ShouldDraw( void );
  54. virtual void SetVisible( bool value );
  55. virtual int GetRenderGroupPriority() { return 70; }
  56. protected:
  57. // vgui overrides
  58. virtual void OnCommand( const char *command );
  59. private:
  60. void SetUpResults( IGameEvent * event );
  61. CExButton *m_pReplay;
  62. CExButton *m_pNext;
  63. CExButton *m_pQuit;
  64. ImagePanel *m_pTopBar;
  65. ImagePanel *m_pBottomBar;
  66. EditablePanel *m_ResultsPanel;
  67. int m_iReplayY;
  68. int m_iNextY;
  69. int m_iBottomBarY;
  70. int m_iTopBarY;
  71. bool m_bShouldBeVisible;
  72. float m_showButtonsTime;
  73. };
  74. DECLARE_HUDELEMENT_DEPTH( CTFTrainingComplete, 1 );
  75. //-----------------------------------------------------------------------------
  76. // Purpose: Constructor
  77. //-----------------------------------------------------------------------------
  78. CTFTrainingComplete::CTFTrainingComplete( const char *pElementName ) : EditablePanel( NULL, "TrainingComplete" ), CHudElement( pElementName )
  79. {
  80. vgui::Panel *pParent = g_pClientMode->GetViewport();
  81. SetParent( pParent );
  82. m_bShouldBeVisible = false;
  83. m_showButtonsTime = 0.0f;
  84. m_ResultsPanel = NULL;
  85. m_pReplay = NULL;
  86. m_pNext = NULL;
  87. m_pQuit = NULL;
  88. m_pTopBar = NULL;
  89. m_pBottomBar = NULL;
  90. m_iReplayY = 0;
  91. m_iNextY = 0;
  92. m_iBottomBarY = 0;
  93. m_iTopBarY = 0;
  94. SetScheme( "ClientScheme" );
  95. MakePopup();
  96. RegisterForRenderGroup( "mid" );
  97. }
  98. void CTFTrainingComplete::SetUpResults( IGameEvent *event )
  99. {
  100. m_ResultsPanel = dynamic_cast<EditablePanel *>( FindChildByName( "Results" ) );
  101. const char *map = event->GetString( "map" );
  102. const char *nextMap = event->GetString( "next_map" );
  103. const char *endText = event->GetString( "text" );
  104. bool bHasNextMap = Q_stricmp( nextMap, "" ) != 0;
  105. // title
  106. {
  107. wchar_t outputText[MAX_TRAINING_MSG_LENGTH];
  108. CTFHudTraining::FormatTrainingText(bHasNextMap ? "#TF_Training_Success" : "#TF_Training_Completed" , outputText);
  109. m_ResultsPanel->SetDialogVariable( "wintext", outputText);
  110. }
  111. // record that the player has completed training with the current class
  112. C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
  113. if ( pLocalPlayer && !V_stricmp(map, "tr_target" ) )
  114. {
  115. Training_MarkClassComplete( pLocalPlayer->GetPlayerClass()->GetClassIndex(), 1 );
  116. }
  117. else if ( !V_stricmp(map, "tr_dustbowl" ) )
  118. {
  119. Training_MarkClassComplete( TF_CLASS_SOLDIER, 2 );
  120. }
  121. else
  122. {
  123. Warning( "Completed a training that we don't recognize!?\n" );
  124. Assert( false );
  125. }
  126. // Set the text to show to the user
  127. CExRichText *pRichText = dynamic_cast<CExRichText *>(FindChildByName( "ResultsText", true ) );
  128. if ( pRichText )
  129. {
  130. wchar_t wsText_LastMap[MAX_TRAINING_MSG_LENGTH];
  131. wchar_t wsText_NextMap[MAX_TRAINING_MSG_LENGTH];
  132. #ifdef WIN32
  133. V_swprintf_safe( wsText_LastMap, L"%S", GetMapDisplayName( map ) );
  134. V_swprintf_safe( wsText_NextMap, L"%S", GetMapDisplayName( nextMap ) );
  135. #else
  136. // GetMapDisplayName returns char * which is %s, NOT %S, on Posix
  137. V_swprintf_safe( wsText_LastMap, L"%s", GetMapDisplayName( map ) );
  138. V_swprintf_safe( wsText_NextMap, L"%s", GetMapDisplayName( nextMap ) );
  139. #endif
  140. wchar_t wsResult[MAX_TRAINING_MSG_LENGTH];
  141. g_pVGuiLocalize->ConstructString_safe( wsResult, g_pVGuiLocalize->Find( endText ), 2, wsText_LastMap, wsText_NextMap );
  142. pRichText->SetText( wsResult );
  143. bHasNextMap = Q_stricmp( nextMap, "" ) != 0;
  144. m_pNext->SetVisible( bHasNextMap );
  145. m_pQuit->SetVisible( !bHasNextMap );
  146. }
  147. extern int Training_GetProgressCount();
  148. TFGameRules()->SetAllowTrainingAchievements( true );
  149. g_AchievementMgrTF.UpdateAchievement( ACHIEVEMENT_TF_COMPLETE_TRAINING, Training_GetProgressCount() );
  150. }
  151. //-----------------------------------------------------------------------------
  152. // Purpose:
  153. //-----------------------------------------------------------------------------
  154. void CTFTrainingComplete::ApplySettings( KeyValues *inResourceData )
  155. {
  156. BaseClass::ApplySettings( inResourceData );
  157. }
  158. //-----------------------------------------------------------------------------
  159. // Purpose:
  160. //-----------------------------------------------------------------------------
  161. void CTFTrainingComplete::Reset()
  162. {
  163. m_bShouldBeVisible = false;
  164. }
  165. //-----------------------------------------------------------------------------
  166. // Purpose:
  167. //-----------------------------------------------------------------------------
  168. void CTFTrainingComplete::Init()
  169. {
  170. // listen for events
  171. ListenForGameEvent( "training_complete" );
  172. ListenForGameEvent( "teamplay_round_start" );
  173. ListenForGameEvent( "teamplay_game_over" );
  174. ListenForGameEvent( "tf_game_over" );
  175. m_bShouldBeVisible = false;
  176. CHudElement::Init();
  177. }
  178. void CTFTrainingComplete::SetVisible( bool value )
  179. {
  180. if ( value == IsVisible() )
  181. return;
  182. if ( value )
  183. {
  184. RequestFocus();
  185. SetKeyBoardInputEnabled( true );
  186. SetMouseInputEnabled( true );
  187. HideLowerPriorityHudElementsInGroup( "mid" );
  188. }
  189. else
  190. {
  191. SetMouseInputEnabled( false );
  192. SetKeyBoardInputEnabled( false );
  193. UnhideLowerPriorityHudElementsInGroup( "mid" );
  194. }
  195. BaseClass::SetVisible( value );
  196. }
  197. //-----------------------------------------------------------------------------
  198. // Purpose:
  199. //-----------------------------------------------------------------------------
  200. void CTFTrainingComplete::FireGameEvent( IGameEvent * event )
  201. {
  202. const char *pEventName = event->GetName();
  203. if ( Q_strcmp( "teamplay_round_start", pEventName ) == 0 )
  204. {
  205. m_bShouldBeVisible = false;
  206. }
  207. else if ( Q_strcmp( "teamplay_game_over", pEventName ) == 0 )
  208. {
  209. m_bShouldBeVisible = false;
  210. }
  211. else if ( Q_strcmp( "tf_game_over", pEventName ) == 0 )
  212. {
  213. m_bShouldBeVisible = false;
  214. }
  215. else if ( Q_strcmp( "training_complete", pEventName ) == 0 )
  216. {
  217. if ( !g_PR )
  218. return;
  219. InvalidateLayout( false, true );
  220. // Prevent the game from continuing until they press a button.
  221. tf_training_client_message.SetValue( (int)TRAINING_CLIENT_MESSAGE_IN_SUMMARY_SCREEN );
  222. m_showButtonsTime = gpGlobals->curtime + DELAY_TO_SHOW_BUTTONS;
  223. m_bShouldBeVisible = true;
  224. SetUpResults( event );
  225. }
  226. }
  227. //-----------------------------------------------------------------------------
  228. // Purpose: Performs layout
  229. //-----------------------------------------------------------------------------
  230. void CTFTrainingComplete::PerformLayout()
  231. {
  232. if ( m_pTopBar == NULL || m_pBottomBar == NULL || m_pReplay == NULL || m_pNext == NULL )
  233. {
  234. return;
  235. }
  236. //Get the offsets
  237. int dummy;
  238. int offset = m_pBottomBar->GetTall();
  239. m_pReplay->GetPos( dummy, m_iReplayY );
  240. m_pReplay->SetPos( dummy, m_iReplayY + offset );
  241. m_pNext->GetPos( dummy, m_iNextY );
  242. m_pNext->SetPos( dummy, m_iNextY + offset );
  243. m_pQuit->GetPos( dummy, m_iNextY );
  244. m_pQuit->SetPos( dummy, m_iNextY + offset );
  245. m_pBottomBar->GetPos( dummy, m_iBottomBarY );
  246. m_pBottomBar->SetPos( dummy, m_iBottomBarY + offset );
  247. m_pTopBar->GetPos( dummy, m_iTopBarY );
  248. m_pTopBar->SetPos( dummy, m_iTopBarY - offset );
  249. }
  250. //-----------------------------------------------------------------------------
  251. // Purpose: Applies scheme settings
  252. //-----------------------------------------------------------------------------
  253. void CTFTrainingComplete::ApplySchemeSettings( vgui::IScheme *pScheme )
  254. {
  255. LoadControlSettings( "resource/UI/TrainingComplete.res" );
  256. m_pReplay = dynamic_cast<CExButton *>( FindChildByName( "Replay" ) );
  257. m_pNext = dynamic_cast<CExButton *>( FindChildByName( "Next" ) );
  258. m_pQuit = dynamic_cast<CExButton *>( FindChildByName( "Quit" ) );
  259. m_pTopBar = dynamic_cast<ImagePanel *>( FindChildByName( "TopBar" ) );
  260. m_pBottomBar = dynamic_cast<ImagePanel *>( FindChildByName( "BottomBar" ) );
  261. BaseClass::ApplySchemeSettings( pScheme );
  262. }
  263. //-----------------------------------------------------------------------------
  264. // Purpose: returns whether panel should be drawn
  265. //-----------------------------------------------------------------------------
  266. bool CTFTrainingComplete::ShouldDraw()
  267. {
  268. if ( !m_bShouldBeVisible )
  269. return false;
  270. return CHudElement::ShouldDraw();
  271. }
  272. //-----------------------------------------------------------------------------
  273. // Purpose: panel think method
  274. //-----------------------------------------------------------------------------
  275. void CTFTrainingComplete::OnThink()
  276. {
  277. if ( 0.0f != m_showButtonsTime )
  278. {
  279. if( gpGlobals->curtime > m_showButtonsTime)
  280. {
  281. //After a certain amount of time, show the menu nav buttons and hide the HUD.
  282. m_showButtonsTime = 0.0f;
  283. }
  284. }
  285. else
  286. {
  287. //The menu buttons are showing.
  288. //Always hide the health... this needs to be done every frame because a message from the server keeps resetting this.
  289. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  290. if ( pLocalPlayer )
  291. {
  292. pLocalPlayer->m_Local.m_iHideHUD |= HIDEHUD_HEALTH;
  293. }
  294. if ( 0 != m_iBottomBarY )
  295. {
  296. static const float BLEND_AMOUNT = 0.15f;
  297. static const float BLEND_CONST = BLEND_AMOUNT - 1.0f;
  298. int x, y;
  299. //Get the dy for the bottom bar. We'll use that for all the widgets since they're all traveling the same distance.
  300. m_pBottomBar->GetPos( x, y );
  301. int dy = m_iBottomBarY - y;
  302. // Note: y = m_iBottomBarY - dy. We use this to great advantage later to help keep the code cleaner.
  303. // if we have less than a pixel step, clamp us to the end.
  304. if ( abs(dy) < (int)( 1.0f / BLEND_AMOUNT ) )
  305. {
  306. dy = 0;
  307. }
  308. m_pBottomBar->SetPos( x, m_iBottomBarY + (int)( BLEND_CONST * (float)dy ) );
  309. m_pNext->GetPos( x, y );
  310. m_pNext->SetPos( x, m_iNextY + (int)( BLEND_CONST * (float)dy ) );
  311. m_pQuit->GetPos( x, y );
  312. m_pQuit->SetPos( x, m_iNextY + (int)( BLEND_CONST * (float)dy ) );
  313. m_pReplay->GetPos( x, y );
  314. m_pReplay->SetPos( x, m_iReplayY + (int)( BLEND_CONST * (float)dy ) );
  315. m_pTopBar->GetPos( x, y );
  316. m_pTopBar->SetPos( x, m_iTopBarY - (int)( BLEND_CONST * (float)dy ) );
  317. if ( dy == 0 )
  318. {
  319. //Stop condition.
  320. m_iBottomBarY = 0;
  321. }
  322. }
  323. }
  324. }
  325. //-----------------------------------------------------------------------------
  326. // Purpose:
  327. //-----------------------------------------------------------------------------
  328. void CTFTrainingComplete::OnCommand( const char *command )
  329. {
  330. if ( !Q_strcmp( command, "next" ) )
  331. {
  332. tf_training_client_message.SetValue( (int)TRAINING_CLIENT_MESSAGE_NEXT_MAP );
  333. }
  334. else if ( !Q_strcmp( command, "replay" ) )
  335. {
  336. tf_training_client_message.SetValue( (int)TRAINING_CLIENT_MESSAGE_REPLAY );
  337. }
  338. else if ( !Q_strcmp( command, "quit" ) )
  339. {
  340. engine->ExecuteClientCmd( "disconnect\n" );
  341. IViewPortPanel *pMMOverride = ( gViewPortInterface->FindPanelByName( PANEL_MAINMENUOVERRIDE ) );
  342. if ( pMMOverride )
  343. {
  344. ((CHudMainMenuOverride*)pMMOverride)->ScheduleTrainingCheck( true );
  345. }
  346. }
  347. else
  348. {
  349. BaseClass::OnCommand( command );
  350. }
  351. }
  352. #if _DEBUG
  353. //@note Tom Bui: For testing...
  354. CON_COMMAND( training_complete, "Test")
  355. {
  356. IGameEvent *winEvent = gameeventmanager->CreateEvent( "training_complete" );
  357. if ( winEvent )
  358. {
  359. static bool sbTarget = true;
  360. winEvent->SetString( "map", "blah" );
  361. winEvent->SetString( "next_map", sbTarget ? "tr_dustbowl" : "" );
  362. winEvent->SetString( "text", sbTarget ? "#TR_Target_EndDialog" : "#TR_Dustbowl_EndDialog" );
  363. gameeventmanager->FireEvent( winEvent );
  364. }
  365. }
  366. #endif