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.
 
 
 
 
 
 

1539 lines
50 KiB

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "class_loadout_panel.h"
#include "c_tf_player.h"
#include "vgui_controls/CheckButton.h"
#include "econ_gcmessages.h"
#include "gc_clientsystem.h"
#include "tf_item_system.h"
#include "loadout_preset_panel.h"
#include "econ_item_description.h"
#include "item_style_select_dialog.h"
#include "vgui/IInput.h"
#include "vgui_controls/PanelListPanel.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
extern ConVar tf_respawn_on_loadoutchanges;
ConVar tf_show_preset_explanation_in_class_loadout( "tf_show_preset_explanation_in_class_loadout", "1", FCVAR_HIDDEN | FCVAR_CLIENTDLL | FCVAR_ARCHIVE );
ConVar tf_show_taunt_explanation_in_class_loadout( "tf_show_taunt_explanation_in_class_loadout", "1", FCVAR_HIDDEN | FCVAR_CLIENTDLL | FCVAR_ARCHIVE );
void ParticleSlider_UpdateRequest( int iLoadoutPosition, float value )
{
CClassLoadoutPanel *pPanel = g_pClassLoadoutPanel;
if ( !pPanel )
return;
CEconItemView *pHat = pPanel->GetItemInSlot( iLoadoutPosition );
if ( !pHat )
return;
// does this hat even have a particle effect
static CSchemaAttributeDefHandle pAttrDef_AttachParticleEffect( "attach particle effect" );
uint32 iHasEffect = 0;
if ( !pHat->FindAttribute( pAttrDef_AttachParticleEffect, &iHasEffect ) )
return;
// Check for use head toggle
static CSchemaAttributeDefHandle pAttrDef_UseHeadOrigin( "particle effect use head origin" );
uint32 iUseHead = 0;
if ( !pHat->FindAttribute( pAttrDef_UseHeadOrigin, &iUseHead ) || iUseHead == 0 )
return;
// Look for the attribute and request to change it
static CSchemaAttributeDefHandle pAttrDef_VerticalOffset( "particle effect vertical offset" );
uint32 iOffSet = 0;
if ( !pHat->FindAttribute( pAttrDef_VerticalOffset, &iOffSet ) && value == 0 )
{
return;
}
else
{
const float& flAttrValue = (float&)iOffSet;
if ( value == flAttrValue )
return; // no change do nothing
}
// Send a message to the GC to request a change
GCSDK::CProtoBufMsg<CMsgSetItemEffectVerticalOffset> msg( k_EMsgGCSetItemEffectVerticalOffset );
msg.Body().set_item_id( pHat->GetItemID() );
msg.Body().set_offset( value );
GCClientSystem()->BSendMessage( msg );
}
void HatOffset_Callback( IConVar *pConVar, char const *pOldString, float flOldValue )
{
ConVarRef cVarRef( pConVar );
ParticleSlider_UpdateRequest( LOADOUT_POSITION_HEAD, cVarRef.GetFloat() );
}
ConVar tf_hat_effect_offset( "tf_hat_effect_offset", "0", FCVAR_DEVELOPMENTONLY, "Adjust the position of the unusual effect for your hat.", HatOffset_Callback );
void Misc1Offset_Callback( IConVar *pConVar, char const *pOldString, float flOldValue )
{
ConVarRef cVarRef( pConVar );
ParticleSlider_UpdateRequest( LOADOUT_POSITION_MISC, cVarRef.GetFloat() );
}
ConVar tf_misc1_effect_offset( "tf_misc1_effect_offset", "0", FCVAR_DEVELOPMENTONLY, "Adjust the position of the unusual effect for your hat.", Misc1Offset_Callback );
void Misc2Offset_Callback( IConVar *pConVar, char const *pOldString, float flOldValue )
{
ConVarRef cVarRef( pConVar );
ParticleSlider_UpdateRequest( LOADOUT_POSITION_MISC2, cVarRef.GetFloat() );
}
ConVar tf_misc2_effect_offset( "tf_misc2_effect_offset", "0", FCVAR_DEVELOPMENTONLY, "Adjust the position of the unusual effect for your hat.", Misc2Offset_Callback );
// Hacky solution to different classes wanting different slots visible in their loadouts, and in different positions
struct LoadoutPanelPositioningInstance
{
int m_iPos[NUM_ITEM_PANELS_IN_LOADOUT];
};
bool IsTauntPanelPosition( int iButtonPos )
{
return iButtonPos >= 9 && iButtonPos <= 16;
}
const LoadoutPanelPositioningInstance g_DefaultLoadoutPanelPositioning =
{
{
1, // LOADOUT_POSITION_PRIMARY = 0,
2, // LOADOUT_POSITION_SECONDARY,
3, // LOADOUT_POSITION_MELEE,
0, // LOADOUT_POSITION_UTILITY, // STAGING ONLY
0, // LOADOUT_POSITION_BUILDING,
0, // LOADOUT_POSITION_PDA,
0, // LOADOUT_POSITION_PDA2,
5, // LOADOUT_POSITION_HEAD,
6, // LOADOUT_POSITION_MISC,
8, // LOADOUT_POSITION_ACTION,
7, // LOADOUT_POSITION_MISC2,
9, // LOADOUT_POSITION_TAUNT,
10, // LOADOUT_POSITION_TAUNT2,
11, // LOADOUT_POSITION_TAUNT3,
12, // LOADOUT_POSITION_TAUNT4,
13, // LOADOUT_POSITION_TAUNT5,
14, // LOADOUT_POSITION_TAUNT6,
15, // LOADOUT_POSITION_TAUNT7,
16, // LOADOUT_POSITION_TAUNT8,
#ifdef STAGING_ONLY
0, // LOADOUT_POSITION_PDA_ADDON1,
0, // LOADOUT_POSITION_PDA_ADDON2,
0, // LOADOUT_POSITION_PDA3,
//9, // LOADOUT_POSITION_MISC3,
//10, // LOADOUT_POSITION_MISC4,
//11, // LOADOUT_POSITION_MISC5,
//12, // LOADOUT_POSITION_MISC6,
//13, // LOADOUT_POSITION_MISC7,
//14, // LOADOUT_POSITION_MISC8,
//15, // LOADOUT_POSITION_MISC9,
//16, // LOADOUT_POSITION_MISC10,
0, // LOADOUT_POSITION_BUILDING2,
#endif // STAGING_ONLY
}
};
const LoadoutPanelPositioningInstance g_LoadoutPanelPositioning_Spy =
{
{
0, // LOADOUT_POSITION_PRIMARY = 0,
1, // LOADOUT_POSITION_SECONDARY,
2, // LOADOUT_POSITION_MELEE,
0, // LOADOUT_POSITION_UTILITY, // STAGING ONLY
4, // LOADOUT_POSITION_BUILDING, // sapper
0, // LOADOUT_POSITION_PDA, // disguise kit (Hidden)
3, // LOADOUT_POSITION_PDA2, // Watch
5, // LOADOUT_POSITION_HEAD,
6, // LOADOUT_POSITION_MISC,
8, // LOADOUT_POSITION_ACTION,
7, // LOADOUT_POSITION_MISC2,
9, // LOADOUT_POSITION_TAUNT,
10, // LOADOUT_POSITION_TAUNT2,
11, // LOADOUT_POSITION_TAUNT3,
12, // LOADOUT_POSITION_TAUNT4,
13, // LOADOUT_POSITION_TAUNT5,
14, // LOADOUT_POSITION_TAUNT6,
15, // LOADOUT_POSITION_TAUNT7,
16, // LOADOUT_POSITION_TAUNT8,
#ifdef STAGING_ONLY
0, // LOADOUT_POSITION_PDA_ADDON1,
0, // LOADOUT_POSITION_PDA_ADDON2,
0, // LOADOUT_POSITION_PDA3,
//9, // LOADOUT_POSITION_MISC3,
//10, // LOADOUT_POSITION_MISC4,
//11, // LOADOUT_POSITION_MISC5,
//12, // LOADOUT_POSITION_MISC6,
//13, // LOADOUT_POSITION_MISC7,
//14, // LOADOUT_POSITION_MISC8,
//15, // LOADOUT_POSITION_MISC9,
//16, // LOADOUT_POSITION_MISC10,
0, // LOADOUT_POSITION_BUILDING2,
#endif // STAGING_ONLY
}
};
const LoadoutPanelPositioningInstance g_LoadoutPanelPositioning_Engineer =
{
{
1, // LOADOUT_POSITION_PRIMARY = 0,
2, // LOADOUT_POSITION_SECONDARY,
3, // LOADOUT_POSITION_MELEE,
0, // LOADOUT_POSITION_UTILITY, // STAGING ONLY
0, // LOADOUT_POSITION_BUILDING,
4, // LOADOUT_POSITION_PDA,
0, // LOADOUT_POSITION_PDA2,
5, // LOADOUT_POSITION_HEAD,
6, // LOADOUT_POSITION_MISC,
8, // LOADOUT_POSITION_ACTION,
7, // LOADOUT_POSITION_MISC2,
9, // LOADOUT_POSITION_TAUNT,
10, // LOADOUT_POSITION_TAUNT2,
11, // LOADOUT_POSITION_TAUNT3,
12, // LOADOUT_POSITION_TAUNT4,
13, // LOADOUT_POSITION_TAUNT5,
14, // LOADOUT_POSITION_TAUNT6,
15, // LOADOUT_POSITION_TAUNT7,
16, // LOADOUT_POSITION_TAUNT8,
#ifdef STAGING_ONLY
17, // LOADOUT_POSITION_PDA_ADDON1,
18, // LOADOUT_POSITION_PDA_ADDON2,
0, // LOADOUT_POSITION_PDA3,
//9, // LOADOUT_POSITION_MISC3,
//10, // LOADOUT_POSITION_MISC4,
//11, // LOADOUT_POSITION_MISC5,
//12, // LOADOUT_POSITION_MISC6,
//13, // LOADOUT_POSITION_MISC7,
//14, // LOADOUT_POSITION_MISC8,
//15, // LOADOUT_POSITION_MISC9,
//16, // LOADOUT_POSITION_MISC10,
0, // LOADOUT_POSITION_BUILDING2,
#endif // STAGING_ONLY
}
};
const LoadoutPanelPositioningInstance *g_VisibleLoadoutSlotsPerClass[] =
{
&g_DefaultLoadoutPanelPositioning, // TF_CLASS_UNDEFINED
&g_DefaultLoadoutPanelPositioning, // TF_CLASS_SCOUT
&g_DefaultLoadoutPanelPositioning, // TF_CLASS_SNIPER
&g_DefaultLoadoutPanelPositioning, // TF_CLASS_SOLDIER
&g_DefaultLoadoutPanelPositioning, // TF_CLASS_DEMOMAN
&g_DefaultLoadoutPanelPositioning, // TF_CLASS_MEDIC
&g_DefaultLoadoutPanelPositioning, // TF_CLASS_HEAVYWEAPONS
&g_DefaultLoadoutPanelPositioning, // TF_CLASS_PYRO
&g_LoadoutPanelPositioning_Spy, // TF_CLASS_SPY
&g_LoadoutPanelPositioning_Engineer, // TF_CLASS_ENGINEER
};
COMPILE_TIME_ASSERT( ARRAYSIZE( g_VisibleLoadoutSlotsPerClass ) == TF_LAST_NORMAL_CLASS );
//-----------------------------------------------------------------------------
// Particle Effect Slider
//-----------------------------------------------------------------------------
CLoadoutItemOptionsPanel::CLoadoutItemOptionsPanel( Panel *parent, const char *pName ) : vgui::EditablePanel( parent, pName )
{
m_pHatParticleSlider = NULL;
m_pHatParticleUseHeadButton = NULL;
m_iCurrentClassIndex = -1;
m_eItemSlot = LOADOUT_POSITION_INVALID;
m_pListPanel = new vgui::PanelListPanel( this, "PanelListPanel" );
m_pListPanel->SetFirstColumnWidth( 0 );
m_pHatParticleSlider = new CCvarSlider( m_pListPanel, "HatParticleSlider" );
m_pHatParticleSlider->AddActionSignalTarget( this );
m_pHatParticleUseHeadButton = new vgui::CheckButton( m_pListPanel, "HatUseHeadCheckButton", "#GameUI_ParticleHatUseHead" );
m_pHatParticleUseHeadButton->AddActionSignalTarget( this );
m_pSetStyleButton = new CExButton( m_pListPanel, "SetStyleButton", "#TF_Item_SelectStyle" );
m_pSetStyleButton->AddActionSignalTarget( this );
}
//-----------------------------------------------------------------------------
void CLoadoutItemOptionsPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
LoadControlSettings( "resource/UI/ItemOptionsPanel.res" );
}
//-----------------------------------------------------------------------------
void CLoadoutItemOptionsPanel::PerformLayout( void )
{
BaseClass::PerformLayout();
m_pHatParticleSlider->SetTickColor( Color( 235, 226, 202, 255 ) ); // tanlight
}
//-----------------------------------------------------------------------------
void CLoadoutItemOptionsPanel::OnCommand( const char *command )
{
if ( FStrEq( command, "particle_button_clicked" ) )
{
UpdateItemOptionsUI();
return;
}
else if ( FStrEq( command, "particle_use_head_clicked" ) )
{
// Grab current hat
CEconItemView *pHat = TFInventoryManager()->GetItemInLoadoutForClass( m_iCurrentClassIndex, m_eItemSlot );
if ( !pHat )
return;
// does this hat even have a particle effect
static CSchemaAttributeDefHandle pAttrDef_AttachParticleEffect( "attach particle effect" );
uint32 iHasEffect = 0;
if ( !pHat->FindAttribute( pAttrDef_AttachParticleEffect, &iHasEffect ) )
return;
// Send a message to the GC to request a change
GCSDK::CProtoBufMsg<CMsgSetHatEffectUseHeadOrigin> msg( k_EMsgGCSetHatEffectUseHeadOrigin );
msg.Body().set_item_id( pHat->GetItemID() );
msg.Body().set_use_head( m_pHatParticleUseHeadButton->IsSelected() );
GCClientSystem()->BSendMessage( msg );
return;
}
else if ( FStrEq( command, "set_style" ) )
{
CEconItemView *pHat = TFInventoryManager()->GetItemInLoadoutForClass( m_iCurrentClassIndex, m_eItemSlot );
CStyleSelectDialog *pStyle = vgui::SETUP_PANEL( new CStyleSelectDialog( GetParent(), pHat ) );
if ( pStyle )
{
pStyle->Show();
}
}
}
//-----------------------------------------------------------------------------
void CLoadoutItemOptionsPanel::OnMessage( const KeyValues* pParams, vgui::VPANEL hFromPanel )
{
if ( FStrEq( pParams->GetName(), "SliderDragEnd" ) )
{
m_pHatParticleSlider->ApplyChanges();
}
BaseClass::OnMessage( pParams, hFromPanel );
}
//-----------------------------------------------------------------------------
void CLoadoutItemOptionsPanel::SetItemSlot( loadout_positions_t eItemSlot, int iClassIndex )
{
m_eItemSlot = eItemSlot;
m_iCurrentClassIndex = iClassIndex;
// Init the Slider based on the slot
const char * pszConVarName = NULL;
switch ( eItemSlot )
{
case LOADOUT_POSITION_HEAD :
pszConVarName = "tf_hat_effect_offset";
break;
case LOADOUT_POSITION_MISC :
pszConVarName = "tf_misc1_effect_offset";
break;
case LOADOUT_POSITION_MISC2 :
pszConVarName = "tf_misc2_effect_offset";
break;
default:
break;
}
if ( pszConVarName )
{
m_pHatParticleSlider->SetupSlider( -8, 8, pszConVarName, false );
}
m_pHatParticleSlider->SetTickColor( Color( 235, 226, 202, 255 ) ); // tanlight
m_pHatParticleSlider->SetTickCaptions( "", "" );
UpdateItemOptionsUI();
}
//-----------------------------------------------------------------------------
void CLoadoutItemOptionsPanel::UpdateItemOptionsUI()
{
if ( m_eItemSlot == LOADOUT_POSITION_INVALID )
return;
m_pListPanel->RemoveAll();
// Add controls for various item options
AddControlsParticleEffect();
AddControlsSetStyle();
// Bail if no controls added
if ( m_pListPanel->GetItemCount() == 0 )
{
// We should have some controls if we get to this point.
Assert( 0 );
SetVisible( false );
return;
}
// Resize the background and list panel to contain all the controls
int nVertPixels = m_pListPanel->ComputeVPixelsNeeded();
int nNewTall = Min( 200, nVertPixels );
m_pListPanel->SetTall( nNewTall );
SetTall( nNewTall );
InvalidateLayout( true, false );
}
//-----------------------------------------------------------------------------
void CLoadoutItemOptionsPanel::AddControlsParticleEffect( void ) const
{
m_pHatParticleUseHeadButton->SetVisible( false );
m_pHatParticleSlider->SetVisible( false );
CEconItemView *pItem = TFInventoryManager()->GetItemInLoadoutForClass( m_iCurrentClassIndex, m_eItemSlot );
if ( pItem )
{
// does this hat even have a particle effect
static CSchemaAttributeDefHandle pAttrDef_AttachParticleEffect( "attach particle effect" );
uint32 iValue = 0;
if ( pItem->FindAttribute( pAttrDef_AttachParticleEffect, &iValue ) )
{
m_pHatParticleUseHeadButton->SetVisible( true );
m_pListPanel->AddItem( NULL, m_pHatParticleUseHeadButton );
m_pListPanel->AddItem( NULL, m_pHatParticleSlider );
// Check for use head toggle
static CSchemaAttributeDefHandle pAttrDef_UseHeadOrigin( "particle effect use head origin" );
uint32 iUseHead = 0;
if ( pItem->FindAttribute( pAttrDef_UseHeadOrigin, &iUseHead ) && iUseHead > 0 )
{
m_pHatParticleSlider->SetVisible( true );
m_pHatParticleUseHeadButton->SetSelected( true );
m_pHatParticleSlider->SetTickColor( Color( 235, 226, 202, 255 ) ); // tanlight
m_pHatParticleSlider->Repaint();
// Get offset if it exists
static CSchemaAttributeDefHandle pAttrDef_VerticalOffset( "particle effect vertical offset" );
uint32 iOffset = 0;
if ( pItem->FindAttribute( pAttrDef_VerticalOffset, &iOffset ) )
{
m_pHatParticleSlider->SetSliderValue( (float&)iOffset );
}
}
else
{
m_pHatParticleUseHeadButton->SetSelected( false );
}
}
}
}
//-----------------------------------------------------------------------------
void CLoadoutItemOptionsPanel::AddControlsSetStyle( void ) const
{
m_pSetStyleButton->SetVisible( false );
CEconItemView *pItem = GetItem();
if ( pItem && pItem->GetStaticData()->GetNumStyles() )
{
m_pSetStyleButton->SetVisible( true );
m_pListPanel->AddItem( NULL, m_pSetStyleButton );
}
}
//-----------------------------------------------------------------------------
CEconItemView* CLoadoutItemOptionsPanel::GetItem( void ) const
{
return TFInventoryManager()->GetItemInLoadoutForClass( m_iCurrentClassIndex, m_eItemSlot );
}
CClassLoadoutPanel *g_pClassLoadoutPanel = NULL;
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CClassLoadoutPanel::CClassLoadoutPanel( vgui::Panel *parent )
: CBaseLoadoutPanel( parent, "class_loadout_panel" )
, m_pItemOptionPanelKVs( NULL )
{
m_iCurrentClassIndex = TF_CLASS_UNDEFINED;
m_iCurrentTeamIndex = TF_TEAM_RED;
m_iCurrentSlotIndex = -1;
m_pPlayerModelPanel = NULL;
m_pSelectionPanel = NULL;
m_pTauntHintLabel = NULL;
m_pTauntLabel = NULL;
m_pTauntCaratLabel = NULL;
m_pPassiveAttribsLabel = NULL;
m_pLoadoutPresetPanel = NULL;
m_pPresetsExplanationPopup = NULL;
m_pTauntsExplanationPopup = NULL;
m_pBuildablesButton = NULL;
m_pCharacterLoadoutButton = NULL;
m_pTauntLoadoutButton = NULL;
m_bInTauntLoadoutMode = false;
g_pClassLoadoutPanel = this;
m_pItemOptionPanel = new CLoadoutItemOptionsPanel( this, "ItemOptionsPanel" );
}
CClassLoadoutPanel::~CClassLoadoutPanel()
{
if ( m_pItemOptionPanelKVs )
{
m_pItemOptionPanelKVs->deleteThis();
m_pItemOptionPanelKVs = NULL;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
{
LoadControlSettings( "Resource/UI/ClassLoadoutPanel.res" );
BaseClass::ApplySchemeSettings( pScheme );
m_pPlayerModelPanel = dynamic_cast<CTFPlayerModelPanel*>( FindChildByName("classmodelpanel") );
m_pTauntHintLabel = dynamic_cast<vgui::Label*>( FindChildByName("TauntHintLabel") );
m_pTauntLabel = dynamic_cast<CExLabel*>( FindChildByName("TauntLabel") );
m_pTauntCaratLabel = dynamic_cast<CExLabel*>( FindChildByName("TauntCaratLabel") );
m_pBuildablesButton = dynamic_cast<CExButton*>( FindChildByName("BuildablesButton") );
m_pCharacterLoadoutButton = dynamic_cast<CExImageButton*>( FindChildByName("CharacterLoadoutButton") );
m_pTauntLoadoutButton = dynamic_cast<CExImageButton*>( FindChildByName("TauntLoadoutButton") );
m_pPassiveAttribsLabel = dynamic_cast<CExLabel*>( FindChildByName("PassiveAttribsLabel") );
m_pLoadoutPresetPanel = dynamic_cast<CLoadoutPresetPanel*>( FindChildByName( "loadout_preset_panel" ) );
m_pPresetsExplanationPopup = dynamic_cast<CExplanationPopup*>( FindChildByName( "PresetsExplanation" ) );
m_pTauntsExplanationPopup = dynamic_cast<CExplanationPopup*>( FindChildByName( "TauntsExplanation" ) );
m_pTopLinePanel = FindChildByName( "TopLine" );
if ( m_pPassiveAttribsLabel )
{
m_pPassiveAttribsLabel->SetMouseInputEnabled( false );
}
m_pMouseOverTooltip->SetPositioningStrategy( IPTTP_BOTTOM_SIDE );
m_aDefaultColors[LOADED][FG][DEFAULT] = vgui::scheme()->GetIScheme( GetScheme() )->GetColor( "Econ.Button.PresetDefaultColorFg", Color( 255, 255, 255, 255 ) );
m_aDefaultColors[LOADED][FG][ARMED] = vgui::scheme()->GetIScheme( GetScheme() )->GetColor( "Econ.Button.PresetArmedColorFg", Color( 255, 255, 255, 255 ) );
m_aDefaultColors[LOADED][FG][DEPRESSED] = vgui::scheme()->GetIScheme( GetScheme() )->GetColor( "Econ.Button.PresetDepressedColorFg", Color( 255, 255, 255, 255 ) );
m_aDefaultColors[LOADED][BG][DEFAULT] = vgui::scheme()->GetIScheme( GetScheme() )->GetColor( "Econ.Button.PresetDefaultColorBg", Color( 255, 255, 255, 255 ) );
m_aDefaultColors[LOADED][BG][ARMED] = vgui::scheme()->GetIScheme( GetScheme() )->GetColor( "Econ.Button.PresetArmedColorBg", Color( 255, 255, 255, 255 ) );
m_aDefaultColors[LOADED][BG][DEPRESSED] = vgui::scheme()->GetIScheme( GetScheme() )->GetColor( "Econ.Button.PresetDepressedColorBg", Color( 255, 255, 255, 255 ) );
m_aDefaultColors[NOTLOADED][FG][DEFAULT] = vgui::scheme()->GetIScheme( GetScheme() )->GetColor( "Button.TextColor", Color( 255, 255, 255, 255 ) );
m_aDefaultColors[NOTLOADED][FG][ARMED] = vgui::scheme()->GetIScheme( GetScheme() )->GetColor( "Button.ArmedTextColor", Color( 255, 255, 255, 255 ) );
m_aDefaultColors[NOTLOADED][FG][DEPRESSED] = vgui::scheme()->GetIScheme( GetScheme() )->GetColor( "Button.DepressedTextColor", Color( 255, 255, 255, 255 ) );
m_aDefaultColors[NOTLOADED][BG][DEFAULT] = vgui::scheme()->GetIScheme( GetScheme() )->GetColor( "Button.BgColor", Color( 255, 255, 255, 255 ) );
m_aDefaultColors[NOTLOADED][BG][ARMED] = vgui::scheme()->GetIScheme( GetScheme() )->GetColor( "Button.ArmedBgColor", Color( 255, 255, 255, 255 ) );
m_aDefaultColors[NOTLOADED][BG][DEPRESSED] = vgui::scheme()->GetIScheme( GetScheme() )->GetColor( "Button.DepressedBgColor", Color( 255, 255, 255, 255 ) );
}
void CClassLoadoutPanel::ApplySettings( KeyValues *inResourceData )
{
BaseClass::ApplySettings( inResourceData );
KeyValues *pItemKV = inResourceData->FindKey( "itemoptionpanels_kv" );
if ( pItemKV )
{
if ( m_pItemOptionPanelKVs )
{
m_pItemOptionPanelKVs->deleteThis();
}
m_pItemOptionPanelKVs = new KeyValues("itemoptionpanels_kv");
pItemKV->CopySubkeys( m_pItemOptionPanelKVs );
}
#ifdef STAGING_ONLY
// PDA Panels
if ( m_pItemModelPanels.Count() > LOADOUT_POSITION_PDA_ADDON2 )
{
for ( int i = LOADOUT_POSITION_PDA_ADDON1; i <= LOADOUT_POSITION_PDA_ADDON2; i++ )
{
int wide = m_pItemModelPanels[i]->GetWide();
int tall = m_pItemModelPanels[i]->GetTall();
m_pItemModelPanels[i]->SetSize( wide / 2, tall / 2 );
m_pItemModelPanels[i]->InvalidateLayout();
}
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::PerformLayout( void )
{
BaseClass::PerformLayout();
// This is disabled by default in res file. IF we turn it on again, uncomment this.
/*if ( m_pPassiveAttribsLabel )
{
m_pPassiveAttribsLabel->SetVisible( !m_bInTauntLoadoutMode );
}*/
if ( m_pTauntHintLabel )
{
m_pTauntHintLabel->SetVisible( m_bInTauntLoadoutMode );
const char *key = engine->Key_LookupBinding( "taunt" );
if ( !key )
{
key = "< not bound >";
}
SetDialogVariable( "taunt", key );
}
if ( m_pTauntLabel )
{
m_pTauntLabel->SetVisible( m_bInTauntLoadoutMode );
}
if ( m_pTauntCaratLabel )
{
m_pTauntCaratLabel->SetVisible( m_bInTauntLoadoutMode );
}
if ( m_pCharacterLoadoutButton )
{
UpdatePageButtonColor( m_pCharacterLoadoutButton, !m_bInTauntLoadoutMode );
}
if ( m_pTauntLoadoutButton )
{
UpdatePageButtonColor( m_pTauntLoadoutButton, m_bInTauntLoadoutMode );
}
FOR_EACH_VEC( m_vecItemOptionButtons, i )
{
m_vecItemOptionButtons[i]->SetVisible( false );
}
for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
{
// Viewing a class loadout. Layout the buttons & the class image.
if ( i >= NUM_ITEM_PANELS_IN_LOADOUT )
{
m_pItemModelPanels[i]->SetVisible( false );
continue;
}
int iButtonPos = 0;
if ( m_iCurrentClassIndex != TF_CLASS_UNDEFINED )
{
iButtonPos = g_VisibleLoadoutSlotsPerClass[m_iCurrentClassIndex]->m_iPos[i];
}
bool bIsVisible = false;
if ( iButtonPos > 0 )
{
bIsVisible = m_bInTauntLoadoutMode ? IsTauntPanelPosition( iButtonPos ) : !IsTauntPanelPosition( iButtonPos );
}
m_pItemModelPanels[i]->SetVisible( bIsVisible );
if ( bIsVisible )
{
if ( m_bInTauntLoadoutMode )
{
iButtonPos -= g_VisibleLoadoutSlotsPerClass[m_iCurrentClassIndex]->m_iPos[LOADOUT_POSITION_TAUNT];
}
else
{
iButtonPos--;
}
#ifdef STAGING_ONLY
// Override for the PDA AddOnSlots
if ( i == LOADOUT_POSITION_PDA_ADDON1 )
{
int iYPos, iXPos;
m_pItemModelPanels[ LOADOUT_POSITION_PDA ]->GetPos( iXPos, iYPos );
int iWide, iTall;
m_pItemModelPanels[ LOADOUT_POSITION_PDA ]->GetSize( iWide, iTall );
m_pItemModelPanels[i]->SetPos( iXPos + iWide + XRES(1), iYPos );
m_pItemModelPanels[i]->SetSize( iWide / 2.1, iTall / 2.1 );
continue;
}
else if ( i == LOADOUT_POSITION_PDA_ADDON2 )
{
int iYPos, iXPos;
m_pItemModelPanels[LOADOUT_POSITION_PDA]->GetPos( iXPos, iYPos );
int iWide, iTall;
m_pItemModelPanels[LOADOUT_POSITION_PDA]->GetSize( iWide, iTall );
m_pItemModelPanels[i]->SetPos( iXPos + iWide + XRES(1), iYPos + iTall - (iTall / 2.1 ) );
m_pItemModelPanels[i]->SetSize( iWide / 2.1, iTall / 2.1 );
continue;
}
#endif
m_pItemModelPanels[i]->SetNoItemText( ItemSystem()->GetItemSchema()->GetLoadoutStringsForDisplay( EEquipType_t::EQUIP_TYPE_CLASS )[i] );
int iCenter = GetWide() * 0.5;
int iColumnHeight = 4;
int iColumn = iButtonPos / iColumnHeight;
int iYButtonPos = iButtonPos % iColumnHeight;
int iOffset = iColumn == 0 ? m_iItemXPosOffcenterA : m_iItemXPosOffcenterB + ((iColumn - 1) * 200);
int iXPos = iCenter + iOffset;
int iYPos = m_iItemYPos + (m_iItemYDelta * iYButtonPos);
m_pItemModelPanels[i]->SetPos( iXPos, iYPos );
// Update position and visibility of the item option buttons
if ( i < m_vecItemOptionButtons.Count() )
{
// Place the button just inside the item model panel
CExButton* pItemOptionsPanel = m_vecItemOptionButtons[iButtonPos];
int iButtonWide = m_pItemModelPanels[i]->GetWide();
int iMyWide = pItemOptionsPanel->GetWide();
int iOptionsXPos = iColumn == 0
? iXPos + iButtonWide - iMyWide
: iXPos;
pItemOptionsPanel->SetPos( iOptionsXPos, iYPos );
CEconItemView *pItemData = TFInventoryManager()->GetItemInLoadoutForClass( m_iCurrentClassIndex, i );
// Enable or disable the item options button for this item model panel
pItemOptionsPanel->SetVisible( !m_bInTauntLoadoutMode && AnyOptionsAvailableForItem( pItemData ) );
pItemOptionsPanel->SetCommand( CFmtStr( "options%d", i ) );
}
}
m_pItemModelPanels[ i ]->SetSelected( false );
}
if ( m_pLoadoutPresetPanel )
{
m_pLoadoutPresetPanel->SetPos( ( ScreenWidth() - m_pLoadoutPresetPanel->GetWide() ) / 2, m_iItemYPos );
}
LinkModelPanelControllerNavigation( true );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::OnKeyCodePressed( vgui::KeyCode code )
{
// See if the preset control uses this key
if( m_pLoadoutPresetPanel->HandlePresetKeyPressed( code ) )
{
return;
}
ButtonCode_t nButtonCode = GetBaseButtonCode( code );
if (nButtonCode == KEY_XBUTTON_LEFT ||
nButtonCode == KEY_XSTICK1_LEFT ||
nButtonCode == KEY_XSTICK2_LEFT ||
nButtonCode == STEAMCONTROLLER_DPAD_LEFT ||
code == KEY_LEFT ||
nButtonCode == KEY_XBUTTON_RIGHT ||
nButtonCode == KEY_XSTICK1_RIGHT ||
nButtonCode == KEY_XSTICK2_RIGHT ||
nButtonCode == STEAMCONTROLLER_DPAD_RIGHT ||
code == KEY_RIGHT ||
nButtonCode == KEY_XBUTTON_UP ||
nButtonCode == KEY_XSTICK1_UP ||
nButtonCode == KEY_XSTICK2_UP ||
nButtonCode == STEAMCONTROLLER_DPAD_UP ||
code == KEY_UP ||
nButtonCode == KEY_XBUTTON_DOWN ||
nButtonCode == KEY_XSTICK1_DOWN ||
nButtonCode == KEY_XSTICK2_DOWN ||
nButtonCode == STEAMCONTROLLER_DPAD_DOWN ||
code == KEY_DOWN )
{
// just eat all navigation keys so we don't
// end up with undesirable navigation behavior bubbling from
// one item model panel to another
}
else if( nButtonCode == KEY_XBUTTON_A || code == KEY_ENTER || nButtonCode == STEAMCONTROLLER_A )
{
// show the current loadout slot
int nSelected = GetFirstSelectedItemIndex( true );
if( nSelected != -1 )
{
OnCommand( VarArgs("change%d", nSelected ) );
}
}
else
{
BaseClass::OnKeyCodePressed( code );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::OnNavigateTo( const char* panelName )
{
CItemModelPanel *pChild = dynamic_cast<CItemModelPanel *>( FindChildByName( panelName ) );
if( !pChild )
return;
pChild->SetSelected( true );
SetBorderForItem( pChild, false );
pChild->RequestFocus();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::OnNavigateFrom( const char* panelName )
{
CItemModelPanel *pChild = dynamic_cast<CItemModelPanel *>( FindChildByName( panelName ) );
if( !pChild )
return;
pChild->SetSelected( false );
SetBorderForItem( pChild, false );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::OnShowPanel( bool bVisible, bool bReturningFromArmory )
{
if ( bVisible )
{
// always start in character loadout page
SetLoadoutPage( CHARACTER_LOADOUT_PAGE );
if ( m_pSelectionPanel )
{
m_pSelectionPanel->SetVisible( false );
m_pSelectionPanel->MarkForDeletion();
m_pSelectionPanel = NULL;
}
m_iCurrentSlotIndex = TF_WPN_TYPE_PRIMARY;
if( m_pItemModelPanels.Count() && m_pItemModelPanels[0] )
{
m_pItemModelPanels[0]->SetSelected( true );
SetBorderForItem( m_pItemModelPanels[0], false );
}
m_bLoadoutHasChanged = false;
if ( tf_show_preset_explanation_in_class_loadout.GetBool() && m_pPresetsExplanationPopup )
{
m_pPresetsExplanationPopup->Popup();
tf_show_preset_explanation_in_class_loadout.SetValue( 0 );
}
else if ( tf_show_taunt_explanation_in_class_loadout.GetBool() && m_pTauntsExplanationPopup )
{
m_pTauntsExplanationPopup->Popup();
tf_show_taunt_explanation_in_class_loadout.SetValue( 0 );
}
ClearItemOptionsMenu();
}
else
{
if ( m_pPlayerModelPanel )
{
m_pPlayerModelPanel->ClearCarriedItems();
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::PostShowPanel( bool bVisible )
{
if ( bVisible )
{
if ( m_pPlayerModelPanel )
{
m_pPlayerModelPanel->SetVisible( true );
}
if ( m_pBuildablesButton )
{
m_pBuildablesButton->SetVisible( m_iCurrentClassIndex == TF_CLASS_ENGINEER );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::SetClass( int iClass )
{
m_iCurrentClassIndex = iClass;
if ( m_pLoadoutPresetPanel )
{
m_pLoadoutPresetPanel->SetClass( m_iCurrentClassIndex );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::SetTeam( int iTeam )
{
Assert( IsValidTFTeam( iTeam ) );
m_iCurrentTeamIndex = iTeam;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CClassLoadoutPanel::GetNumRelevantSlots() const
{
return m_pItemModelPanels.Count();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CEconItemView *CClassLoadoutPanel::GetItemInSlot( int iSlot )
{
if( iSlot >= 0 && iSlot < m_pItemModelPanels.Count() )
{
return m_pItemModelPanels[iSlot]->GetItem();
}
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::FireGameEvent( IGameEvent *event )
{
// If we're not visible, ignore all events
if ( !IsVisible() )
return;
BaseClass::FireGameEvent( event );
// We need to update ourselves after the base has done it, so our item models have been updated
const char *type = event->GetName();
if ( Q_strcmp( "inventory_updated", type ) == 0 )
{
if ( m_pPlayerModelPanel )
{
m_pPlayerModelPanel->HoldItemInSlot( m_iCurrentSlotIndex );
}
}
}
void CClassLoadoutPanel::AddNewItemPanel( int iPanelIndex )
{
BaseClass::AddNewItemPanel( iPanelIndex );
m_vecItemOptionButtons[ m_vecItemOptionButtons.AddToTail() ] = new CExButton( this,
CFmtStr( "item_options_button%d", iPanelIndex ),
"+",
this,
CFmtStr( "options%d", iPanelIndex ) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::UpdateModelPanels( void )
{
// Search for a Robot Costume
bool bIsRobot = false;
static CSchemaAttributeDefHandle pAttrDef_PlayerRobot( "appear as mvm robot" );
// For now, fill them out with the local player's currently wielded items
for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
{
CEconItemView *pItemData = TFInventoryManager()->GetItemInLoadoutForClass( m_iCurrentClassIndex, i );
if ( !pItemData )
continue;
if ( FindAttribute( pItemData, pAttrDef_PlayerRobot ) )
{
bIsRobot = true;
break;
}
}
// We're showing the loadout for a specific class.
TFPlayerClassData_t *pData = GetPlayerClassData( m_iCurrentClassIndex );
if ( m_pPlayerModelPanel )
{
m_pPlayerModelPanel->ClearCarriedItems();
m_pPlayerModelPanel->SetToPlayerClass( m_iCurrentClassIndex, bIsRobot );
m_pPlayerModelPanel->SetTeam( m_iCurrentTeamIndex );
}
// For now, fill them out with the local player's currently wielded items
for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
{
CEconItemView *pItemData = TFInventoryManager()->GetItemInLoadoutForClass( m_iCurrentClassIndex, i );
m_pItemModelPanels[i]->SetItem( pItemData );
m_pItemModelPanels[i]->SetShowQuantity( true );
m_pItemModelPanels[i]->SetSelected( false );
SetBorderForItem( m_pItemModelPanels[i], false );
if ( m_pPlayerModelPanel && pItemData && pItemData->IsValid() )
{
m_pPlayerModelPanel->AddCarriedItem( pItemData );
}
}
if ( m_pPlayerModelPanel )
{
m_pPlayerModelPanel->HoldItemInSlot( m_iCurrentSlotIndex );
}
SetDialogVariable( "loadoutclass", g_pVGuiLocalize->Find( pData->m_szLocalizableName ) );
UpdatePassiveAttributes();
// Now layout again to position our item buttons
InvalidateLayout();
if ( m_pItemOptionPanel->IsVisible() )
{
m_pItemOptionPanel->UpdateItemOptionsUI();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::OnItemPanelMouseReleased( vgui::Panel *panel )
{
CItemModelPanel *pItemPanel = dynamic_cast < CItemModelPanel * > ( panel );
if ( pItemPanel && IsVisible() )
{
for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
{
if ( m_pItemModelPanels[i] == pItemPanel )
{
OnCommand( VarArgs("change%d", i) );
return;
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::OnSelectionReturned( KeyValues *data )
{
if ( data )
{
uint64 ulIndex = data->GetUint64( "itemindex", INVALID_ITEM_ID );
// ulIndex implies do nothing (escape key)
if ( ulIndex != 0 )
{
TFInventoryManager()->EquipItemInLoadout( m_iCurrentClassIndex, m_iCurrentSlotIndex, ulIndex );
m_bLoadoutHasChanged = true;
UpdateModelPanels();
// Send the preset panel a msg so it can save the change
KeyValues *pLoadoutChangedMsg = new KeyValues( "LoadoutChanged" );
pLoadoutChangedMsg->SetInt( "slot", m_iCurrentSlotIndex );
pLoadoutChangedMsg->SetUint64( "itemid", ulIndex );
PostMessage( m_pLoadoutPresetPanel, pLoadoutChangedMsg );
}
}
PostMessage( GetParent(), new KeyValues("SelectionEnded") );
// It'll have deleted itself, so we don't need to clean it up
m_pSelectionPanel = NULL;
OnCancelSelection();
// find the selected item and give it the focus
CItemModelPanel *pSelection = GetFirstSelectedItemModelPanel( true );
if( !pSelection )
{
m_pItemModelPanels[0]->SetSelected( true );
pSelection = m_pItemModelPanels[0];
}
pSelection->RequestFocus();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::OnCancelSelection( void )
{
if ( m_pSelectionPanel )
{
m_pSelectionPanel->SetVisible( false );
m_pSelectionPanel->MarkForDeletion();
m_pSelectionPanel = NULL;
}
if ( m_pPlayerModelPanel )
{
m_pPlayerModelPanel->SetVisible( true );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::RespawnPlayer()
{
if ( tf_respawn_on_loadoutchanges.GetBool() )
{
// Tell the GC to tell server that we should respawn if we're in a respawn room
GCSDK::CGCMsg< MsgGCEmpty_t > msg( k_EMsgGCRespawnPostLoadoutChange );
GCClientSystem()->BSendMessage( msg );
}
}
//-----------------------------------------------------------------------------
// Purpose: Apply KVs to the item option buttons
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::ApplyKVsToItemPanels( void )
{
BaseClass::ApplyKVsToItemPanels();
if ( m_pItemOptionPanelKVs )
{
for ( int i = 0; i < m_vecItemOptionButtons.Count(); i++ )
{
m_vecItemOptionButtons[i]->ApplySettings( m_pItemOptionPanelKVs );
m_vecItemOptionButtons[i]->InvalidateLayout();
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::OnClosing( void )
{
if ( m_pPlayerModelPanel )
{
m_pPlayerModelPanel->ClearCarriedItems();
}
if ( m_bLoadoutHasChanged )
{
RespawnPlayer();
m_bLoadoutHasChanged = false;
}
}
extern const char *g_szItemBorders[AE_MAX_TYPES][5];
extern ConVar cl_showbackpackrarities;
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::SetBorderForItem( CItemModelPanel *pItemPanel, bool bMouseOver )
{
if ( !pItemPanel )
return;
const char *pszBorder = NULL;
if ( pItemPanel->IsGreyedOut() )
{
pszBorder = "EconItemBorder";
}
else
{
int iRarity = 0;
if ( pItemPanel->HasItem() && cl_showbackpackrarities.GetBool() )
{
iRarity = pItemPanel->GetItem()->GetItemQuality();
uint8 nRarity = pItemPanel->GetItem()->GetItemDefinition()->GetRarity();
if ( ( nRarity != k_unItemRarity_Any ) && ( iRarity != AE_SELFMADE ) )
{
// translate this quality to rarity
iRarity = nRarity + AE_RARITY_DEFAULT;
}
if ( iRarity > 0 )
{
if ( bMouseOver || pItemPanel->IsSelected() )
{
pszBorder = g_szItemBorders[iRarity][1];
}
else
{
pszBorder = g_szItemBorders[iRarity][0];
}
}
}
if ( iRarity == 0 )
{
if ( bMouseOver || pItemPanel->IsSelected() )
{
pszBorder = "LoadoutItemMouseOverBorder";
}
else
{
pszBorder = "EconItemBorder";
}
}
}
vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() );
pItemPanel->SetBorder( pScheme->GetBorder( pszBorder ) );
}
//-----------------------------------------------------------------------------
// Purpose: Clear the item options menu and reset the button that summoned it
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::ClearItemOptionsMenu( void )
{
SetOptionsButtonText( m_pItemOptionPanel->GetItemSlot(), "+" );
m_pItemOptionPanel->SetItemSlot( LOADOUT_POSITION_INVALID, m_iCurrentClassIndex );
m_pItemOptionPanel->SetVisible( false );
}
//-----------------------------------------------------------------------------
// Purpose: Safely set the text for a button
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::SetOptionsButtonText( int nIndex, const char* pszText )
{
if ( nIndex >= 0 && nIndex < m_vecItemOptionButtons.Count() )
{
m_vecItemOptionButtons[ m_pItemOptionPanel->GetItemSlot() ]->SetText( pszText );
}
}
//-----------------------------------------------------------------------------
// Purpose: Return if the passed in item has any options
//-----------------------------------------------------------------------------
bool CClassLoadoutPanel::AnyOptionsAvailableForItem( const CEconItemView *pItem )
{
if ( !pItem )
return false;
// Styles!
if ( pItem->GetStaticData()->GetNumSelectableStyles() > 1 )
return true;
// Unusual particle effect! For Cosmetics only
static CSchemaAttributeDefHandle pAttrDef_AttachParticleEffect( "attach particle effect" );
if ( pItem->FindAttribute( pAttrDef_AttachParticleEffect ) && pItem->GetItemDefinition()->GetLoadoutSlot( 0 ) >= LOADOUT_POSITION_HEAD )
return true;
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::SetLoadoutPage( classloadoutpage_t loadoutPage )
{
ClearItemOptionsMenu();
switch ( loadoutPage )
{
case CHARACTER_LOADOUT_PAGE:
{
m_bInTauntLoadoutMode = false;
}
break;
case TAUNT_LOADOUT_PAGE:
{
m_bInTauntLoadoutMode = true;
}
break;
default:
{
// Unhandled loadout page
Assert( 0 );
}
}
InvalidateLayout();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::OnCommand( const char *command )
{
if ( FStrEq( command, "characterloadout" ) )
{
SetLoadoutPage( CHARACTER_LOADOUT_PAGE );
return;
}
else if ( FStrEq( command, "tauntloadout" ) )
{
SetLoadoutPage( TAUNT_LOADOUT_PAGE );
return;
}
else if ( !V_strnicmp( command, "change", 6 ) )
{
const char *pszNum = command+6;
if ( pszNum && pszNum[0] )
{
int iSlot = atoi(pszNum);
if ( iSlot >= 0 && iSlot < CLASS_LOADOUT_POSITION_COUNT && m_iCurrentClassIndex != TF_CLASS_UNDEFINED )
{
if ( m_iCurrentSlotIndex != iSlot )
{
m_iCurrentSlotIndex = iSlot;
}
// Create the selection screen. It removes itself on close.
m_pSelectionPanel = new CEquipSlotItemSelectionPanel( this, m_iCurrentClassIndex, iSlot );
m_pSelectionPanel->ShowPanel( 0, true );
if ( m_pPlayerModelPanel )
{
m_pPlayerModelPanel->SetVisible( false );
}
ClearItemOptionsMenu();
PostMessage( GetParent(), new KeyValues("SelectionStarted") );
}
}
return;
}
else if ( !V_strnicmp( command, "options", 7 ) )
{
const char *pszNum = command + 7;
if( pszNum && pszNum[0] )
{
int iSlot = atoi( pszNum );
//iSlot = g_VisibleLoadoutSlotsPerClass[m_iCurrentClassIndex]->m_iPos[iSlot - 1];
if ( iSlot >= 0 && iSlot < m_vecItemOptionButtons.Count() && m_iCurrentClassIndex != TF_CLASS_UNDEFINED )
{
// Change the button we're coming from to be a "+"
SetOptionsButtonText( m_pItemOptionPanel->GetItemSlot(), "+" );
// Update the current slot index for callback from the setstyle button.
// It will send us a message to change the item the player model is holding
// and we need this to be updated for that.
m_iCurrentSlotIndex = iSlot;
// Did they just toggle?
if ( m_pItemOptionPanel->GetItemSlot() == iSlot )
{
m_pItemOptionPanel->SetVisible( !m_pItemOptionPanel->IsVisible() );
}
else
{
// Set the options panel to have the data for this slot
m_pItemOptionPanel->SetItemSlot( (loadout_positions_t)iSlot, m_iCurrentClassIndex );
m_pItemOptionPanel->SetVisible( true );
// Figure out if this is on the left or right
int iColumnHeight = 4;
int iColumn = iSlot / iColumnHeight;
PinCorner_e myCornerToPin = iColumn == 0 ? PIN_TOPLEFT : PIN_TOPRIGHT;
PinCorner_e siblingCornerPinTo = iColumn == 0 ? PIN_TOPRIGHT : PIN_TOPLEFT;
// Pin to the appropriate side
int iButtonPos = g_VisibleLoadoutSlotsPerClass[m_iCurrentClassIndex]->m_iPos[ iSlot ] - 1;
m_pItemOptionPanel->PinToSibling( m_vecItemOptionButtons[ iButtonPos ]->GetName(), myCornerToPin, siblingCornerPinTo );
m_pItemOptionPanel->UpdateItemOptionsUI();
}
// Change the button we're going to to be "-" if we're visible, "+" if we're not
SetOptionsButtonText( m_pItemOptionPanel->GetItemSlot(), m_pItemOptionPanel->IsVisible() ? "-" : "+" );
}
return;
}
}
BaseClass::OnCommand( command );
}
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::OnMessage( const KeyValues* pParams, vgui::VPANEL hFromPanel )
{
BaseClass::OnMessage( pParams, hFromPanel );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
struct passive_attrib_to_print_t
{
const CEconItemAttributeDefinition *m_pAttrDef;
attrib_value_t m_value;
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CAttributeIterator_AddPassiveAttribsToPassiveList : public CEconItemSpecificAttributeIterator
{
public:
CAttributeIterator_AddPassiveAttribsToPassiveList( CUtlVector<passive_attrib_to_print_t> *pList, bool bForceAdd )
: m_pList( pList )
, m_bForceAdd( bForceAdd )
{
Assert( m_pList );
}
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, attrib_value_t value )
{
Assert( pAttrDef );
if ( pAttrDef->IsHidden() )
return true;
if ( !m_bForceAdd )
{
const char *pDesc = pAttrDef->GetArmoryDescString();
if ( !pDesc || !pDesc[0] )
return true;
// If we have the "on_wearer" key, we're a passive attribute
if ( !Q_stristr(pDesc, "on_wearer") )
return true;
}
// Now see if we're already in the list
FOR_EACH_VEC( (*m_pList), i )
{
passive_attrib_to_print_t& passiveAttr = (*m_pList)[i];
Assert( passiveAttr.m_pAttrDef );
// We match if our class is the same -- this is a case-sensitive compare!
if ( Q_strcmp( passiveAttr.m_pAttrDef->GetAttributeClass(), pAttrDef->GetAttributeClass() ) )
continue;
// We've found a matching attribute. Collate our values and stomp over the earlier value.
passiveAttr.m_value = CollateAttributeValues( passiveAttr.m_pAttrDef, passiveAttr.m_value, pAttrDef, value );
return true;
}
// We didn't find it. Add it to the list.
passive_attrib_to_print_t newPassiveAttr = { pAttrDef, value };
m_pList->AddToTail( newPassiveAttr );
return true;
}
// Other types are ignored.
private:
CUtlVector<passive_attrib_to_print_t> *m_pList;
bool m_bForceAdd;
};
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::UpdatePassiveAttributes( void )
{
if ( !m_pPassiveAttribsLabel )
return;
// We build a list of attributes & associated values by looping through all equipped items.
// This way we can identify & collate attributes based on the same definition index.
CUtlVector<passive_attrib_to_print_t> vecAttribsToPrint;
// Loop through all equipped items
for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
{
CEconItemView *pItemData = TFInventoryManager()->GetItemInLoadoutForClass( m_iCurrentClassIndex, i );
if ( pItemData && pItemData->IsValid() )
{
CAttributeIterator_AddPassiveAttribsToPassiveList attrItPassives( &vecAttribsToPrint, false );
pItemData->IterateAttributes( &attrItPassives );
}
}
// Then add any set bonuses
if ( steamapicontext && steamapicontext->SteamUser() )
{
CSteamID localSteamID = steamapicontext->SteamUser()->GetSteamID();
CUtlVector<const CEconItemSetDefinition *> pActiveSets;
TFInventoryManager()->GetActiveSets( &pActiveSets, localSteamID, m_iCurrentClassIndex );
FOR_EACH_VEC( pActiveSets, set )
{
CAttributeIterator_AddPassiveAttribsToPassiveList attrItSetPassives( &vecAttribsToPrint, true );
pActiveSets[set]->IterateAttributes( &attrItSetPassives );
}
}
// Now build the text
wchar_t wszPassiveDesc[4096];
wszPassiveDesc[0] = '\0';
m_pPassiveAttribsLabel->GetTextImage()->ClearColorChangeStream();
wchar_t *pHeader = g_pVGuiLocalize->Find( "#TF_PassiveAttribs" );
if ( pHeader )
{
V_wcscpy_safe( wszPassiveDesc, pHeader );
V_wcscat_safe( wszPassiveDesc, L"\n" );
}
if ( vecAttribsToPrint.Count() )
{
FOR_EACH_VEC( vecAttribsToPrint, i )
{
CEconAttributeDescription AttrDesc( GLocalizationProvider(), vecAttribsToPrint[i].m_pAttrDef, vecAttribsToPrint[i].m_value );
AddAttribPassiveText( AttrDesc, wszPassiveDesc, ARRAYSIZE(wszPassiveDesc) );
}
}
else
{
vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() );
Color col = pScheme->GetColor( GetColorNameForAttribColor( ATTRIB_COL_NEUTRAL ), Color(255,255,255,255) );
m_pPassiveAttribsLabel->GetTextImage()->AddColorChange( col, Q_wcslen( wszPassiveDesc ) );
wchar_t *pNone = g_pVGuiLocalize->Find( "#TF_PassiveAttribs_None" );
if ( pNone )
{
V_wcscat_safe( wszPassiveDesc, pNone );
}
}
m_pPassiveAttribsLabel->SetText( wszPassiveDesc );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::AddAttribPassiveText( const CEconAttributeDescription& AttrDesc, INOUT_Z_CAP(iNumPassiveChars) wchar_t *out_wszPassiveDesc, int iNumPassiveChars )
{
vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() );
Assert( pScheme );
if ( !AttrDesc.GetDescription().IsEmpty() )
{
// Insert the color change at the current position
Color col = pScheme->GetColor( GetColorNameForAttribColor( AttrDesc.GetDefaultColor() ), Color(255,255,255,255) );
m_pPassiveAttribsLabel->GetTextImage()->AddColorChange( col, Q_wcslen( out_wszPassiveDesc ) );
// Now append the text of the attribute
V_wcsncat( out_wszPassiveDesc, AttrDesc.GetDescription().Get(), iNumPassiveChars );
V_wcsncat( out_wszPassiveDesc, L"\n", iNumPassiveChars );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClassLoadoutPanel::UpdatePageButtonColor( CExImageButton *pPageButton, bool bIsActive )
{
if ( pPageButton )
{
int iLoaded = bIsActive ? LOADED : NOTLOADED;
pPageButton->SetDefaultColor( m_aDefaultColors[iLoaded][FG][DEFAULT], m_aDefaultColors[iLoaded][BG][DEFAULT] );
pPageButton->SetArmedColor( m_aDefaultColors[iLoaded][FG][ARMED], m_aDefaultColors[iLoaded][BG][ARMED] );
pPageButton->SetDepressedColor( m_aDefaultColors[iLoaded][FG][DEPRESSED], m_aDefaultColors[iLoaded][BG][DEPRESSED] );
}
}