//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // //=============================================================================// #include "cbase.h" #include "quest_item_panel.h" #include "tf_hud_item_progress_tracker.h" #include "quest_log_panel.h" #include "c_tf_player.h" #include "econ_item_description.h" #include "clientmode_tf.h" #include #include "quest_objective_manager.h" #include "econ_quests.h" #include "confirm_dialog.h" #include "tf_quest_restriction.h" #include "item_model_panel.h" #include "tf_gc_client.h" // memdbgon must be the last include file in a .cpp file!!! #include void AddSubKeyNamed( KeyValues *pKeys, const char *pszName ); const float k_flQuestDecodeTime = 2.f; const float k_flQuestTurnInTime = 5.f; ConVar tf_quest_turn_in_confirm_opt_out( "tf_quest_turn_in_confirm_opt_out", "0", FCVAR_ARCHIVE, "If nonzero, don't confirm submitting a contract that does not have all of the bonus points" ); extern CQuestLogPanel *GetQuestLog(); extern CQuestTooltip* g_spTextTooltip; extern const char *s_pszMMTypes[kMatchmakingTypeCount]; extern const char *s_pszGameModes[eNumGameCategories]; void SelectGroup( EMatchmakingGroupType eGroup, bool bSelected ); void SelectCategory( EGameCategory eCategory, bool bSelected ); void PromptOrFireCommand( const char* pszCommand ); static void ConfirmDiscardQuest( bool bConfirmed, void* pContext ) { CQuestItemPanel *pQuestItemPanel = ( CQuestItemPanel* )pContext; if ( pQuestItemPanel ) { pQuestItemPanel->OnConfirmDelete( bConfirmed ); } } static void ConfirmEquipLoaners( bool bConfirmed, void* pContext ) { CQuestItemPanel *pQuestItemPanel = ( CQuestItemPanel* )pContext; if ( pQuestItemPanel ) { pQuestItemPanel->OnConfirmEquipLoaners( bConfirmed ); } } static void ConfirmTurnInQuest( bool bConfirmed, void* pContext ) { if ( bConfirmed ) { CQuestItemPanel *pQuestItemPanel = (CQuestItemPanel*)pContext; if ( pQuestItemPanel ) { pQuestItemPanel->OnCompleteQuest(); } } } //----------------------------------------------------------------------------- // Purpose: fill vecLoanerItems with loaners def indices from pQuest //----------------------------------------------------------------------------- static int GetLoanerListFromQuest( const CEconItemView *pQuest, CUtlVector< item_definition_index_t >& vecLoanerItems ) { if ( !pQuest ) return 0; // loaners from the quest const CUtlVector< CTFRequiredQuestItemsSet >& vecQuestRequiredItems = pQuest->GetItemDefinition()->GetQuestDef()->GetRequiredItemSets(); FOR_EACH_VEC( vecQuestRequiredItems, i ) { // don't add dups if ( vecLoanerItems.Find( vecQuestRequiredItems[i].GetLoanerItemDef() ) == vecLoanerItems.InvalidIndex() ) { vecLoanerItems.AddToTail( vecQuestRequiredItems[i].GetLoanerItemDef() ); } } // loaners from the objectives //{ // // Get all the objectives // QuestObjectiveDefVec_t vecChosenObjectives; // pQuest->GetItemDefinition()->GetQuestDef()->GetRolledObjectivesForItem( vecChosenObjectives, pQuest ); // // Get all the items we need to give as loaners from the objectives // FOR_EACH_VEC( vecChosenObjectives, i ) // { // const CUtlVector< CTFRequiredQuestItemsSet >& vecObjectiveRequiredItems = vecChosenObjectives[ i ]->GetConditions()->GetRequiredItemSets(); // FOR_EACH_VEC( vecObjectiveRequiredItems, iRequired ) // { // // don't add dups // if ( vecLoanerItems.Find( vecObjectiveRequiredItems[ iRequired ].GetLoanerItemDef() ) == vecLoanerItems.InvalidIndex() ) // { // vecLoanerItems.AddToTail( vecObjectiveRequiredItems[ iRequired ].GetLoanerItemDef() ); // } // } // } //} return vecLoanerItems.Count(); } //----------------------------------------------------------------------------- // Purpose: fill vecGrantedLoaners with granted loaners from specific quest ID //----------------------------------------------------------------------------- static int GetLoanersFromLocalInventory( const itemid_t& questID, const CUtlVector< item_definition_index_t >& vecLoanerItems, CUtlVector< CEconItemView* >& vecGrantedLoaners ) { if ( vecLoanerItems.Count() > 0 ) { CPlayerInventory *pLocalInv = InventoryManager()->GetLocalInventory(); int nCount = pLocalInv->GetItemCount(); for ( int i = 0; i < nCount; ++i ) { CEconItemView* pItem = pLocalInv->GetItem( i ); bool bIsLoaner = false; // check if the item is a loaner and is associated with this quest FOR_EACH_VEC( vecLoanerItems, iLoaner ) { if ( vecLoanerItems[iLoaner] == pItem->GetItemDefIndex() && GetAssociatedQuestItemID( pItem ) == questID ) { bIsLoaner = true; break; } } // already granted this loaner, remove from the list to give if ( bIsLoaner ) { vecGrantedLoaners.AddToTail( pItem ); } // found all given loaners if ( vecLoanerItems.Count() == vecGrantedLoaners.Count() ) { break; } } } return vecGrantedLoaners.Count(); } DECLARE_BUILD_FACTORY( CInputProxyPanel ) CInputProxyPanel::CInputProxyPanel( Panel *parent, const char *pszPanelName ) : BaseClass( parent, pszPanelName ) {} void CInputProxyPanel::AddPanelForCommand( EInputTypes eInputType, Panel* pPanel, const char* pszCommand ) { m_vecRedirectPanels[ eInputType ].AddToTail( { pPanel, pszCommand } ); } void CInputProxyPanel::OnCursorMoved( int x, int y ) { FOR_EACH_VEC( m_vecRedirectPanels[ INPUT_MOUSE_MOVE ], i ) { PostMessage( m_vecRedirectPanels[ INPUT_MOUSE_MOVE ][ i ].m_pPanel, new KeyValues( m_vecRedirectPanels[ INPUT_MOUSE_MOVE ][ i ].m_pszCommand, "x", x, "y", y ) ); } } void CInputProxyPanel::OnCursorEntered() { FOR_EACH_VEC( m_vecRedirectPanels[ INPUT_MOUSE_ENTER ], i ) { PostMessage( m_vecRedirectPanels[ INPUT_MOUSE_ENTER ][ i ].m_pPanel, new KeyValues( m_vecRedirectPanels[ INPUT_MOUSE_ENTER ][ i ].m_pszCommand ) ); } } void CInputProxyPanel::OnCursorExited() { FOR_EACH_VEC( m_vecRedirectPanels[ INPUT_MOUSE_EXIT ], i ) { PostMessage( m_vecRedirectPanels[ INPUT_MOUSE_EXIT ][ i ].m_pPanel, new KeyValues( m_vecRedirectPanels[ INPUT_MOUSE_EXIT ][ i ].m_pszCommand ) ); } } void CInputProxyPanel::OnMousePressed(MouseCode code) { FOR_EACH_VEC( m_vecRedirectPanels[ INPUT_MOUSE_PRESS ], i ) { PostMessage( m_vecRedirectPanels[ INPUT_MOUSE_PRESS ][ i ].m_pPanel, new KeyValues( m_vecRedirectPanels[ INPUT_MOUSE_PRESS ][ i ].m_pszCommand, "code", code ) ); } } void CInputProxyPanel::OnMouseDoublePressed(MouseCode code) { FOR_EACH_VEC( m_vecRedirectPanels[ INPUT_MOUSE_DOUBLE_PRESS ], i ) { PostMessage( m_vecRedirectPanels[ INPUT_MOUSE_DOUBLE_PRESS ][ i ].m_pPanel, new KeyValues( m_vecRedirectPanels[ INPUT_MOUSE_DOUBLE_PRESS ][ i ].m_pszCommand, "code", code ) ); } } void CInputProxyPanel::OnMouseReleased(MouseCode code) { FOR_EACH_VEC( m_vecRedirectPanels[ INPUT_MOUSE_RELEASED ], i ) { PostMessage( m_vecRedirectPanels[ INPUT_MOUSE_RELEASED ][ i ].m_pPanel, new KeyValues( m_vecRedirectPanels[ INPUT_MOUSE_RELEASED ][ i ].m_pszCommand, "code", code ) ); } } void CInputProxyPanel::OnMouseWheeled(int delta) { FOR_EACH_VEC( m_vecRedirectPanels[ INPUT_MOUSE_WHEEL ], i ) { PostMessage( m_vecRedirectPanels[ INPUT_MOUSE_WHEEL ][ i ].m_pPanel, new KeyValues( m_vecRedirectPanels[ INPUT_MOUSE_WHEEL ][ i ].m_pszCommand, "delta", delta ) ); } } DECLARE_BUILD_FACTORY( CQuestStatusPanel ) CQuestStatusPanel::CQuestStatusPanel( Panel *parent, const char *pszPanelName ) : EditablePanel( parent, pszPanelName ) , m_pMovingContainer( NULL ) , m_bShouldBeVisible( false ) { m_pMovingContainer = new EditablePanel( this, "movingcontainer" ); m_transitionTimer.Invalidate(); } void CQuestStatusPanel::SetShow( bool bShow ) { if ( bShow != m_bShouldBeVisible ) { m_transitionTimer.Start( 0.6f ); } m_bShouldBeVisible = bShow; SetVisible( m_bShouldBeVisible ); } void CQuestStatusPanel::OnThink() { BaseClass::OnThink(); const int nStartY = m_bShouldBeVisible ? m_iHiddenY : m_iVisibleY; const int nEndY = m_bShouldBeVisible ? m_iVisibleY : m_iHiddenY; float flProgress = 1.f; if ( !m_transitionTimer.IsElapsed() ) { flProgress = Bias( RemapValClamped( m_transitionTimer.GetElapsedTime(), 0.f , m_transitionTimer.GetCountdownDuration(), 0.f, 1.f ), 0.7f ); } flProgress = RemapVal( flProgress, 0.f, 1.f, (float)nStartY, (float)nEndY ); m_pMovingContainer->SetPos( m_pMovingContainer->GetXPos(), flProgress ); SetVisible( m_bShouldBeVisible || flProgress > 0.f ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CQuestItemPanel::CQuestItemPanel( Panel *parent, const char *pszPanelName, CEconItemView* pQuestItem, CScrollableQuestList* pQuestList ) : EditablePanel( parent, pszPanelName ) , m_hQuestItem( NULL ) , m_eState( STATE_NORMAL ) , m_pTurnInContainer( NULL ) , m_pTurnInDimmer( NULL ) , m_pszCompleteSound( NULL ) , m_pFrontFolderContainer( NULL ) , m_pBackFolderContainer( NULL ) , m_bCollapsed( true ) , m_pQuestList( pQuestList ) , m_pQuestPaperContainer( NULL ) , m_pTitleButton( NULL ) , m_pIdentifyContainer( NULL ) , m_pIdentifyDimmer( NULL ) , m_pKVCipherStrings( NULL ) , m_pPhotoStatic( NULL ) , m_pFlavorScrollingContainer( NULL ) , m_pTurningInLabel( NULL ) , m_pFindServerButton( NULL ) , m_pLoanerContainerPanel( NULL ) , m_pRequestLoanerItemsButton( NULL ) , m_pEquipLoanerItemsButton( NULL ) , m_pItemTrackerPanel( NULL ) , m_pKVItemTracker( NULL ) , m_pObjectiveExplanationLabel( NULL ) , m_pEncodedStatus( NULL ) , m_pInactiveStatus( NULL ) , m_pReadyToTurnInStatus( NULL ) , m_pExpirationLabel( NULL ) , m_pTurnInButton( NULL ) , m_bHasAllControls( false ) , m_pDiscardButton( NULL ) { SetItem( pQuestItem ); m_StateTimer.Invalidate(); ListenForGameEvent( "quest_objective_completed" ); ListenForGameEvent( "player_spawn" ); ListenForGameEvent( "client_disconnect" ); ListenForGameEvent( "inventory_updated" ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CQuestItemPanel::~CQuestItemPanel() { if ( m_pItemTrackerPanel ) { m_pItemTrackerPanel->MarkForDeletion(); m_pItemTrackerPanel = NULL; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CQuestItemPanel::ApplySchemeSettings( IScheme *pScheme ) { BaseClass::ApplySchemeSettings ( pScheme ); AddActionSignalTarget( GetQuestLog() ); LoadResFileForCurrentItem(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CQuestItemPanel::LoadResFileForCurrentItem() { tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); const char *pszResFile = "Resource/UI/quests/QuestItemPanel_Base.res"; if ( m_hQuestItem ) { const GameItemDefinition_t *pItemDef = m_hQuestItem->GetItemDefinition(); // Get our quest theme const CQuestThemeDefinition *pTheme = pItemDef->GetQuestDef()->GetQuestTheme(); if ( pTheme ) { pszResFile = pTheme->GetQuestItemResFile(); } } KeyValues *pConditions = new KeyValues( "conditions" ); if ( pConditions ) { char uilanguage[64]; uilanguage[0] = 0; engine->GetUILanguage( uilanguage, sizeof( uilanguage ) ); char szCondition[64]; Q_snprintf( szCondition, sizeof( szCondition ), "if_%s", uilanguage ); AddSubKeyNamed( pConditions, szCondition ); } SetMouseInputEnabled( true ); // Slam this to true. When panels get created, they'll inherit their parents' mouse enabled state // and if we've been fiddling with it, we might accidently create all child panels with mouse input disabled. // Setting this to true just before the controls are made gives them a chance to be mouse enabled if they want. LoadControlSettings( pszResFile, NULL, NULL, pConditions ); g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, m_strReset ); m_pMainContainer = FindControl( "MainContainer" ); if ( m_pMainContainer ) { m_pMainContainer->AddActionSignalTarget( this ); } m_pQuestPaperContainer = FindControl( "QuestPaperContainer", true ); m_pFrontFolderContainer = FindControl( "FrontFolderContainer", true ); Assert( m_pFrontFolderContainer ); if ( m_pFrontFolderContainer ) { m_pFrontFolderImage = m_pFrontFolderContainer->FindControl( "FrontFolderImage", true ); Assert( m_pFrontFolderImage ); m_pEncodedStatus = m_pFrontFolderContainer->FindControl< CQuestStatusPanel >( "EncodedStatus", true ); m_pInactiveStatus = m_pFrontFolderContainer->FindControl< CQuestStatusPanel >( "InactiveStatus", true ); m_pReadyToTurnInStatus = m_pFrontFolderContainer->FindControl< CQuestStatusPanel >( "ReadyToTurnInStatus", true ); } m_pBackFolderContainer = FindControl( "BackFolderContainer", true ); Assert( m_pBackFolderContainer ); if ( m_pBackFolderContainer ) { m_pBackFolderImage = m_pBackFolderContainer->FindControl( "BackFolderImage", true ); Assert( m_pBackFolderImage ); } if ( m_pQuestPaperContainer ) { #if defined( STAGING_ONLY ) || defined( DEBUG ) // don't do this in public m_pDiscardButton = new CExButton( m_pQuestPaperContainer, "Discard", "Discard", this, "discard_quest" ); m_pDiscardButton->SetEnabled( true ); m_pDiscardButton->SizeToContents(); m_pDiscardButton->SetZPos( 101 ); m_pDiscardButton->SetPos( 70, 40 ); m_pDiscardButton->SetVisible( false ); #endif // STAGING_ONLY || DEBUG m_pFindServerButton = m_pQuestPaperContainer->FindControl< CExButton >( "FindServerButton", true ); m_pLoanerContainerPanel = m_pQuestPaperContainer->FindControl< EditablePanel >( "LoanerContainerPanel", true ); if ( m_pLoanerContainerPanel ) { m_pRequestLoanerItemsButton = m_pLoanerContainerPanel->FindControl< CExButton >( "RequestLoanerItemsButton", true ); m_pEquipLoanerItemsButton = m_pLoanerContainerPanel->FindControl< CExButton >( "EquipLoanerItemsButton", true ); for ( int i = 0; i < ARRAYSIZE( m_pLoanerItemModelPanel ); ++i ) { m_pLoanerItemModelPanel[i] = m_pLoanerContainerPanel->FindControl< CItemModelPanel >( CFmtStr( "Loaner%dItemModelPanel", i + 1 ), true ); } } m_pTitleButton = m_pQuestPaperContainer->FindControl( "TitleButton", true ); m_pIdentifyContainer = m_pQuestPaperContainer->FindControl( "IdentifyButtonContainer", true ); if ( m_pIdentifyContainer ) { m_pIdentifyDimmer = m_pIdentifyContainer->FindControl( "Dimmer", true ); m_pIdentifyButton = m_pIdentifyContainer->FindControl( "IdentifyButton", true ); } Assert( m_pIdentifyContainer ); m_pEncodedImage = m_pQuestPaperContainer->FindControl( "EncodedImage", true ); m_pPhotoStatic = m_pQuestPaperContainer->FindControl( "StaticPhoto", true ); Assert( m_pPhotoStatic ); m_pFlavorScrollingContainer = m_pQuestPaperContainer->FindControl( "ScrollableBottomContainer", true ); Assert( m_pFlavorScrollingContainer ); if ( m_pFlavorScrollingContainer ) { m_pObjectiveExplanationLabel = m_pFlavorScrollingContainer->FindControl< Label >( "QuestObjectiveExplanation", true ); } CInputProxyPanel* pInputProxy = m_pQuestPaperContainer->FindControl< CInputProxyPanel >( "PaperInputProxyPanel", true ); if ( pInputProxy ) { // Make the scroller scroll pInputProxy->AddPanelForCommand( CInputProxyPanel::INPUT_MOUSE_WHEEL, m_pFlavorScrollingContainer, "MouseWheeled" ); // Make the title glow pInputProxy->AddPanelForCommand( CInputProxyPanel::INPUT_MOUSE_ENTER, m_pTitleButton, "CursorEntered" ); pInputProxy->AddPanelForCommand( CInputProxyPanel::INPUT_MOUSE_EXIT, m_pTitleButton, "CursorExited" ); // Capture clicks to expand/contract pInputProxy->AddPanelForCommand( CInputProxyPanel::INPUT_MOUSE_RELEASED, this, "MouseReleased" ); } m_pTurnInContainer = m_pQuestPaperContainer->FindControl< EditablePanel >( "TurnInContainer" ); Assert( m_pTurnInContainer ); if ( m_pTurnInContainer ) { m_pTurnInDimmer = m_pTurnInContainer->FindControl< EditablePanel >( "Dimmer", true ); Assert( m_pTurnInContainer ); m_pTurnInButton = m_pTurnInContainer->FindControl< Button >( "TurnInButton", true ); Assert( m_pTurnInButton ); m_pTurnInSpinnerContainer = m_pTurnInContainer->FindControl< EditablePanel>( "TurnInSpinnerContainer", true ); Assert( m_pTurnInSpinnerContainer ); if ( m_pTurnInSpinnerContainer ) { m_pTurningInLabel = m_pTurnInSpinnerContainer->FindControl< Label >( "TurningInLabel", true ); Assert( m_pTurningInLabel ); } } m_pAcceptedImage = m_pQuestPaperContainer->FindControl< ImagePanel >( "AcceptedImage", true ); Assert( m_pAcceptedImage ); } if ( m_pFrontFolderContainer ) { CInputProxyPanel* pInputProxy = m_pFrontFolderContainer->FindControl< CInputProxyPanel >( "FrontInputProxyPanel", true ); if ( pInputProxy ) { pInputProxy->AddPanelForCommand( CInputProxyPanel::INPUT_MOUSE_ENTER, m_pInactiveStatus, "CursorEntered" ); pInputProxy->AddPanelForCommand( CInputProxyPanel::INPUT_MOUSE_EXIT, m_pInactiveStatus, "CursorExited" ); // Make the title glow pInputProxy->AddPanelForCommand( CInputProxyPanel::INPUT_MOUSE_ENTER, m_pTitleButton, "CursorEntered" ); pInputProxy->AddPanelForCommand( CInputProxyPanel::INPUT_MOUSE_EXIT, m_pTitleButton, "CursorExited" ); // Make the backdrop highlight pInputProxy->AddPanelForCommand( CInputProxyPanel::INPUT_MOUSE_ENTER, this, "CollapsedGlowStart" ); pInputProxy->AddPanelForCommand( CInputProxyPanel::INPUT_MOUSE_EXIT, this, "CollapsedGlowEnd" ); // Capture clicks to expand/contract pInputProxy->AddPanelForCommand( CInputProxyPanel::INPUT_MOUSE_RELEASED, this, "MouseReleased" ); } } m_pExpirationLabel = FindControl