Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
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.
 
 
 
 
 
 

1625 lines
53 KiB

//========= 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 <vgui_controls/AnimationController.h>
#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 <tier0/memdbgon.h>
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<EditablePanel>( "MainContainer" );
if ( m_pMainContainer )
{
m_pMainContainer->AddActionSignalTarget( this );
}
m_pQuestPaperContainer = FindControl<EditablePanel>( "QuestPaperContainer", true );
m_pFrontFolderContainer = FindControl<EditablePanel>( "FrontFolderContainer", true );
Assert( m_pFrontFolderContainer );
if ( m_pFrontFolderContainer )
{
m_pFrontFolderImage = m_pFrontFolderContainer->FindControl<ImagePanel>( "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<EditablePanel>( "BackFolderContainer", true );
Assert( m_pBackFolderContainer );
if ( m_pBackFolderContainer )
{
m_pBackFolderImage = m_pBackFolderContainer->FindControl<ImagePanel>( "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<CExButton>( "TitleButton", true );
m_pIdentifyContainer = m_pQuestPaperContainer->FindControl<EditablePanel>( "IdentifyButtonContainer", true );
if ( m_pIdentifyContainer )
{
m_pIdentifyDimmer = m_pIdentifyContainer->FindControl<EditablePanel>( "Dimmer", true );
m_pIdentifyButton = m_pIdentifyContainer->FindControl<CExButton>( "IdentifyButton", true );
}
Assert( m_pIdentifyContainer );
m_pEncodedImage = m_pQuestPaperContainer->FindControl<ImagePanel>( "EncodedImage", true );
m_pPhotoStatic = m_pQuestPaperContainer->FindControl<ImagePanel>( "StaticPhoto", true );
Assert( m_pPhotoStatic );
m_pFlavorScrollingContainer = m_pQuestPaperContainer->FindControl<CExScrollingEditablePanel>( "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<Label>( "QuestExpirationWarning", true );
m_pFlavorText = FindControl<Label>( "QuestFlavorText", true );
SetupObjectivesPanels( true );
if ( pConditions )
{
pConditions->deleteThis();
}
m_bHasAllControls = m_pQuestPaperContainer
&& m_pFrontFolderContainer
&& m_pFrontFolderImage
&& m_pBackFolderContainer
&& m_pBackFolderImage
&& m_pEncodedStatus
&& m_pInactiveStatus
&& m_pReadyToTurnInStatus
&& m_pFlavorText
&& m_pObjectiveExplanationLabel
&& m_pExpirationLabel
&& m_pTurnInContainer
&& m_pTurnInDimmer
&& m_pTurnInButton
&& m_pIdentifyButton
&& m_pTurnInSpinnerContainer
&& m_pTitleButton
&& m_pIdentifyDimmer
&& m_pIdentifyContainer
&& m_pPhotoStatic
&& m_pAcceptedImage
&& m_pTurningInLabel
&& m_pFlavorScrollingContainer
&& m_pItemTrackerPanel
&& m_pEncodedImage
&& m_pMainContainer;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CQuestItemPanel::ApplySettings( KeyValues *inResourceData )
{
tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
BaseClass::ApplySettings( inResourceData );
if ( m_hQuestItem )
{
m_vecFoldersImages.Purge();
KeyValues *pKVFoldersBlock = inResourceData->FindKey( "folders" );
Assert( pKVFoldersBlock );
if ( pKVFoldersBlock )
{
FOR_EACH_TRUE_SUBKEY( pKVFoldersBlock, pKVFolder )
{
auto& folder = m_vecFoldersImages[ m_vecFoldersImages.AddToTail() ];
folder.m_strFront = pKVFolder->GetString( "front", NULL);
folder.m_strBack = pKVFolder->GetString( "back", NULL );
}
}
else
{
const GameItemDefinition_t *pItemDef = m_hQuestItem->GetItemDefinition();
// Get our quest theme
const CQuestThemeDefinition *pTheme = pItemDef->GetQuestDef()->GetQuestTheme();
if ( pTheme )
{
Warning( "%s %s is missing 'folders' data\n", pItemDef->GetQuestDef()->GetCorrespondingOperationName(), pTheme->GetQuestItemResFile() );
}
}
}
if ( 1/*m_pKVItemTracker == NULL*/ )
{
KeyValues *pTrackerKV = inResourceData->FindKey( "tracker_kv" );
if ( pTrackerKV )
{
m_pKVItemTracker = pTrackerKV->MakeCopy();
}
}
m_strEncodedText = inResourceData->GetString( "encoded_text", NULL );
m_strExpireText = inResourceData->GetString( "expire_text", NULL );
m_strItemTrackerResFile = inResourceData->GetString( "TrackerPanelResFile", NULL );
// Sound effects
m_strTurnInSound = inResourceData->GetString( "turn_in_sound", NULL );
m_strTurnInSuccessSound = inResourceData->GetString( "turn_in_success_sound", NULL );
m_strDecodeSound = inResourceData->GetString( "decode_sound", NULL );
m_strExpandSound = inResourceData->GetString( "expand_sound", NULL );
m_strCollapseSound = inResourceData->GetString( "collapse_sound", NULL );
// Animations
m_strReset = inResourceData->GetString( "anim_reset", NULL );
m_strAnimExpand = inResourceData->GetString( "anim_expand", NULL );
m_strAnimCollapse = inResourceData->GetString( "anim_collapse", NULL );
m_strTurningIn = inResourceData->GetString( "anim_turning_in", NULL );
m_strHighlightOn = inResourceData->GetString( "anim_highlight_on", NULL );
m_strHighlightOff = inResourceData->GetString( "anim_highlight_off", NULL );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CQuestItemPanel::PerformLayout( void )
{
tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
BaseClass::PerformLayout();
if ( !HasAllControls() )
return;
m_pIdentifyContainer->SetVisible( m_eState == STATE_UNIDENTIFIED );
m_pTurnInContainer->SetVisible( m_eState == STATE_COMPLETED || m_eState == STATE_TURNING_IN__GC_RESPONDED || m_eState == STATE_TURNING_IN__WAITING_FOR_GC);
m_pTurnInButton->SetVisible( m_eState == STATE_COMPLETED );
m_pTurnInSpinnerContainer->SetVisible( m_eState == STATE_TURNING_IN__GC_RESPONDED || m_eState == STATE_TURNING_IN__WAITING_FOR_GC );
m_pPhotoStatic->SetVisible( m_eState == STATE_UNIDENTIFIED || m_eState == STATE_IDENTIFYING );
m_pFindServerButton->SetVisible( m_eState == STATE_NORMAL );
// only exist in non public build
if ( m_pDiscardButton )
{
m_pDiscardButton->SetVisible( m_eState == STATE_NORMAL );
}
// loaners
if ( m_eState == STATE_NORMAL || m_eState == STATE_COMPLETED )
{
// get all loaners required from quest
CUtlVector< item_definition_index_t > vecLoanerItems;
bool bRequiredLoaners = GetLoanerListFromQuest( m_hQuestItem, vecLoanerItems ) > 0;
// get all granted loaners from this quest
CUtlVector< CEconItemView* > vecGrantedLoaners;
if ( bRequiredLoaners )
{
GetLoanersFromLocalInventory( m_hQuestItem->GetItemID(), vecLoanerItems, vecGrantedLoaners );
}
if ( bRequiredLoaners )
{
m_pLoanerContainerPanel->SetVisible( true );
bool bAllGranted = vecLoanerItems.Count() == vecGrantedLoaners.Count();
m_pRequestLoanerItemsButton->SetVisible( !bAllGranted );
m_pEquipLoanerItemsButton->SetVisible( bAllGranted );
for ( int i = 0; i < ARRAYSIZE( m_pLoanerItemModelPanel ); ++i )
{
// try to use the granted items first
if ( i < vecGrantedLoaners.Count() )
{
m_pLoanerItemModelPanel[i]->SetItem( vecGrantedLoaners[i] );
m_pLoanerItemModelPanel[i]->SetVisible( true );
}
// In case we don't get all the loaner items, use fake items as second option
else if ( i < vecLoanerItems.Count() )
{
CEconItemView tempItem;
tempItem.Init( vecLoanerItems[i], AE_UNIQUE, AE_USE_SCRIPT_VALUE, true );
m_pLoanerItemModelPanel[i]->SetItem( &tempItem );
m_pLoanerItemModelPanel[i]->SetVisible( true );
}
else
{
m_pLoanerItemModelPanel[i]->SetVisible( false );
}
}
}
else
{
m_pLoanerContainerPanel->SetVisible( false );
}
}
else
{
m_pLoanerContainerPanel->SetVisible( false );
}
m_pEncodedStatus->SetShow( m_eState == STATE_UNIDENTIFIED );
m_pReadyToTurnInStatus->SetShow( m_eState == STATE_COMPLETED || m_eState == STATE_TURNING_IN__GC_RESPONDED || m_eState == STATE_TURNING_IN__WAITING_FOR_GC );
float flDecodeAmount = 1.f;
// Only cypher-style decoding needs to decode
if ( m_eDecodeStyle == DECODE_STYLE_CYPHER && m_eState == STATE_UNIDENTIFIED )
{
flDecodeAmount = 0.f;
}
m_pEncodedImage->SetAlpha( m_eState == STATE_UNIDENTIFIED ? 255 : 0 );
if ( m_hQuestItem )
{
m_pTitleButton->SetText( GetDecodedString( "name", flDecodeAmount ) );
int nScrollableYOffset = 0;
// Check if the quest is going to expire soon (within a week). If so, show a "This is going to be destroyed" message.
const CRTime nExpirationTime = m_hQuestItem->GetExpirationDate();
const CRTime nOneWeekFromNow = CRTime::RTime32DateAdd( CRTime::RTime32TimeCur(), 1, k_ETimeUnitWeek );
const bool bExpiringSoon = nExpirationTime.GetRTime32() != RTime32(0) && nExpirationTime < nOneWeekFromNow;
m_pExpirationLabel->SetVisible( bExpiringSoon );
if ( bExpiringSoon )
{
CLocalizedRTime32 locTime = { nExpirationTime.GetRTime32(), false, GLocalizationProvider(), NULL };
m_pExpirationLabel->SetText( CConstructLocalizedString( g_pVGuiLocalize->Find( m_strExpireText ), locTime ) );
m_pExpirationLabel->InvalidateLayout( true );
m_pExpirationLabel->SizeToContents();
nScrollableYOffset += m_pExpirationLabel->GetTall();
}
m_pObjectiveExplanationLabel->SetPos( 0, nScrollableYOffset );
m_pObjectiveExplanationLabel->SetText( GetDecodedString( "explanation", flDecodeAmount ) );
m_pObjectiveExplanationLabel->InvalidateLayout( true ); // So we get the right height when we do SizeToContents below
m_pObjectiveExplanationLabel->SizeToContents();
nScrollableYOffset += m_pObjectiveExplanationLabel->GetTall();
m_pFlavorText->SetText( GetDecodedString( "desc", flDecodeAmount ) );
int nWide, nTall;
m_pFlavorText->GetTextImage()->GetContentSize( nWide, nTall );
m_pFlavorText->SetTall( nTall + 20 );
m_pItemTrackerPanel->SetPos( m_pItemTrackerPanel->GetXPos(), nScrollableYOffset );
nScrollableYOffset += m_pItemTrackerPanel->GetTall();
// Put the flavor text below the obectives
m_pFlavorText->SetPos( m_pFlavorText->GetXPos(), nScrollableYOffset );
m_pFlavorScrollingContainer->InvalidateLayout( true );
m_pFlavorScrollingContainer->InvalidateLayout();
m_pFlavorScrollingContainer->ResetScrollAmount();
// Randomize our folder images based on original ID
if ( m_vecFoldersImages.Count() )
{
RandomSeed( m_hQuestItem->GetSOCData() ? m_hQuestItem->GetSOCData()->GetOriginalID() : m_hQuestItem->GetItemDefIndex() );
int idx = RandomInt( 0, m_vecFoldersImages.Count() - 1 );
m_pFrontFolderImage->SetImage( m_vecFoldersImages[ idx ].m_strFront );
m_pBackFolderImage->SetImage( m_vecFoldersImages[ idx ].m_strBack );
}
}
UpdateInvalidReasons();
if ( m_pItemTrackerPanel )
{
auto& vecObjectives = m_pItemTrackerPanel->GetAttributePanels();
FOR_EACH_VEC( vecObjectives, i )
{
// Only do this when unidentified. The panel updates its own string, and we don't want to stomp it
if ( m_eState == STATE_UNIDENTIFIED )
{
const wchar_t *pszString = GetDecodedString( CFmtStr( "objective%d", i ), flDecodeAmount );
vecObjectives[ i ]->SetDialogVariable( "attr_desc", pszString );
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CQuestItemPanel::IsCursorOverMainContainer() const
{
return m_pMainContainer ? m_pMainContainer->IsCursorOver() : false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CQuestItemPanel::SetupObjectivesPanels( bool bRecreate )
{
if ( m_pItemTrackerPanel && bRecreate )
{
m_pItemTrackerPanel->MarkForDeletion();
m_pItemTrackerPanel = NULL;
}
if ( !m_hQuestItem )
return;
if ( !m_pItemTrackerPanel )
{
m_pItemTrackerPanel = new CItemTrackerPanel( m_pFlavorScrollingContainer, "ItemTrackerPanel", m_hQuestItem->GetSOCData(), m_strItemTrackerResFile );
m_pItemTrackerPanel->SetAutoDelete( false );
SETUP_PANEL( m_pItemTrackerPanel );
}
else
{
// Get all the panels created
m_pItemTrackerPanel->SetItem( m_hQuestItem->GetSOCData() );
m_pItemTrackerPanel->InvalidateLayout( true );
}
m_pItemTrackerPanel->SetTall( m_pItemTrackerPanel->GetContentTall() );
// Need to re-layout so the flavor text gets properly positioned under
// all of the objectives
InvalidateLayout();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CQuestItemPanel::SetItem( CEconItemView* pItem )
{
tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
if ( pItem == m_hQuestItem )
{
return;
}
m_bCollapsed = true;
m_hQuestItem.SetItem( pItem );
if ( m_pItemTrackerPanel && pItem )
{
m_pItemTrackerPanel->SetItem( pItem->GetSOCData() );
}
// By default
SetState( STATE_NORMAL );
if ( m_hQuestItem )
{
if ( IsQuestItemReadyToTurnIn( m_hQuestItem ) )
{
SetState( STATE_COMPLETED );
}
else if ( IsUnacknowledged() )
{
SetState( STATE_UNIDENTIFIED );
}
// Snag the quickplay map (if there is one)
m_strQuickPlayMap = m_hQuestItem->GetItemDefinition()->GetQuestDef()->GetQuickplayMapName();
m_strMatchmakingGroupName = m_hQuestItem->GetItemDefinition()->GetQuestDef()->GetMatchmakingGroupName();
m_strMatchmakingCategoryName = m_hQuestItem->GetItemDefinition()->GetQuestDef()->GetMatchmakingCategoryName();
m_strMatchmakingMapName = m_hQuestItem->GetItemDefinition()->GetQuestDef()->GetMatchmakingMapName();
}
// Reload res file so we get the right art
LoadResFileForCurrentItem();
// Capture strings after controls are created
CaptureAndEncodeStrings();
InvalidateLayout();
}
//-----------------------------------------------------------------------------
// Purpose: Returns if the character is one that we don't want to re-encode
// as another, or one that we don't want to encode another to in
// order to maintain line breaks so that the decoding sequence is
// easier for the user to follow.
//-----------------------------------------------------------------------------
bool IsNonEncodeCharacter( const wchar_t& wch)
{
switch ( wch )
{
case L'\x000A':
case L'\x000B':
case L'\x000C':
case L'\x000D':
case L'\x0085':
case L'\x2028':
case L'\x2029':
case L' ':
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CQuestItemPanel::CaptureAndEncodeStrings()
{
tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
if ( !m_hQuestItem )
return;
// Clean up any existing values
if ( m_pKVCipherStrings )
{
m_pKVCipherStrings->deleteThis();
m_pKVCipherStrings = NULL;
}
m_pKVCipherStrings = new KeyValues( "cipherstrings" );
KeyValues *pKVDecoded = m_pKVCipherStrings->CreateNewKey();
pKVDecoded->SetName( "decoded" );
{
// Capture the description/flavor string
const char *pszLocToken = m_hQuestItem->GetItemDefinition()->GetQuestDef()->GetRolledDescriptionForItem( m_hQuestItem->GetSOCData() );
pKVDecoded->SetWString( "desc", g_pVGuiLocalize->Find( pszLocToken ) );
}
if ( m_pObjectiveExplanationLabel )
{
wchar_t wszBuff[512];
m_pObjectiveExplanationLabel->GetText( wszBuff, ARRAYSIZE( wszBuff ) );
pKVDecoded->SetWString( "explanation", wszBuff );
}
auto& vecObjectives = m_pItemTrackerPanel->GetAttributePanels();
// Capture objective strings
FOR_EACH_VEC( vecObjectives, i )
{
CItemAttributeProgressPanel *pObjective = vecObjectives[ i ];
KeyValues *pKV = pObjective->GetDialogVariables();
pKVDecoded->SetWString( CFmtStr( "objective%d", i ), pKV->GetWString( "attr_desc" ) );
}
// Create encoded strings from the decoded strings
KeyValues *pKVEncoded = pKVDecoded->MakeCopy();
pKVEncoded->SetName( "encoded" );
m_pKVCipherStrings->AddSubKey( pKVEncoded );
RandomSeed( m_hQuestItem->GetSOCData() ? m_hQuestItem->GetSOCData()->GetOriginalID() : m_hQuestItem->GetItemDefIndex() );
// "encode" each string by scrambling
FOR_EACH_VALUE( pKVEncoded, pKVString )
{
const wchar_t *pWString = pKVString->GetWString();
wchar wszBuff[4096];
loc_scpy_safe( wszBuff, pWString );
int nStrLen = Q_wcslen( wszBuff );
// Go through the entire string and swap each character
// with another random character in the string
int i=0;
while( wszBuff[i] != 0 && i < ARRAYSIZE( wszBuff ) )
{
// Dont scramble spaces to maintain line breaks
if ( !IsNonEncodeCharacter( wszBuff[i] ) )
{
// Scramble, but keep trying if we scramble to a space
do
{
wszBuff[i] = *(pWString + RandomInt( 0, nStrLen - 1 ) );
} while ( IsNonEncodeCharacter( wszBuff[i] ) );
}
i++;
}
pKVEncoded->SetWString( pKVString->GetName(), wszBuff );
}
const char *pszLocToken = m_hQuestItem->GetItemDefinition()->GetQuestDef()->GetRolledNameForItem( m_hQuestItem->GetSOCData() );
const wchar_t* pwszName = g_pVGuiLocalize->Find( pszLocToken );
// Force the encrypted version of the quest title to be "<Encrypted>".
pKVEncoded->SetWString( "name", g_pVGuiLocalize->Find( m_strEncodedText ) );
pKVDecoded->SetWString( "name", pwszName );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CQuestItemPanel::OnCommand( const char *command )
{
tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
BaseClass::OnCommand( command );
if ( FStrEq( command, "discard_quest" ) )
{
OnDiscardQuest();
}
else if ( FStrEq( command, "select" ) )
{
m_pQuestList->SetSelected( this, false );
}
else if ( FStrEq( command, "turnin" ) )
{
if ( m_hQuestItem && m_hQuestItem->GetItemDefinition() && m_hQuestItem->GetItemDefinition()->GetQuestDef() )
{
if ( !tf_quest_turn_in_confirm_opt_out.GetBool() && ( GetEarnedBonusPoints( m_hQuestItem ) != m_hQuestItem->GetItemDefinition()->GetQuestDef()->GetMaxBonusPoints() ) )
{
CTFGenericConfirmOptOutDialog *pPanel = ShowConfirmOptOutDialog( "#TF_Quest_TurnIn_Title", "#TF_Quest_TurnIn_Text",
"#TF_Quest_TurnIn_Yes", "#TF_Quest_TurnIn_No",
"#TF_Quest_TurnIn_Ask_Opt_Out", "tf_quest_turn_in_confirm_opt_out",
ConfirmTurnInQuest );
if ( pPanel )
{
pPanel->SetContext( this );
return;
}
}
else
{
OnCompleteQuest();
}
}
}
else if ( FStrEq( command, "identify" ) )
{
OnIdentify();
}
else if ( FStrEq( command, "request_loaner_items" ) )
{
GCSDK::CProtoBufMsg< CMsgGCQuestObjective_RequestLoanerItems > msg( k_EMsgGCQuestObjective_RequestLoanerItems );
msg.Body().set_quest_item_id( m_hQuestItem->GetItemID() );
GCClientSystem()->BSendMessage( msg );
}
else if ( FStrEq( command, "equip_loaner_items" ) )
{
OnEquipLoaners();
}
else if( Q_strnicmp( "playsound", command, 9 ) == 0 )
{
vgui::surface()->PlaySound( command + 10 );
}
else if ( FStrEq( "mm_casual_open", command ) )
{
if ( GTFGCClientSystem() )
{
if ( ( m_strMatchmakingGroupName != 0 ) || ( m_strMatchmakingCategoryName != 0 ) || ( m_strMatchmakingMapName != 0 ) )
{
GTFGCClientSystem()->ClearCasualSearchCriteria();
if ( m_strMatchmakingGroupName != 0 )
{
int iGroupType = StringFieldToInt( m_strMatchmakingGroupName.Get(), s_pszMMTypes, ARRAYSIZE( s_pszMMTypes ) );
if ( iGroupType > -1 )
{
SelectGroup( (EMatchmakingGroupType)iGroupType, true );
}
}
if ( m_strMatchmakingCategoryName != 0 )
{
int iCategoryType = StringFieldToInt( m_strMatchmakingCategoryName.Get(), s_pszGameModes, ARRAYSIZE( s_pszGameModes ) );
if ( iCategoryType > -1 )
{
SelectCategory( (EGameCategory)iCategoryType, true );
}
}
if ( m_strMatchmakingMapName != 0 )
{
if ( GetItemSchema() )
{
const MapDef_t *pMap = GetItemSchema()->GetMasterMapDefByName( m_strMatchmakingMapName.Get() );
if ( pMap )
{
GTFGCClientSystem()->SelectCasualMap( pMap->m_nDefIndex, true );
}
}
}
}
}
// Defaulting to 12v12
GTFGCClientSystem()->SetLadderType( k_nMatchGroup_Casual_12v12 );
PromptOrFireCommand( "OpenMatchmakingLobby casual" );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const wchar_t* CQuestItemPanel::GetDecodedString( const char* pszKeyName, float flPercentDecoded )
{
tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
static wchar_t wszBuff[4096];
KeyValues *pKVEncoded = m_pKVCipherStrings->FindKey( "encoded" );
KeyValues *pKVDecoded = m_pKVCipherStrings->FindKey( "decoded" );
// Trivial work?
if ( flPercentDecoded <= 0.f )
{
return pKVEncoded->GetWString( pszKeyName );
}
else if ( flPercentDecoded >= 1.f )
{
return pKVDecoded->GetWString( pszKeyName );
}
loc_scpy_safe( wszBuff, pKVEncoded->GetWString( pszKeyName ) );
const locchar_t* pwszDecoded = pKVDecoded->GetWString( pszKeyName );
int nLength = loc_strlen( pwszDecoded );
int nMaxCopy = nLength * flPercentDecoded;
// Not using V_wcsncpy because it null terminates.
wcsncpy( wszBuff, pwszDecoded, nMaxCopy );
return wszBuff;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CQuestItemPanel::OnThink()
{
tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
switch ( m_eState )
{
case STATE_IDENTIFYING:
{
// Have we finished?
if ( m_StateTimer.HasStarted() && m_StateTimer.IsElapsed() )
{
m_pItemTrackerPanel->InvalidateLayout();
m_StateTimer.Invalidate();
SetState( STATE_NORMAL );
// Play a reveal sound?
const GameItemDefinition_t *pItemDef = m_hQuestItem->GetItemDefinition();
const CQuestThemeDefinition *pTheme = pItemDef->GetQuestDef()->GetQuestTheme();
if ( pTheme )
{
const char *pszRevealSound = pTheme->GetRevealSound();
if ( pszRevealSound && pszRevealSound[0] )
{
vgui::surface()->PlaySound( pszRevealSound );
}
}
}
float flPercent = m_StateTimer.GetElapsedTime() / m_StateTimer.GetCountdownDuration();
switch( m_eDecodeStyle )
{
case DECODE_STYLE_CYPHER:
{
// Slowly "decode" the text in the lables
m_pTitleButton->SetText( GetDecodedString( "name", flPercent ) );
m_pFlavorText->SetText( GetDecodedString( "desc", flPercent ) );
m_pObjectiveExplanationLabel->SetText( GetDecodedString( "explanation", flPercent ) );
auto& vecObjectives = m_pItemTrackerPanel->GetAttributePanels();
FOR_EACH_VEC( vecObjectives, i )
{
const wchar_t *pszString = GetDecodedString( CFmtStr( "objective%d", i ), flPercent );
vecObjectives[ i ]->SetDialogVariable( "attr_desc", pszString );
}
break;
}
case DECODE_STYLE_PANEL_FADE:
{
// Slowly fade out the encode image
m_pEncodedImage->SetAlpha( 255 * ( 1.f - flPercent ) );
break;
}
default:
Assert( 0 );
}
break;
}
case STATE_TURNING_IN__WAITING_FOR_GC:
{
// Have we finished?
if ( m_StateTimer.HasStarted() && m_StateTimer.IsElapsed() )
{
m_pQuestList->SetCompletingPanel( NULL );
m_StateTimer.Invalidate();
// Bring up confirm dialog
CTFGenericConfirmDialog *pDialog = new CTFGenericConfirmDialog( "#TF_Trading_Timeout_Title", "#TF_Trading_Timeout_Text", "#TF_OK", NULL, NULL, NULL );
if ( pDialog )
{
pDialog->SetContext( this );
pDialog->Show();
}
SetState( STATE_COMPLETED );
}
// Intentionally fall through
}
case STATE_TURNING_IN__GC_RESPONDED:
{
// Have we finished?
if ( m_StateTimer.HasStarted() && m_StateTimer.IsElapsed() )
{
SetState( STATE_SHOW_ACCEPTED );
m_StateTimer.Start( 3.f );
m_pAcceptedImage->SetVisible( true );
vgui::surface()->PlaySound( m_strTurnInSuccessSound );
}
if ( m_pTurningInLabel )
{
int nPeriods = m_StateTimer.GetElapsedTime() / 0.3f;
nPeriods %= 4; // Only do up to 3 periods
wchar_t wszTurningInText[64];
char szTurningInLocToken[128];
m_pTurningInLabel->GetTextImage()->GetUnlocalizedText( szTurningInLocToken, ARRAYSIZE( szTurningInLocToken ) );
V_snwprintf( wszTurningInText, ARRAYSIZE( wszTurningInText ), L"%ls", g_pVGuiLocalize->Find( szTurningInLocToken ) );
while ( nPeriods > 0 )
{
V_wcsncat( wszTurningInText, L".", ARRAYSIZE( wszTurningInText ) );
--nPeriods;
}
m_pTurningInLabel->SetText( wszTurningInText );
}
break;
}
case STATE_SHOW_ACCEPTED:
{
if ( m_StateTimer.HasStarted() && m_StateTimer.IsElapsed() )
{
m_pQuestList->SetCompletingPanel( NULL );
m_StateTimer.Invalidate();
engine->ClientCmd_Unrestricted( "gameui_allowescapetoshow\n" );
InventoryManager()->ShowItemsPickedUp( true, false );
GetQuestLog()->AttachToGameUI();
GetQuestLog()->MarkQuestsDirty();
m_pQuestList->PopulateQuestLists();
engine->ClientCmd_Unrestricted( "gameui_preventescapetoshow\n" );
if ( m_pszCompleteSound )
{
vgui::surface()->PlaySound( m_pszCompleteSound );
}
}
else
{
float flPercent = Clamp( m_StateTimer.GetElapsedTime() / 0.2f, 0.f, 1.f );
m_nPaperXShakePos = sin( m_StateTimer.GetElapsedTime() * 200.f ) * ( 1.f - flPercent ) * 8.f;
m_nPaperYShakePos = sin( m_StateTimer.GetElapsedTime() * 200.f ) * ( 1.f - flPercent ) * 8.f;
m_pQuestPaperContainer->SetPos( m_nPaperXPos + m_nPaperXShakePos, m_nPaperYPos + m_nPaperYShakePos );
}
break;
}
case STATE_UNIDENTIFIED:
{
// Do nothing
break;
}
case STATE_COMPLETED:
{
// Do nothing
break;
}
default:
// Do nothing
break;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CQuestItemPanel::FireGameEvent( IGameEvent *event )
{
tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
if( FStrEq( event->GetName(), "quest_objective_completed" ) )
{
itemid_t nIDLow = 0x00000000FFFFFFFF & (itemid_t)event->GetInt( "quest_item_id_low" );
itemid_t nIDHi = 0xFFFFFFFF00000000 & (itemid_t)event->GetInt( "quest_item_id_hi" ) << 32;
itemid_t nID = nIDLow | nIDHi;
if ( m_hQuestItem && nID == m_hQuestItem->GetID() )
{
SetupObjectivesPanels( false );
if ( IsQuestItemReadyToTurnIn( m_hQuestItem ) )
{
SetState( STATE_COMPLETED );
}
PerformLayout();
}
}
else if ( FStrEq( event->GetName(), "player_spawn" )
|| FStrEq( event->GetName(), "client_disconnect" ) )
{
InvalidateLayout();
}
else if ( FStrEq( "inventory_updated", event->GetName() ) )
{
// InvalidateLayout();
}
}
void CQuestItemPanel::OnMouseReleased( MouseCode code )
{
OnCommand( "select" );
}
//-----------------------------------------------------------------------------
// Purpose: Update our invalid reasons
//-----------------------------------------------------------------------------
void CQuestItemPanel::UpdateInvalidReasons()
{
tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
InvalidReasonsContainer_t invalidReasons;
bool bAllAreInvalid = false;
C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
if ( pLocalPlayer && m_hQuestItem )
{
// Get the tracker for the items
const CQuestItemTracker* pItemTracker = QuestObjectiveManager()->GetTypedTracker< CQuestItemTracker* >( m_hQuestItem->GetItemID() );
// Get invalid reasons
if ( pItemTracker )
{
int nNumInvalid = pItemTracker->IsValidForPlayer( pLocalPlayer, invalidReasons );
bAllAreInvalid = pItemTracker->GetTrackers().Count() == nNumInvalid;
}
// Build a string describing why the current quest can't be worked on
if ( !invalidReasons.IsValid() )
{
CUtlVector< CUtlString > vecStrings;
// Get the strings that explain each reasons
GetInvalidReasonsNames( invalidReasons, vecStrings );
wchar_t wszBuff[ 1024 ];
// Start with the explanation
V_swprintf_safe( wszBuff, L"%ls", g_pVGuiLocalize->Find( "#TF_QuestInvalid_Explanation" ) );
// Add in each reason why the quest is invalid
for( int i = 0; i < vecStrings.Count(); ++ i )
{
V_wcscat_safe( wszBuff, L"\n\n" );
V_wcscat_safe( wszBuff, g_pVGuiLocalize->Find( vecStrings[i] ) );
}
// This gets snagged by CQuestTooltip
m_pInactiveStatus->SetDialogVariable( "tiptext", wszBuff );
}
}
// Visible if there's a reason why we're invalid
bool bShow = bAllAreInvalid && m_eState == STATE_NORMAL;
m_pInactiveStatus->SetShow( bShow );
m_pInactiveStatus->SetMouseInputEnabled( bShow );
m_pInactiveStatus->SetTooltip( g_spTextTooltip, NULL );
}
//-----------------------------------------------------------------------------
// Purpose: Start a glow
//-----------------------------------------------------------------------------
void CQuestItemPanel::OnCollapsedGlowStart( void )
{
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, m_strHighlightOn );
}
//-----------------------------------------------------------------------------
// Purpose: Stop the glow
//-----------------------------------------------------------------------------
void CQuestItemPanel::OnCollapsedGlowEnd( void )
{
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, m_strHighlightOff );
}
//-----------------------------------------------------------------------------
// Purpose: Delete the quest.
//-----------------------------------------------------------------------------
void CQuestItemPanel::OnDiscardQuest( void )
{
#if !defined(STAGING_ONLY) && !defined(DEBUG)
// Not in public!
return;
#endif
if ( m_pQuestList->GetCompletingPanel() == NULL )
{
// Bring up confirm dialog
CTFGenericConfirmDialog *pDialog = new CTFGenericConfirmDialog( "#QuestConfirmDiscard_Title", "#QuestConfirmDiscard_Body", "#X_DiscardItem", "#Cancel", &ConfirmDiscardQuest, NULL );
if ( pDialog )
{
pDialog->SetContext( this );
pDialog->Show();
}
const GameItemDefinition_t *pItemDef = m_hQuestItem->GetItemDefinition();
// Get our quest theme
const CQuestThemeDefinition *pTheme = pItemDef->GetQuestDef()->GetQuestTheme();
if ( pTheme )
{
const char *pszDiscardSound = pTheme->GetDiscardSound();
if ( pszDiscardSound && pszDiscardSound[0] )
{
vgui::surface()->PlaySound( pszDiscardSound );
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Equip loaners for local player
//-----------------------------------------------------------------------------
void CQuestItemPanel::OnEquipLoaners( void )
{
if ( !m_hQuestItem )
return;
if ( m_pQuestList->GetCompletingPanel() == NULL )
{
// Bring up confirm dialog
CTFGenericConfirmDialog *pDialog = new CTFGenericConfirmDialog( "#QuestConfirmEquipLoaners_Title", "#QuestConfirmEquipLoaners_Body", "#Equip", "#Cancel", &ConfirmEquipLoaners, NULL );
if ( pDialog )
{
pDialog->SetContext( this );
pDialog->Show();
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Send a message to the GC to evaluate completion of this quest
//-----------------------------------------------------------------------------
void CQuestItemPanel::OnCompleteQuest( void )
{
if ( !m_hQuestItem )
return;
// Double check that they're not just forcing the command
if ( IsQuestItemReadyToTurnIn( m_hQuestItem ) && m_pQuestList->GetCompletingPanel() == NULL )
{
m_pQuestList->SetCompletingPanel( this );
SetState( STATE_TURNING_IN__WAITING_FOR_GC );
// Use the timer for turning in the quest
m_StateTimer.Start( k_flQuestTurnInTime );
vgui::surface()->PlaySound( m_strTurnInSound );
GCSDK::CProtoBufMsg< CMsgGCQuestComplete_Request > msg( k_EMsgGCQuestComplete_Request );
msg.Body().set_quest_item_id( m_hQuestItem->GetItemID() );
GCClientSystem()->BSendMessage( msg );
PostActionSignal( new KeyValues("CompleteQuest") );
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, m_strTurningIn );
const GameItemDefinition_t *pItemDef = m_hQuestItem->GetItemDefinition();
// Get our quest theme
const CQuestThemeDefinition *pTheme = pItemDef->GetQuestDef()->GetQuestTheme();
if ( pTheme )
{
m_pszCompleteSound = pTheme->GetRewardSound();
}
}
}
void CQuestItemPanel::OnIdentify()
{
if ( IsUnacknowledged() )
{
SetState( STATE_IDENTIFYING );
// Use the timer for identifying progress
m_StateTimer.Start( k_flQuestDecodeTime );
vgui::surface()->PlaySound( m_strDecodeSound );
// ack item
CEconItemView *pModifyItem = m_hQuestItem;
TFInventoryManager()->AcknowledgeItem( pModifyItem, false );
TFInventoryManager()->SetItemBackpackPosition( pModifyItem, (uint32)-1, false, true );
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( m_pQuestPaperContainer, "QuestItem_StaticPhoto_Reveal" );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CQuestItemPanel::OnConfirmDelete( bool bConfirm )
{
// Delete the quest
if ( bConfirm && m_hQuestItem )
{
GCSDK::CProtoBufMsg< CMsgGCQuestDiscard_Request > msg( k_EMsgGCQuestDiscard_Request );
msg.Body().set_quest_item_id( m_hQuestItem->GetItemID() );
GCClientSystem()->BSendMessage( msg );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CQuestItemPanel::OnConfirmEquipLoaners( bool bConfirm )
{
// equip loaners
if ( bConfirm && m_hQuestItem )
{
// get all loaners required from quest
CUtlVector< item_definition_index_t > vecLoanerItems;
bool bRequiredLoaners = GetLoanerListFromQuest( m_hQuestItem, vecLoanerItems );
// get all granted loaners from this quest
CUtlVector< CEconItemView* > vecGrantedLoaners;
if ( bRequiredLoaners )
{
GetLoanersFromLocalInventory( m_hQuestItem->GetItemID(), vecLoanerItems, vecGrantedLoaners );
}
for ( int i=0; i<vecGrantedLoaners.Count(); ++i )
{
CEconItemView *pItem = vecGrantedLoaners[i];
if ( pItem )
{
// do it for first class that can equip
for ( int iClass = TF_FIRST_NORMAL_CLASS; iClass < TF_LAST_NORMAL_CLASS; ++iClass )
{
if ( pItem->GetStaticData()->CanBeUsedByClass( iClass ) )
{
int iSlot = pItem->GetStaticData()->GetLoadoutSlot( iClass );
TFInventoryManager()->EquipItemInLoadout( iClass, iSlot, pItem->GetItemID() );
// take the player to character loadout page
engine->ClientCmd_Unrestricted( CFmtStr( "open_charinfo_direct %d", iClass ) );
break;
}
}
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CQuestItemPanel::QuestCompletedResponse()
{
// If we werent the one listening, dont bother
if ( m_eState != STATE_TURNING_IN__WAITING_FOR_GC )
return;
m_pQuestPaperContainer->GetPos( m_nPaperXPos, m_nPaperYPos );
m_nPaperXShakePos = m_nPaperYShakePos = 0;
SetState( STATE_TURNING_IN__GC_RESPONDED );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CQuestItemPanel::SetSelected( bool bSelected, bool bImmediate )
{
bool bPrevCollapsedSide = m_bCollapsed;
m_bCollapsed = ( !m_bCollapsed && bSelected ) || ( !bSelected );
if ( !bImmediate && bPrevCollapsedSide != m_bCollapsed )
{
if ( m_bCollapsed )
{
vgui::surface()->PlaySound( m_strCollapseSound );
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, m_strAnimCollapse );
}
else
{
vgui::surface()->PlaySound( m_strExpandSound );
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, m_strAnimExpand );
}
}
else
{
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, m_strReset );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CQuestItemPanel::IsUnacknowledged()
{
if ( !m_hQuestItem )
return false;
return IsQuestItemUnidentified( m_hQuestItem->GetSOCData() );
}
void CQuestItemPanel::SetState( EItemPanelState_t eState )
{
m_eState = eState;
InvalidateLayout();
}
//-----------------------------------------------------------------------------
// Purpose: GC Msg handler to handle a loaner item response
//-----------------------------------------------------------------------------
class CGCLoanerRequestResponse : public GCSDK::CGCClientJob
{
public:
CGCLoanerRequestResponse( GCSDK::CGCClient *pClient ) : GCSDK::CGCClientJob( pClient ) {}
virtual bool BYieldingRunGCJob( GCSDK::IMsgNetPacket *pNetPacket )
{
GCSDK::CProtoBufMsg<CMsgGCQuestObjective_RequestLoanerResponse> msg( pNetPacket );
// Show them the items they just got loaned!
InventoryManager()->ShowItemsPickedUp( true, false );
return true;
}
};
GC_REG_JOB( GCSDK::CGCClient, CGCLoanerRequestResponse, "CGCLoanerRequestResponse", k_EMsgGCQuestObjective_RequestLoanerResponse, GCSDK::k_EServerTypeGCClient );