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.

279 lines
8.6 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "tf_survey_questions.h"
  9. #include "ienginevgui.h"
  10. #include "tf_match_description.h"
  11. #ifdef CLIENT_DLL
  12. #include "tf_gc_client.h"
  13. #include "vgui_controls/RadioButton.h"
  14. #include "iclientmode.h"
  15. #include <vgui_controls/AnimationController.h>
  16. #include "game/client/iviewport.h"
  17. #include "tf_hud_mainmenuoverride.h"
  18. #include "tf_gamerules.h"
  19. #endif
  20. // memdbgon must be the last include file in a .cpp file!!!
  21. #include "tier0/memdbgon.h"
  22. //-----------------------------------------------------------------------------
  23. // Purpose: Criteria function for competitive inquiry survey
  24. // Only include casual matches
  25. //-----------------------------------------------------------------------------
  26. bool CompetitiveInquiry( const CMsgGC_Match_Result& msgMatchResult, uint32 nPlayerIndex )
  27. {
  28. const IMatchGroupDescription* pMatchDesc = GetMatchGroupDescription( (EMatchGroup) msgMatchResult.match_group() );
  29. if ( pMatchDesc )
  30. {
  31. // Only show this in Casual 12v12
  32. return pMatchDesc->m_eMatchGroup == k_nMatchGroup_Casual_12v12;
  33. }
  34. return false;
  35. }
  36. //-----------------------------------------------------------------------------
  37. // Purpose: Criteria function for casual inquiry survey
  38. // Only include competitive matches
  39. //-----------------------------------------------------------------------------
  40. bool CasualInquiry( const CMsgGC_Match_Result& msgMatchResult, uint32 nPlayerIndex )
  41. {
  42. const IMatchGroupDescription* pMatchDesc = GetMatchGroupDescription( ( EMatchGroup )msgMatchResult.match_group() );
  43. if ( pMatchDesc )
  44. {
  45. // Only show this in Competitive 6v6
  46. return pMatchDesc->m_eMatchGroup == k_nMatchGroup_Ladder_6v6;
  47. }
  48. return false;
  49. }
  50. //-----------------------------------------------------------------------------
  51. // Purpose: The actual definition of the survey questions
  52. //-----------------------------------------------------------------------------
  53. // Survey Enum Help Text String Weight Criteria Function Active
  54. const SurveyQuestion_t g_SurveyQuestions[SurveyQuestionType_ARRAYSIZE] = { { QUESTION_MATCH_QUALITY, "MatchQuality", 1.f, NULL, true },
  55. { QUESTION_MAP_QUALITY, "MapQuality", 1.f, NULL, true },
  56. { QUESTION_COMP_INQUIRY, "CompetitiveInquiry", 1.f, &CompetitiveInquiry, true },
  57. { QUESTION_CASUAL_INQUIRY, "CasualInquiry", 1.f, &CasualInquiry, true } };
  58. #ifdef CLIENT_DLL
  59. //-----------------------------------------------------------------------------
  60. // Purpose: Figure out which survey panel to make
  61. //-----------------------------------------------------------------------------
  62. CSurveyQuestionPanel* CreateSurveyQuestionPanel( Panel* pParent, const CMsgGCSurveyRequest& msgSurveyQuestion )
  63. {
  64. CSurveyQuestionPanel* pSurveyPanel = NULL;
  65. Assert( msgSurveyQuestion.has_question_type() );
  66. switch( msgSurveyQuestion.question_type() )
  67. {
  68. case QUESTION_MATCH_QUALITY:
  69. pSurveyPanel = new CMatchQualitySurvey( pParent, msgSurveyQuestion );
  70. break;
  71. case QUESTION_MAP_QUALITY:
  72. pSurveyPanel = new CMapQualitySurvey( pParent, msgSurveyQuestion );
  73. break;
  74. case QUESTION_COMP_INQUIRY:
  75. pSurveyPanel = new CCompInquirySurvey( pParent, msgSurveyQuestion );
  76. break;
  77. case QUESTION_CASUAL_INQUIRY:
  78. pSurveyPanel = new CCasualInquirySurvey( pParent, msgSurveyQuestion );
  79. break;
  80. default:
  81. Assert( !"Unhandled survey question type!" );
  82. }
  83. return pSurveyPanel;
  84. }
  85. CSurveyQuestionPanel::CSurveyQuestionPanel( Panel* pParent, CMsgGCSurveyRequest msgSurveyQuestion )
  86. : EditablePanel( pParent, "Survey" )
  87. , m_msgRequest( msgSurveyQuestion )
  88. , m_bResponded( false )
  89. {
  90. vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientScheme.res", "ClientScheme");
  91. SetScheme(scheme);
  92. SetProportional( true );
  93. ListenForGameEvent( "server_spawn" );
  94. ListenForGameEvent( "client_disconnect" );
  95. ListenForGameEvent( "client_beginconnect" );
  96. }
  97. CSurveyQuestionPanel::~CSurveyQuestionPanel()
  98. {
  99. if ( !m_bResponded )
  100. {
  101. GTFGCClientSystem()->SendSurveyResponse( SEEN_BUT_UNANSWERED_SURVEY_QUESTION );
  102. m_bResponded = true;
  103. }
  104. GTFGCClientSystem()->ClearSurveyRequest();
  105. }
  106. void CSurveyQuestionPanel::OnCommand( const char *command )
  107. {
  108. if ( FStrEq( command, "close" ) )
  109. {
  110. if ( !m_bResponded )
  111. {
  112. GTFGCClientSystem()->SendSurveyResponse( SEEN_AND_DISMISSED_SURVEY_QUESTION );
  113. m_bResponded = true;
  114. }
  115. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( GetParent(), "SurveyHideSequence", false );
  116. return;
  117. }
  118. else if ( FStrEq( command, "submit" ) )
  119. {
  120. if ( !m_bResponded )
  121. {
  122. Submit();
  123. m_bResponded = true;
  124. }
  125. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( GetParent(), "SurveySubmitSequence", false );
  126. return;
  127. }
  128. else if ( FStrEq( command, "delete" ) )
  129. {
  130. MarkForDeletion();
  131. return;
  132. }
  133. BaseClass::OnCommand( command );
  134. }
  135. void CSurveyQuestionPanel::ApplySchemeSettings( IScheme *pScheme )
  136. {
  137. BaseClass::ApplySchemeSettings( pScheme );
  138. SetProportional( true );
  139. LoadControlSettings( GetResFile() );
  140. InvalidateLayout( true );
  141. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( GetParent(), "SurveyShowSequence", false );
  142. }
  143. void CSurveyQuestionPanel::FireGameEvent( IGameEvent *event )
  144. {
  145. const char *pEventName = event->GetName();
  146. // They left/changed servers. Consider the survey abandoned
  147. if ( !Q_stricmp( pEventName, "client_disconnect" ) ||
  148. !Q_stricmp( pEventName, "client_beginconnect" ) ||
  149. !Q_stricmp( pEventName, "server_spawn" ) )
  150. {
  151. MarkForDeletion();
  152. }
  153. }
  154. CMultipleChoiceSurveyQuestionPanel::CMultipleChoiceSurveyQuestionPanel( Panel* pParent, CMsgGCSurveyRequest msgSurveyQuestion, uint16 nSurveyResponses )
  155. : CSurveyQuestionPanel( pParent, msgSurveyQuestion )
  156. {
  157. m_nSurveyResponses = nSurveyResponses;
  158. }
  159. //-----------------------------------------------------------------------------
  160. // Purpose: Get the labels under the radio buttons to highlight
  161. //-----------------------------------------------------------------------------
  162. void CMultipleChoiceSurveyQuestionPanel::Think()
  163. {
  164. // We need to be on top of absolutely everything. Clicking on another
  165. // popup will move it on top of us, and that cannot be!
  166. MoveToFront();
  167. bool bAnySelected = false;
  168. // Radio buttons aren't cool and can ONLY have their labels to the right.
  169. // This panel has extra labels under the radio labels that we want to highlight
  170. // so set the label's FG colors to the radio buttons FG colors.
  171. for( int i = 0; i < m_nSurveyResponses; ++i )
  172. {
  173. RadioButton* pRadioButton = FindControl< RadioButton >( CFmtStr( "Radio%d", i ), true );
  174. Panel* pRadioLabel = FindChildByName( CFmtStr( "Radio%dLabel", i ), true );
  175. if ( pRadioButton && pRadioLabel )
  176. {
  177. pRadioLabel->SetFgColor( pRadioButton->GetFgColor() );
  178. bAnySelected = bAnySelected || pRadioButton->IsSelected();
  179. }
  180. }
  181. Panel* pSubmitButton = FindChildByName( "SubmitButton", true );
  182. if ( pSubmitButton )
  183. {
  184. pSubmitButton->SetEnabled( bAnySelected );
  185. }
  186. }
  187. void CMultipleChoiceSurveyQuestionPanel::Submit()
  188. {
  189. // Figure out which radio button is checked, and use that as our response
  190. for( int i = 0; i < m_nSurveyResponses; ++i )
  191. {
  192. RadioButton* pRadioButton = FindControl< RadioButton >( CFmtStr( "Radio%d", i ), true );
  193. if ( pRadioButton && pRadioButton->IsSelected() )
  194. {
  195. GTFGCClientSystem()->SendSurveyResponse( i );
  196. return;
  197. }
  198. }
  199. }
  200. void CMapQualitySurvey::PerformLayout()
  201. {
  202. const MapDef_t* pMapDef = NULL;
  203. if ( TFGameRules() )
  204. {
  205. pMapDef = GetItemSchema()->GetMasterMapDefByName ( TFGameRules()->MapName() );
  206. }
  207. else
  208. {
  209. pMapDef = GetItemSchema()->GetMasterMapDefByIndex( RandomInt( 1, GetItemSchema()->GetMapCount() - 1 ) );
  210. }
  211. Assert( pMapDef );
  212. if ( !pMapDef )
  213. return;
  214. EditablePanel* pMapChoice = FindControl< EditablePanel >( "QuestionContainer", true );
  215. if ( pMapChoice )
  216. {
  217. // Label text
  218. pMapChoice->SetDialogVariable( "mapname", g_pVGuiLocalize->Find( pMapDef->pszMapNameLocKey ) );
  219. }
  220. }
  221. #ifdef STAGING_ONLY
  222. CON_COMMAND( test_survey, "Creates a test survey" )
  223. {
  224. if( args.ArgC() < 2 )
  225. return;
  226. int nDefIndex = atoi( args[1] );
  227. if ( nDefIndex < 0 || nDefIndex >= SurveyQuestionType_ARRAYSIZE )
  228. return;
  229. CMsgGCSurveyRequest msgSurvey;
  230. msgSurvey.set_match_id( 0 );
  231. msgSurvey.set_question_type( (SurveyQuestionType)nDefIndex );
  232. Panel* pSurvey = CreateSurveyQuestionPanel( NULL, msgSurvey );
  233. IViewPortPanel *pMMOverride = ( gViewPortInterface->FindPanelByName( PANEL_MAINMENUOVERRIDE ) );
  234. pSurvey->SetParent( (CHudMainMenuOverride*)pMMOverride );
  235. }
  236. #endif
  237. #endif