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.

1122 lines
38 KiB

5 years ago
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
#include "cbase.h"
#include "tf_hud_item_progress_tracker.h"
#include "iclientmode.h"
#include <vgui_controls/Label.h>
#include <vgui_controls/ImagePanel.h>
#include "gc_clientsystem.h"
#include "engine/IEngineSound.h"
#include "quest_log_panel.h"
#include "econ_controls.h"
#include "tf_item_inventory.h"
#include "c_tf_player.h"
#include "quest_objective_manager.h"
#include "tf_spectatorgui.h"
#include "econ_quests.h"
#include "inputsystem/iinputsystem.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
const float ATTRIB_TRACK_GLOW_HOLD_TIME = 2.f;
const float ATTRIB_TRACK_BAR_GROW_RATE = 0.3f;
const float ATTRIB_TRACK_COMPLETE_PULSE_RATE = 2.f;
const float ATTRIB_TRACK_COMPLETE_PULSE_DIM_HOLD = 0.3f;
const float ATTRIB_TRACK_COMPLETE_PULSE_GLOW_HOLD = 0.9f;
enum EContractHUDVisibility
{
CONTRACT_HUD_SHOW_NONE = 0,
CONTRACT_HUD_SHOW_EVERYTHING,
CONTRACT_HUD_SHOW_ACTIVE,
};
void cc_contract_progress_show_update( IConVar *pConVar, const char *pOldString, float flOldValue )
{
CHudItemAttributeTracker *pTrackerPanel = (CHudItemAttributeTracker *)GET_HUDELEMENT( CHudItemAttributeTracker );
if ( pTrackerPanel )
{
pTrackerPanel->InvalidateLayout();
}
}
ConVar tf_contract_progress_show( "tf_contract_progress_show", "1", FCVAR_CLIENTDLL | FCVAR_DONTRECORD | FCVAR_ARCHIVE, "Settings for the contract HUD element: 0 show nothing, 1 show everything, 2 show only active contracts.", cc_contract_progress_show_update );
ConVar tf_contract_competitive_show( "tf_contract_competitive_show", "2", FCVAR_CLIENTDLL | FCVAR_DONTRECORD | FCVAR_ARCHIVE, "Settings for the contract HUD element during competitive matches: 0 show nothing, 1 show everything, 2 show only active contracts.", cc_contract_progress_show_update );
EContractHUDVisibility GetContractHUDVisibility()
{
if ( TFGameRules() && TFGameRules()->IsMatchTypeCompetitive() )
return (EContractHUDVisibility)tf_contract_competitive_show.GetInt();
return (EContractHUDVisibility)tf_contract_progress_show.GetInt();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CItemAttributeProgressPanel::CItemAttributeProgressPanel( Panel* pParent, const char *pElementName, const CQuestObjectiveDefinition *pObjectiveDef, const char* pszResFileName )
: EditablePanel( pParent, pElementName )
, m_nDefIndex( pObjectiveDef->GetDefinitionIndex() )
, m_flUpdateTime( 0.f )
, m_flLastThink( 0.f )
, m_bAdvanced( pObjectiveDef->IsAdvanced() )
, m_strResFileName( pszResFileName )
{
Assert( !m_strResFileName.IsEmpty() );
m_pAttribBlur = new Label( this, "AttribBlur", "" );
m_pAttribGlow = new Label( this, "AttribGlow", "" );
m_pAttribDesc = new Label( this, "AttribDesc", "" );
REGISTER_COLOR_AS_OVERRIDABLE( m_enabledTextColor, "enabled_text_color_override" );
REGISTER_COLOR_AS_OVERRIDABLE( m_disabledTextColor, "disabled_text_color_override" );
// We're being set for the first time, instantly be progressed
m_pAttribBlur->SetAlpha( 0 );
m_pAttribGlow->SetAlpha( 0 );
m_flUpdateTime = Plat_FloatTime() - ATTRIB_TRACK_GLOW_HOLD_TIME;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItemAttributeProgressPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
LoadControlSettings( m_strResFileName );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItemAttributeProgressPanel::ApplySettings( KeyValues *inResourceData )
{
BaseClass::ApplySettings( inResourceData );
m_strNormalPointLocToken = inResourceData->GetString( "normal_token" );
m_strAdvancedLocToken = inResourceData->GetString( "advanced_token" );
const CQuestObjectiveDefinition *pObjectiveDef = GEconItemSchema().GetQuestObjectiveByDefIndex( m_nDefIndex );
if ( pObjectiveDef )
{
const char *pszDescriptionToken = pObjectiveDef->GetDescriptionToken();
locchar_t loc_ItemDescription[MAX_ITEM_NAME_LENGTH];
const locchar_t *pLocalizedObjectiveName = GLocalizationProvider()->Find( pszDescriptionToken );
if ( !pLocalizedObjectiveName || !pLocalizedObjectiveName[0] )
{
// Couldn't localize it, just use it raw
GLocalizationProvider()->ConvertUTF8ToLocchar( pszDescriptionToken, loc_ItemDescription, ARRAYSIZE( loc_ItemDescription ) );
}
else
{
locchar_t loc_IntermediateName[ MAX_ITEM_NAME_LENGTH ];
locchar_t locValue[ MAX_ITEM_NAME_LENGTH ];
loc_sprintf_safe( locValue, LOCCHAR( "%d" ), pObjectiveDef->GetPoints() );
loc_scpy_safe( loc_IntermediateName, CConstructLocalizedString( pLocalizedObjectiveName, locValue ) );
locchar_t *pszLocString = GLocalizationProvider()->Find( pObjectiveDef->IsAdvanced() ? m_strAdvancedLocToken : m_strNormalPointLocToken );
loc_scpy_safe( loc_ItemDescription, CConstructLocalizedString( pszLocString, loc_IntermediateName ) );
}
SetDialogVariable( "attr_desc", loc_ItemDescription );
}
//SetTall( GetContentTall() );
//m_pAttribDesc->SetTall( GetTall() );
InvalidateLayout();
}
void CItemAttributeProgressPanel::SetIsValid( bool bIsValid )
{
if ( bIsValid )
{
m_pAttribDesc->SetFgColor( m_enabledTextColor );
}
else
{
m_pAttribDesc->SetFgColor( m_disabledTextColor );
}
}
int CItemAttributeProgressPanel::GetContentTall() const
{
// Find the bottom of the text
int nTextWide = 0, nTextTall = 0;
m_pAttribDesc->GetContentSize( nTextWide, nTextTall );
int nTextYpos = m_pAttribDesc->GetYPos();
return nTextYpos + nTextTall;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItemAttributeProgressPanel::SetProgress( Color glowColor )
{
m_flUpdateTime = Plat_FloatTime();
m_pAttribBlur->SetAlpha( 255 );
m_pAttribGlow->SetAlpha( 255 );
m_pAttribDesc->SetAlpha( 0 );
m_pAttribBlur->SetFgColor( glowColor );
m_pAttribGlow->SetFgColor( glowColor );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItemAttributeProgressPanel::OnThink()
{
float flGlowTime = Plat_FloatTime() - m_flUpdateTime;
if ( flGlowTime > ATTRIB_TRACK_GLOW_HOLD_TIME )
{
float flGlowAlpha = RemapValClamped( flGlowTime, ATTRIB_TRACK_GLOW_HOLD_TIME, ATTRIB_TRACK_GLOW_HOLD_TIME + 0.25f, 1.f, 0.f );
m_pAttribBlur->SetAlpha( 255 * flGlowAlpha );
m_pAttribGlow->SetAlpha( 255 * flGlowAlpha );
m_pAttribDesc->SetAlpha( 255 * ( 1.f - flGlowAlpha ) );
}
m_flLastThink = Plat_FloatTime();
}
float CItemTrackerPanel::m_sflEventRecievedTime = 0.f;
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CItemTrackerPanel::CItemTrackerPanel( Panel* pParent, const char *pElementName, const CEconItem* pItem, const char* pszItemTrackerResFile )
: EditablePanel( pParent, pElementName )
, m_pItem( NULL )
, m_pCompletedContainer( NULL )
, m_pCompletedDescGlow( NULL )
, m_pCompletedNameGlow( NULL )
, m_flStandardTargetProgress( 0.f )
, m_flStandardCurrentProgress( 0.f )
, m_flBonusCurrentProgress( 0.f )
, m_flBonusTargetProgress( 0.f )
, m_flUpdateTime( 0.f )
, m_flLastThink( 0.f )
, m_nMaxStandardPoints( 0 )
, m_nMaxBonusPoints( 0 )
, m_eSoundToPlay( SOUND_NONE )
, m_nContentTall( 0 )
, m_bNoEffects( false )
, m_strItemTrackerResFile( pszItemTrackerResFile )
{
Assert( pszItemTrackerResFile );
SetItem( pItem );
ListenForGameEvent( "quest_objective_completed" );
ListenForGameEvent( "player_spawn" );
ListenForGameEvent( "inventory_updated" );
ListenForGameEvent( "localplayer_changeclass" );
ListenForGameEvent( "schema_updated" );
m_pItemName = new Label( this, "ItemName", "" );
m_pCompletedContainer = new EditablePanel( this, "CompletedContainer" );
m_pProgressBarBackground = new EditablePanel( this, "ProgressBarBG" );
m_pProgressBarStandard = new EditablePanel( m_pProgressBarBackground, "ProgressBarStandard" );
m_pProgressBarBonus = new EditablePanel( m_pProgressBarBackground, "ProgressBarBonus" );
m_pProgressBarStandardHighlight = new EditablePanel( m_pProgressBarBackground, "ProgressBarStandardHighlight" );
m_pProgressBarBonusHighlight = new EditablePanel( m_pProgressBarBackground, "ProgressBarBonusHighlight" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CItemTrackerPanel::~CItemTrackerPanel()
{}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItemTrackerPanel::ApplySettings( KeyValues *inResourceData )
{
BaseClass::ApplySettings( inResourceData );
m_strItemAttributeResFile = inResourceData->GetString( "item_attribute_res_file" );
m_strProgressBarStandardLocToken = inResourceData->GetString( "progress_bar_standard_loc_token" );
m_strProgressBarAdvancedLocToken = inResourceData->GetString( "progress_bar_advanced_loc_token" );
Assert( !m_strItemAttributeResFile.IsEmpty() );
Assert( !m_strProgressBarStandardLocToken.IsEmpty() );
Assert( !m_strProgressBarAdvancedLocToken.IsEmpty() );
m_strStandardObjectiveTick = inResourceData->GetString( "standard_objective_tick_sound", NULL );
m_strStandardPointsComplete = inResourceData->GetString( "standard_points_complete_sound", NULL );
m_strAdvancedObjectiveComplete = inResourceData->GetString( "advanced_objective_sound_complete", NULL );
m_strAdvancedPointsComplete = inResourceData->GetString( "advanced_points_complete_sound", NULL );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItemTrackerPanel::ApplySchemeSettings( IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
LoadControlSettings( m_strItemTrackerResFile );
m_pCompletedDescGlow = FindControl<Label>( "CompleteGlowText", true );
m_pCompletedNameGlow = FindControl<Label>( "CompleteItemNameGlow", true );
QuestObjectiveDefVec_t vecChosenObjectives;
if ( m_pItem )
{
m_pItem->GetItemDefinition()->GetQuestDef()->GetRolledObjectivesForItem( vecChosenObjectives, m_pItem->GetSOCData() );
}
FOR_EACH_VEC( vecChosenObjectives, i )
{
auto pObjective = vecChosenObjectives[ i ];
// Find or create the individual attribute panel
CItemAttributeProgressPanel *pPanel = GetPanelForObjective( pObjective );
pPanel->InvalidateLayout();
}
CaptureProgress();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int QuestSort_PointsAscending( CItemAttributeProgressPanel* const* p1, CItemAttributeProgressPanel* const* p2 )
{
const CQuestObjectiveDefinition* pObj1 = GEconItemSchema().GetQuestObjectiveByDefIndex( (*p1)->m_nDefIndex );
const CQuestObjectiveDefinition* pObj2 = GEconItemSchema().GetQuestObjectiveByDefIndex( (*p2)->m_nDefIndex );
if ( pObj1->GetPoints() != pObj2->GetPoints() )
{
// Smallest point value on the bottom
return pObj1->GetPoints() - pObj2->GetPoints();
}
return pObj1->GetDefinitionIndex() - pObj2->GetDefinitionIndex();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItemTrackerPanel::PerformLayout()
{
BaseClass::PerformLayout();
if ( !m_pItem )
return;
// Set the name into dialog variables
const wchar_t *pszLocToken = g_pVGuiLocalize->Find( m_pItem->GetItemDefinition()->GetQuestDef()->GetRolledNameForItem( m_pItem->GetSOCData() ) );
SetDialogVariable( "itemname", pszLocToken );
if ( m_pCompletedContainer )
{
m_pCompletedContainer->SetDialogVariable( "itemname", pszLocToken );
}
const CQuestItemTracker* pItemTracker = QuestObjectiveManager()->GetTypedTracker< CQuestItemTracker* >( m_pItem->GetItemID() );
if ( pItemTracker )
{
bool bStandardPointsCompleteAndBonusPossible = m_flStandardCurrentProgress == m_flStandardTargetProgress && m_flStandardTargetProgress == 1.f && m_nMaxBonusPoints > 0;
uint32 nCurrentPoints = bStandardPointsCompleteAndBonusPossible ? pItemTracker->GetEarnedBonusPoints() : pItemTracker->GetEarnedStandardPoints();
uint32 nTargetPoints = bStandardPointsCompleteAndBonusPossible ? m_nMaxBonusPoints : m_nMaxStandardPoints;
locchar_t locValue[ MAX_ITEM_NAME_LENGTH ];
const locchar_t *pPointsToken = GLocalizationProvider()->Find( bStandardPointsCompleteAndBonusPossible ? m_strProgressBarAdvancedLocToken : m_strProgressBarStandardLocToken );
loc_scpy_safe( locValue, CConstructLocalizedString( pPointsToken, nCurrentPoints, nTargetPoints ) );
m_pProgressBarBackground->SetDialogVariable( "points", locValue );
m_pProgressBarStandard->SetDialogVariable( "points" , locValue );
m_pProgressBarStandardHighlight->SetDialogVariable( "points" , locValue );
m_pProgressBarBonus->SetDialogVariable( "points", locValue );
m_pProgressBarBonusHighlight->SetDialogVariable( "points" , locValue );
}
else
{
m_pProgressBarBackground->SetDialogVariable( "points", "" );
m_pProgressBarStandard->SetDialogVariable( "points" , "" );
m_pProgressBarStandardHighlight->SetDialogVariable( "points" , "" );
m_pProgressBarBonus->SetDialogVariable( "points", "" );
m_pProgressBarBonusHighlight->SetDialogVariable( "points" , "" );
}
m_pProgressBarStandardHighlight->SetVisible( !m_bNoEffects );
m_pProgressBarBonusHighlight->SetVisible( !m_bNoEffects );
int nWide = 0, nTall = 0;
if ( m_pItemName->IsVisible() && !m_bNoEffects )
{
m_pItemName->GetContentSize( nWide, nTall );
}
int nX = m_nAttribXOffset;
int nY = nTall + m_nAttribYStartOffset;
bool bCompleted = true;
m_vecAttribPanels.Sort( &QuestSort_PointsAscending );
if ( !IsStandardCompleted() )
{
bCompleted = false;
}
m_pCompletedContainer->SetVisible( bCompleted );
if ( bCompleted && !m_bNoEffects )
{
m_pCompletedContainer->SetVisible( true );
CExLabel* pCompleted = m_pCompletedContainer->FindControl< CExLabel >( "CompleteDesc", true );
CExLabel* pCompletedGlow = m_pCompletedContainer->FindControl< CExLabel > ( "CompleteGlowText", true );
if ( pCompleted && pCompletedGlow )
{
const wchar_t *pszText = NULL;
const char *pszTextKey = "#QuestTracker_Complete";
if ( pszTextKey )
{
pszText = g_pVGuiLocalize->Find( pszTextKey );
}
if ( pszText )
{
wchar_t wzFinal[512] = L"";
UTIL_ReplaceKeyBindings( pszText, 0, wzFinal, sizeof( wzFinal ), GAME_ACTION_SET_FPSCONTROLS );
pCompleted->SetText( wzFinal );
pCompletedGlow->SetText( wzFinal );
}
}
nY = m_pCompletedContainer->GetTall();
}
else
{
m_pCompletedContainer->SetVisible( false );
}
// Place the bars at the bottom of the text, not the bottom of the text panel
m_pProgressBarBackground->SetPos( m_pProgressBarBackground->GetXPos(), nY );
nY += m_pProgressBarBackground->GetTall() + m_nBarGap;
UpdateBars();
C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
FOR_EACH_VEC( m_vecAttribPanels, i )
{
CItemAttributeProgressPanel* pPanel = m_vecAttribPanels[i];
// Hide all objectives if everything is completed, or just hide standard objectives is standard points re completed
if ( !m_bNoEffects && ( IsEverythingCompleted() || ( IsStandardCompleted() && !pPanel->IsAdvanced() ) ) )
{
pPanel->SetVisible( false );
}
else
{
pPanel->SetPos( nX, nY );
nY += pPanel->GetContentTall();
pPanel->SetVisible( true );
InvalidReasonsContainer_t invalidReasons;
if ( pItemTracker && pLocalPlayer )
{
// Fixup validity, which changes the color of the
const CBaseQuestObjectiveTracker* pObjectiveTracker = pItemTracker->FindTrackerForDefIndex( pPanel->m_nDefIndex );
if ( pObjectiveTracker )
{
pObjectiveTracker->IsValidForPlayer( pLocalPlayer, invalidReasons );
}
}
pPanel->SetIsValid( invalidReasons.IsValid() );
nY += m_nAttribYStep;
}
}
m_nContentTall = nY;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CItemTrackerPanel::GetContentTall() const
{
return m_nContentTall;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItemTrackerPanel::OnThink()
{
BaseClass::OnThink();
if ( !m_pItem || m_bNoEffects )
return;
static double s_flLastSoundTime = 0;
// Give a little time in case other messaes are in flight
if ( ( Plat_FloatTime() - m_sflEventRecievedTime ) > 0.1f )
{
// Dont play sounds very frequently
if ( m_eSoundToPlay != SOUND_NONE && ( ( Plat_FloatTime() - s_flLastSoundTime ) > 0.1f ) )
{
const char *pszSoundName = NULL;
// Figure out which sound to play
switch( m_eSoundToPlay )
{
case SOUND_STANDARD_OBJECTIVE_TICK:
pszSoundName = m_strStandardObjectiveTick;
break;
case SOUND_ADVANCED_OBJECTIVE_TICK:
pszSoundName = m_strAdvancedObjectiveComplete;
break;
case SOUND_QUEST_STANDARD_COMPLETE:
pszSoundName = m_strStandardPointsComplete;
break;
case SOUND_QUEST_ADVANCED_COMPLETE:
pszSoundName = m_strAdvancedPointsComplete;
break;
};
s_flLastSoundTime = Plat_FloatTime();
CLocalPlayerFilter filter;
C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, pszSoundName );
}
m_eSoundToPlay = SOUND_NONE;
}
// If the highlight is done, and the quest is ready to turn in, pulse a glow behind
// the title and the completion instruction
if ( IsDoneProgressing() && IsStandardCompleted() )
{
if ( m_pCompletedDescGlow && m_pCompletedNameGlow )
{
float flPeriod = ( sin( gpGlobals->curtime * ATTRIB_TRACK_COMPLETE_PULSE_RATE ) * 0.5f ) + 0.5f;
float flGlowAlpha = RemapValClamped( flPeriod, ATTRIB_TRACK_COMPLETE_PULSE_DIM_HOLD, ATTRIB_TRACK_COMPLETE_PULSE_GLOW_HOLD, 0.f, 1.f );
m_pCompletedDescGlow->SetAlpha( 255 * flGlowAlpha );
m_pCompletedNameGlow->SetAlpha( 255 * flGlowAlpha );
}
}
float flGlowTime = Plat_FloatTime() - m_flUpdateTime;
if ( flGlowTime > ATTRIB_TRACK_GLOW_HOLD_TIME && ( m_flStandardCurrentProgress != m_flStandardTargetProgress || m_flBonusCurrentProgress != m_flBonusTargetProgress ) )
{
float flDelta = Plat_FloatTime() - m_flLastThink;
m_flStandardCurrentProgress = Approach( m_flStandardTargetProgress, m_flStandardCurrentProgress, flDelta * ATTRIB_TRACK_BAR_GROW_RATE );
m_flBonusCurrentProgress = Approach( m_flBonusTargetProgress, m_flBonusCurrentProgress, flDelta * ATTRIB_TRACK_BAR_GROW_RATE );
// Resize/position the bars
UpdateBars();
// This happens when all the bars are all caught up
if ( IsDoneProgressing() )
{
InvalidateLayout();
}
}
if ( IsDoneProgressing() )
{
m_pProgressBarStandardHighlight->SetVisible( false );
m_pProgressBarBonusHighlight->SetVisible( false );
}
m_flLastThink = Plat_FloatTime();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItemTrackerPanel::FireGameEvent( IGameEvent *pEvent )
{
if ( FStrEq( pEvent->GetName(), "quest_objective_completed" ) )
{
itemid_t nIDLow = 0x00000000FFFFFFFF & (itemid_t)pEvent->GetInt( "quest_item_id_low" );
itemid_t nIDHi = 0xFFFFFFFF00000000 & (itemid_t)pEvent->GetInt( "quest_item_id_hi" ) << 32;
itemid_t nID = nIDLow | nIDHi;
if ( !m_pItem || m_pItem->GetItemID() != nID )
return;
// Capture whatever progress has happened
CaptureProgress();
uint32 nObjectiveDefIndex = pEvent->GetInt( "quest_objective_id" );
// Don't do sounds if there's no objective that made this progress
if ( nObjectiveDefIndex == (uint32)-1 )
return;
bool bAdvanced = false;
const CQuestObjectiveDefinition* pObjective = GEconItemSchema().GetQuestObjectiveByDefIndex( nObjectiveDefIndex );
if ( !pObjective )
return;
bAdvanced = pObjective->IsAdvanced();
const CQuestItemTracker* pItemTracker = QuestObjectiveManager()->GetTypedTracker< CQuestItemTracker* >( m_pItem->GetItemID() );
if ( pItemTracker )
{
const Color& glowColor = pItemTracker->GetEarnedStandardPoints() < m_nMaxStandardPoints ? m_clrStandardHighlight
: m_clrBonusHighlight;
FOR_EACH_VEC( m_vecAttribPanels, i )
{
if ( m_vecAttribPanels[i]->m_nDefIndex == nObjectiveDefIndex )
{
m_vecAttribPanels[i]->SetProgress( glowColor );
break;
}
}
// Check if it's time to play a sound
ESoundToPlay eNewSound = SOUND_NONE;
if ( m_flStandardCurrentProgress < m_flStandardTargetProgress && pItemTracker->GetEarnedStandardPoints() == m_nMaxStandardPoints )
{
eNewSound = SOUND_QUEST_STANDARD_COMPLETE;
}
else if ( m_flBonusCurrentProgress < m_flBonusTargetProgress && pItemTracker->GetEarnedBonusPoints() == m_nMaxBonusPoints )
{
eNewSound = SOUND_QUEST_ADVANCED_COMPLETE;
}
else if ( bAdvanced )
{
eNewSound = SOUND_ADVANCED_OBJECTIVE_TICK;
}
else
{
eNewSound = SOUND_STANDARD_OBJECTIVE_TICK;
}
// Priority will handle this for us
if ( eNewSound > m_eSoundToPlay )
{
m_eSoundToPlay = eNewSound;
if ( m_sflEventRecievedTime < Plat_FloatTime() )
{
m_sflEventRecievedTime = Plat_FloatTime();
}
}
}
}
else if ( FStrEq( pEvent->GetName(), "player_spawn" )
|| FStrEq( pEvent->GetName(), "inventory_updated" )
|| FStrEq( pEvent->GetName(), "localplayer_changeclass" ) )
{
InvalidateLayout();
}
else if ( FStrEq( pEvent->GetName(), "schema_updated" ) )
{
FOR_EACH_VEC( m_vecAttribPanels, i )
{
m_vecAttribPanels[ i ]->InvalidateLayout();
}
InvalidateLayout();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItemTrackerPanel::UpdateBars()
{
// Everything is relative to the background bar
int nWide = m_pProgressBarBackground->GetWide();
// Resize standard bar
m_pProgressBarStandard->SetWide( floor(m_flStandardCurrentProgress * nWide ) );
// Resize bonus bar
m_pProgressBarBonus->SetWide( floor(m_flBonusCurrentProgress * nWide ) );
// Highlight bars snap to the target width
m_pProgressBarStandardHighlight->SetWide( floor(m_flStandardTargetProgress * nWide) );
m_pProgressBarBonusHighlight->SetWide( floor( m_flBonusTargetProgress * nWide ) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItemTrackerPanel::CaptureProgress()
{
if ( !m_pItem )
return;
const CQuestItemTracker* pItemTracker = QuestObjectiveManager()->GetTypedTracker< CQuestItemTracker* >( m_pItem->GetItemID() );
// Fixup bar bounds
float flStandardProgress = 0.f;
float flBonusProgress = 0.f;
if ( pItemTracker )
{
// We use the item trackers for quest progress since they're the most up-to-date
flStandardProgress = (float)pItemTracker->GetEarnedStandardPoints() / (float)( m_nMaxStandardPoints);
flBonusProgress = (float)pItemTracker->GetEarnedBonusPoints() / (float)( m_nMaxBonusPoints );
}
// Standard progress
bool bChange = flStandardProgress != m_flStandardTargetProgress;
m_flStandardTargetProgress = flStandardProgress;
// Bonus progress
bChange |= flBonusProgress != m_flBonusTargetProgress;
m_flBonusTargetProgress = flBonusProgress;
// We're being set for the first time, instantly be progressed
if ( m_flUpdateTime == 0.f || m_bNoEffects )
{
m_flStandardCurrentProgress = m_flStandardTargetProgress;
m_flBonusCurrentProgress = m_flBonusTargetProgress;
m_flUpdateTime = Plat_FloatTime() - ATTRIB_TRACK_GLOW_HOLD_TIME;
InvalidateLayout();
}
else if ( bChange ) // If this is a change, play effects
{
m_flUpdateTime = Plat_FloatTime();
InvalidateLayout();
}
m_pProgressBarStandardHighlight->SetVisible( !m_bNoEffects );
m_pProgressBarBonusHighlight->SetVisible( !m_bNoEffects );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CItemTrackerPanel::IsStandardCompleted() const
{
const CQuestItemTracker* pItemTracker = QuestObjectiveManager()->GetTypedTracker< CQuestItemTracker* >( m_pItem->GetItemID() );
if ( pItemTracker )
{
return pItemTracker->GetEarnedStandardPoints() >= m_nMaxStandardPoints;
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CItemTrackerPanel::IsEverythingCompleted() const
{
const CQuestItemTracker* pItemTracker = QuestObjectiveManager()->GetTypedTracker< CQuestItemTracker* >( m_pItem->GetItemID() );
if ( pItemTracker )
{
return ( pItemTracker->GetEarnedBonusPoints() + pItemTracker->GetEarnedStandardPoints() ) >= ( m_nMaxBonusPoints + m_nMaxStandardPoints );
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItemTrackerPanel::SetItem( const CEconItem* pItem )
{
m_pItem.SetItem( TFInventoryManager()->GetLocalTFInventory()->GetInventoryItemByItemID( pItem->GetItemID() ) );
m_nMaxStandardPoints = pItem->GetItemDefinition()->GetQuestDef()->GetMaxStandardPoints();
m_nMaxBonusPoints = pItem->GetItemDefinition()->GetQuestDef()->GetMaxBonusPoints();
InvalidateLayout();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CItemAttributeProgressPanel* CItemTrackerPanel::GetPanelForObjective( const CQuestObjectiveDefinition* pObjective )
{
FOR_EACH_VEC( m_vecAttribPanels, i )
{
if ( m_vecAttribPanels[ i ]->m_nDefIndex == pObjective->GetDefinitionIndex() )
return m_vecAttribPanels[ i ];
}
CItemAttributeProgressPanel *pPanel = new CItemAttributeProgressPanel( this, "ItemAttributeProgressPanel", pObjective, m_strItemAttributeResFile );
SETUP_PANEL( pPanel );
m_vecAttribPanels.AddToTail( pPanel );
return pPanel;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CItemTrackerPanel::IsValidForLocalPlayer() const
{
C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
CSteamID steamID;
if ( !pLocalPlayer || !pLocalPlayer->GetSteamID( &steamID ) )
return false;
Assert( m_pItem );
// Safeguard. There's a crash in public from this.
if ( !m_pItem )
return false;
const CQuestItemTracker* pItemTracker = QuestObjectiveManager()->GetTypedTracker< CQuestItemTracker* >( m_pItem->GetItemID() );
InvalidReasonsContainer_t invalidReasons;
if ( pItemTracker )
{
int nNumInvalid = pItemTracker->IsValidForPlayer( pLocalPlayer, invalidReasons );
if ( nNumInvalid < pItemTracker->GetTrackers().Count() )
{
return true;
}
}
// Check for completed quests. They are always visible.
CEconItemView *pItem = TFInventoryManager()->GetLocalTFInventory()->GetInventoryItemByItemID( m_pItem->GetItemID() );
if ( pItem && IsQuestItemReadyToTurnIn( pItem ) && GetContractHUDVisibility() == CONTRACT_HUD_SHOW_EVERYTHING )
{
return true;
}
return false;
}
DECLARE_HUDELEMENT( CHudItemAttributeTracker );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CHudItemAttributeTracker::CHudItemAttributeTracker( const char *pElementName )
: CHudElement( pElementName )
, EditablePanel( NULL, "ItemAttributeTracker" )
, m_mapTrackers( DefLessFunc( itemid_t ) )
{
Panel *pParent = g_pClientMode->GetViewport();
SetParent( pParent );
ListenForGameEvent( "player_spawn" );
ListenForGameEvent( "inventory_updated" );
ListenForGameEvent( "client_disconnect" );
ListenForGameEvent( "localplayer_changeclass" );
ListenForGameEvent( "quest_objective_completed" );
RegisterForRenderGroup( "weapon_selection" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudItemAttributeTracker::ApplySchemeSettings( IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
LoadControlSettings( "resource/UI/HudItemAttributeTracker.res" );
m_pStatusContainer = FindControl< EditablePanel >( "QuestsStatusContainer" );
m_pStatusHeaderLabel = m_pStatusContainer->FindControl< Label >( "Header" );
m_pCallToActionLabel = m_pStatusContainer->FindControl< Label >( "CallToAction" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudItemAttributeTracker::PerformLayout()
{
BaseClass::PerformLayout();
CUtlVector<CEconItemView*> vecQuestItems;
TFInventoryManager()->GetAllQuestItems( &vecQuestItems );
int nNumCompleted = 0;
int nNumUnidentified = 0;
int nNumInactive = 0;
C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
FOR_EACH_VEC( vecQuestItems, i )
{
const CEconItemView* pItem = vecQuestItems[i];
if ( IsQuestItemReadyToTurnIn( pItem ) )
{
++nNumCompleted;
}
else if ( IsQuestItemUnidentified( pItem->GetSOCData() ) )
{
++nNumUnidentified;
}
else if ( pLocalPlayer )
{
const CQuestItemTracker* pItemTracker = QuestObjectiveManager()->GetTypedTracker< CQuestItemTracker* >( pItem->GetItemID() );
InvalidReasonsContainer_t invalidReasons;
if ( pItemTracker )
{
if ( pItemTracker->IsValidForPlayer( pLocalPlayer, invalidReasons ) == pItemTracker->GetTrackers().Count() )
{
++nNumInactive;
}
}
}
}
const char* pszHeaderString = NULL;
const char* pszCallToActionString = NULL;
int nNumToShow = 0;
if ( nNumCompleted > 0 )
{
nNumToShow = nNumCompleted;
pszHeaderString = nNumToShow == 1 ? "#QuestTracker_Complete_Single" : "#QuestTracker_Complete_Multiple";
pszCallToActionString = "QuestTracker_Complete";
}
else if ( nNumUnidentified > 0 )
{
nNumToShow = nNumUnidentified;
pszHeaderString = nNumToShow == 1 ? "#QuestTracker_New_Single" : "#QuestTracker_New_Multiple";
pszCallToActionString = "QuestTracker_New_CallToAction";
}
else if ( nNumInactive > 0 )
{
nNumToShow = nNumInactive;
pszHeaderString = nNumToShow == 1 ? "#QuestTracker_Inactive_Single" : "#QuestTracker_Inactive_Multiple";
pszCallToActionString = "QuestTracker_New_CallToAction";
}
bool bAnyStatusToShow = pszHeaderString != NULL;
bool bShowExtras = bAnyStatusToShow && ( GetContractHUDVisibility() != CONTRACT_HUD_SHOW_ACTIVE );
if ( bShowExtras )
{
// Build the "X New Contracts" string
locchar_t locNumNewQuests[ 256 ];
const locchar_t *pLocalizedString = GLocalizationProvider()->Find( pszHeaderString );
if ( pLocalizedString && pLocalizedString[0] )
{
wchar_t wszCounter[ 256 ];
loc_sprintf_safe( wszCounter, LOCCHAR( "%d" ), nNumToShow);
loc_scpy_safe( locNumNewQuests,
CConstructLocalizedString( pLocalizedString, wszCounter ) );
}
m_pStatusContainer->SetDialogVariable( "header", locNumNewQuests );
// Build the "Press [ F2 ] to view" string.
const wchar_t *pszText = NULL;
if ( pszCallToActionString )
{
pszText = g_pVGuiLocalize->Find( pszCallToActionString );
}
if ( pszText )
{
wchar_t wzFinal[512] = L"";
UTIL_ReplaceKeyBindings( pszText, 0, wzFinal, sizeof( wzFinal ), GAME_ACTION_SET_FPSCONTROLS );
m_pStatusContainer->SetDialogVariable( "call_to_action", wzFinal );
}
}
int nY = 0;
if ( m_pStatusContainer )
{
nY = m_pStatusContainer->GetYPos();
m_pStatusContainer->SetVisible( bShowExtras );
if ( m_pStatusContainer->IsVisible() )
{
nY += m_pStatusContainer->GetTall();
int nLabelWide, nLabelTall;
m_pStatusHeaderLabel->GetContentSize( nLabelWide, nLabelTall );
m_pStatusContainer->SetWide( m_nStatusBufferWidth + nLabelWide );
m_pStatusHeaderLabel->SetPos( m_pStatusContainer->GetWide() - m_pStatusHeaderLabel->GetWide(), m_pStatusHeaderLabel->GetYPos() );
m_pCallToActionLabel->SetPos( m_pStatusContainer->GetWide() - m_pCallToActionLabel->GetWide(), m_pCallToActionLabel->GetYPos() );
m_pStatusContainer->SetPos( m_pStatusContainer->GetParent()->GetWide() - m_pStatusContainer->GetWide(), m_pStatusContainer->GetYPos() );
}
}
FOR_EACH_MAP( m_mapTrackers, i )
{
CItemTrackerPanel* pPanel = m_mapTrackers[ i ];
if ( pPanel )
{
if ( pPanel->IsValidForLocalPlayer() )
{
int nTall = pPanel->GetContentTall();
pPanel->SetPos( GetWide() - pPanel->GetWide(), nY );
nY += nTall;
pPanel->SetVisible( true );
}
else
{
pPanel->SetVisible( false );
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudItemAttributeTracker::OnThink()
{
BaseClass::OnThink();
// If the specator GUI is up, we need to drop down a bit so that we're
// not on top of the death notices
int nY = g_pSpectatorGUI && g_pSpectatorGUI->IsVisible() ? g_pSpectatorGUI->GetTopBarHeight() : 0;
int nCurrentX, nCurrentY;
GetPos( nCurrentX, nCurrentY );
if ( nCurrentY != nY )
{
SetPos( nCurrentX, nY );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CHudItemAttributeTracker::ShouldDraw( void )
{
if ( engine->IsPlayingDemo() )
return false;
if ( GetContractHUDVisibility() == CONTRACT_HUD_SHOW_NONE )
return false;
if ( GetLocalPlayerTeam() < FIRST_GAME_TEAM )
return false;
if ( TFGameRules() )
{
if ( TFGameRules()->ShowMatchSummary() )
return false;
if ( TFGameRules()->GetRoundRestartTime() > -1.f )
{
float flTime = TFGameRules()->GetRoundRestartTime() - gpGlobals->curtime;
if ( flTime <= 10.f )
return false;
}
}
return CHudElement::ShouldDraw();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudItemAttributeTracker::FireGameEvent( IGameEvent *pEvent )
{
if ( FStrEq( pEvent->GetName(), "player_spawn" )
|| FStrEq( pEvent->GetName(), "inventory_updated" )
|| FStrEq( pEvent->GetName(), "client_disconnect" )
|| FStrEq( pEvent->GetName(), "localplayer_changeclass" )
|| FStrEq( pEvent->GetName(), "quest_objective_completed" ) )
{
InvalidateLayout();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudItemAttributeTracker::HandleSOEvent( const CSteamID & steamIDOwner, const CSharedObject *pObject, ETrackerHandling_t eHandling )
{
// We only care about items!
if( pObject->GetTypeID() != CEconItem::k_nTypeID )
return;
const CEconItem *pItem = (CEconItem *)pObject;
// We only care about quests
if ( pItem->GetItemDefinition()->GetQuestDef() == NULL )
return;
// We dont do anything with trackers for unidentified quests
if ( IsQuestItemUnidentified( pItem ) )
return;
CItemTrackerPanel* pTracker = NULL;
switch ( eHandling )
{
case TRACKER_CREATE:
case TRACKER_UPDATE:
FindTrackerForItem( pItem, &pTracker, true );
if ( pTracker )
{
pTracker->SetItem( pItem );
}
break;
case TRACKER_REMOVE:
FindTrackerForItem( pItem, &pTracker, false );
if ( pTracker )
{
m_mapTrackers.Remove( pItem->GetItemID() );
pTracker->MarkForDeletion();
}
break;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CHudItemAttributeTracker::FindTrackerForItem( const CEconItem* pItem, CItemTrackerPanel** ppTracker, bool bCreateIfNotFound )
{
(*ppTracker) = NULL;
bool bCreatedNew = false;
auto idx = m_mapTrackers.Find( pItem->GetItemID() );
if ( idx == m_mapTrackers.InvalidIndex() && bCreateIfNotFound )
{
(*ppTracker) = new CItemTrackerPanel( this
, "ItemTrackerPanel"
, pItem
, pItem->GetItemDefinition()->GetQuestDef()->GetQuestTheme()->GetInGameTrackerResFile() );
(*ppTracker)->InvalidateLayout( true, true );
m_mapTrackers.Insert( pItem->GetItemID(), (*ppTracker) );
bCreatedNew = true;
}
else if ( idx != m_mapTrackers.InvalidIndex() )
{
(*ppTracker) = m_mapTrackers[ idx ];
}
return bCreatedNew;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudItemAttributeTracker::LevelInit( void )
{
// We want to listen for our player's SO cache updates
if ( steamapicontext && steamapicontext->SteamUser() )
{
CSteamID steamID = steamapicontext->SteamUser()->GetSteamID();
GCClientSystem()->GetGCClient()->AddSOCacheListener( steamID, this );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudItemAttributeTracker::LevelShutdown( void )
{
if ( steamapicontext && steamapicontext->SteamUser() )
{
CSteamID steamID = steamapicontext->SteamUser()->GetSteamID();
GCClientSystem()->GetGCClient()->RemoveSOCacheListener( steamID, this );
}
}