//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: Scoreboard for MvM // // $NoKeywords: $ //============================================================================= #include "cbase.h" #include "tf_hud_mann_vs_machine_victory.h" #include "tf_playermodelpanel.h" #include "econ_item_inventory.h" #include "vgui/IInput.h" #include "vgui_controls/PanelListPanel.h" #include "tf_particlepanel.h" #include "engine/IEngineSound.h" #include "econ_notifications.h" #include "tf_hud_mann_vs_machine_status.h" #include "tf_lobby_server.h" using namespace vgui; extern const ConVar *sv_cheats; #define MVM_PLAYER_COUNT 6 #define SQUAD_SURPLUS_COUNT 6 //#define WAVE_SUMMARY_TOTAL_TIME 5.0f; #define CREDITS_COLLECTED_TIME 2.0f #define CREDITS_MISSED_TIME 1.0f #define CREDITS_BONUS_TIME 0.5f #define RATING_LABEL_TIME 0.5f #define RATING_SCORE_TIME 0.5f #define SHORT_TIME 0.5f #define RATING_LABEL_TIME 0.5f #define RATING_SCORE_TIME 0.5f #define WAIT_TIME 12.0f #define STARTING_LOOT_PAUSE_TIME 2.f // String constants that match variable names in .res files #define CREDITS_COLLECTED_STR "creditscollected" #define CREDITS_MISSED_STR "creditsmissed" #define CREDITS_BONUS_STR "creditbonus" #define YOUR_UPGRADES_STR "upgrades" #define YOUR_BUYBACKS_STR "buybacks" #define YOUR_BOTTLES_STR "bottles" #define RATING_LABEL_STR "ratinglabel" #define RATING_SCORE_STR "ratingscore" #ifdef STAGING_ONLY ConVar tf_mvm_fake_loot( "tf_mvm_fake_loot", "0" ); #endif extern const char *g_szItemBorders[AE_MAX_TYPES][5]; extern int g_iLegacyClassSelectWeaponSlots[TF_LAST_NORMAL_CLASS]; class CShowMannUpLootNotification : public CEconNotification { public: CShowMannUpLootNotification() { m_pObjective = TFObjectiveResource(); } virtual EType NotificationType() { return eType_AcceptDecline; } virtual bool BShowInGameElements() const OVERRIDE { return true; } virtual void Accept() OVERRIDE { CTFHudMannVsMachineStatus *pMannVsMachineStatus = GET_HUDELEMENT( CTFHudMannVsMachineStatus ); if ( pMannVsMachineStatus && TFObjectiveResource() ) { pMannVsMachineStatus->ReopenVictoryPanel(); } MarkForDeletion(); } virtual void Decline() OVERRIDE { MarkForDeletion(); } virtual void Trigger() OVERRIDE { Accept(); } virtual void UpdateTick() OVERRIDE { CTFHudMannVsMachineStatus *pMannVsMachineStatus = GET_HUDELEMENT( CTFHudMannVsMachineStatus ); if ( !pMannVsMachineStatus || !pMannVsMachineStatus->IsVisible() || m_pObjective != TFObjectiveResource() ) { MarkForDeletion(); } } static bool IsNotificationType( CEconNotification *pNotification ) { return dynamic_cast< CShowMannUpLootNotification *>( pNotification ) != NULL; } const C_TFObjectiveResource* m_pObjective; }; //----------------------------------------------------------------------------- // CVictoryPanel //----------------------------------------------------------------------------- DECLARE_BUILD_FACTORY( CVictoryPanel ); CVictoryPanel::CVictoryPanel( Panel *parent, const char *pName ) : vgui::EditablePanel( parent, pName ) , m_pHeaderContainer( NULL ) , m_pCreditContainerPanel( NULL ) , m_pTotalGameCreditSpendPanel( NULL ) , m_pTeamStatsContainerPanel( NULL) , m_pYourStatsContainerPanel( NULL) , m_pRatingContainerPanel( NULL) , m_pDoneButton( NULL) { SetMouseInputEnabled( true ); m_pDoneButton = new CExImageButton( this, "DoneButton", g_pVGuiLocalize->Find( "#DoneButton" ), this ); } //----------------------------------------------------------------------------- void CVictoryPanel::ApplySchemeSettings( IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme ); LoadControlSettings( "resource/UI/MvMVictoryPanel.res" ); m_pDoneButton->AddActionSignalTarget( GetParent() ); CExButton *pButton = dynamic_cast( FindChildByName("DoneButton") ); if ( pButton ) { pButton->AddActionSignalTarget( this ); } vgui::EditablePanel* pStatsContainer = dynamic_cast( FindChildByName("StatsContainer") ); if ( pStatsContainer ) { m_pHeaderContainer = dynamic_cast( pStatsContainer->FindChildByName("HeaderContainer") ); m_pCreditContainerPanel = dynamic_cast( pStatsContainer->FindChildByName("CreditContainer") ); m_pRatingContainerPanel = dynamic_cast( pStatsContainer->FindChildByName("RatingContainer") ); m_pTotalGameCreditSpendPanel = dynamic_cast( pStatsContainer->FindChildByName("TotalGameCreditSpendPanel") ); } if ( m_pCreditContainerPanel ) { m_pCreditContainerPanel->SetDialogVariable( "header", "" ); m_pCreditContainerPanel->SetDialogVariable( "rating", "" ); m_pCreditContainerPanel->SetDialogVariable( "ratingshadow", "" ); } if ( m_pTotalGameCreditSpendPanel ) { m_pTotalGameCreditSpendPanel->SetDialogVariable( "header", "" ); } } //----------------------------------------------------------------------------- void CVictoryPanel::OnTick( void ) { if ( m_eState == FINISHED ) return; m_fStateRunningTime += gpGlobals->curtime - m_fPreviousTick; m_fPreviousTick = gpGlobals->curtime; // Run through animation loop switch ( m_eState ) { case CREDITS_COLLECT: StateUpdateValue ( m_pCreditContainerPanel, CREDITS_COLLECTED_STR, CREDITS_COLLECTED_TIME, m_fStateRunningTime, CREDITS_MISSED, m_nCreditsCollected ); break; case CREDITS_MISSED: StateUpdateValue ( m_pCreditContainerPanel, CREDITS_MISSED_STR, CREDITS_MISSED_TIME, m_fStateRunningTime, CREDITS_BONUS, m_nCreditsMissed ); break; case CREDITS_BONUS: StateUpdateValue ( m_pCreditContainerPanel, CREDITS_BONUS_STR, CREDITS_BONUS_TIME, m_fStateRunningTime, YOUR_UPGRADES, m_nCreditBonus ); break; case YOUR_UPGRADES: StateUpdateValue ( m_pTotalGameCreditSpendPanel, YOUR_UPGRADES_STR, SHORT_TIME, m_fStateRunningTime, YOUR_BUYBACK, m_nYourUpgradeCredits ); break; case YOUR_BUYBACK: StateUpdateValue ( m_pTotalGameCreditSpendPanel, YOUR_BUYBACKS_STR, SHORT_TIME, m_fStateRunningTime, YOUR_BOTTLES, m_nYourBuybacksCredits ); break; case YOUR_BOTTLES: StateUpdateValue ( m_pTotalGameCreditSpendPanel, YOUR_BOTTLES_STR, SHORT_TIME, m_fStateRunningTime, RATING_LABEL, m_nYourBottlesCredits ); break; case RATING_LABEL: RatingLabelUpdate(); CheckState( RATING_LABEL_TIME, m_fStateRunningTime, RATING_SCORE ); break; case RATING_SCORE: RatingScoreUpdate(); CheckState( RATING_SCORE_TIME, m_fStateRunningTime, FINISHED ); break; default: break; } } //----------------------------------------------------------------------------- void CVictoryPanel::ResetVictoryPanel() { m_fStateRunningTime = 0; if ( m_pCreditContainerPanel ) { // Set all the values to empty strings m_pCreditContainerPanel->SetDialogVariable( CREDITS_COLLECTED_STR, "" ); m_pCreditContainerPanel->SetDialogVariable( CREDITS_MISSED_STR, "" ); m_pCreditContainerPanel->SetDialogVariable( CREDITS_BONUS_STR, "" ); } if ( m_pTotalGameCreditSpendPanel ) { m_pTotalGameCreditSpendPanel->SetDialogVariable( YOUR_UPGRADES_STR, "" ); m_pTotalGameCreditSpendPanel->SetDialogVariable( YOUR_BUYBACKS_STR, "" ); m_pTotalGameCreditSpendPanel->SetDialogVariable( YOUR_BOTTLES_STR, "" ); } if ( m_pRatingContainerPanel ) { m_pRatingContainerPanel->SetDialogVariable( RATING_LABEL_STR, "" ); m_pRatingContainerPanel->SetDialogVariable( RATING_SCORE_STR, "" ); } m_eState = CREDITS_COLLECT; m_fStateRunningTime = 0; m_fPreviousTick = gpGlobals->curtime; CaptureStats(); } //----------------------------------------------------------------------------- void CVictoryPanel::SetMapAndPopFile ( ) { // Map Name char szTempMapName[MAX_PATH]; Q_FileBase( engine->GetLevelName(), szTempMapName, sizeof ( szTempMapName ) ); wchar_t wszMapName[MAX_PATH]; g_pVGuiLocalize->ConvertANSIToUnicode( GetMapDisplayName( szTempMapName ), wszMapName, sizeof(wszMapName) ); char szTempName[MAX_PATH]; V_FileBase( TFObjectiveResource()->GetMvMPopFileName(), szTempName, sizeof( szTempName ) ); int iMissionIndex = GetItemSchema()->FindMvmMissionByName( szTempName ); wchar_t wszLocalizedSummary[ 256 ]; if ( GetItemSchema()->GetMvmMissions().IsValidIndex( iMissionIndex ) ) { const MvMMission_t &mission = GetItemSchema()->GetMvmMissions()[ iMissionIndex ]; g_pVGuiLocalize->ConstructString_safe( wszLocalizedSummary, L"%s1 : %s2", 2, wszMapName, g_pVGuiLocalize->Find( mission.m_sDisplayName.Get() ) ); } else { //Popfile wchar_t wszPopFileName[MAX_PATH]; g_pVGuiLocalize->ConvertANSIToUnicode( GetMapDisplayName(szTempName), wszPopFileName, sizeof(wszPopFileName) ); g_pVGuiLocalize->ConstructString_safe( wszLocalizedSummary, L"%s1 : %s2", 2, wszMapName, wszPopFileName ); } if ( m_pHeaderContainer ) { m_pHeaderContainer->SetDialogVariable( "header", wszLocalizedSummary ); m_pHeaderContainer->SetDialogVariable( "headershadow", wszLocalizedSummary ); } } //----------------------------------------------------------------------------- // Purpose : Save all the stats info incase they reset (Lvl reset) while this screen is active //----------------------------------------------------------------------------- void CVictoryPanel::CaptureStats() { CMannVsMachineStats *pStats = MannVsMachineStats_GetInstance(); if ( !pStats ) return; int nAcquired = pStats->GetAcquiredCredits( -1, false ); int nDropped = pStats->GetDroppedCredits( -1 ); int nMissed = nDropped - nAcquired; int nBonus = pStats->GetBonusCredits( -1 ); m_nCreditsCollected = nAcquired; m_nCreditsMissed = nMissed; m_nCreditBonus = nBonus; m_nYourBuybacksCredits = pStats->GetLocalPlayerBuyBackSpending( -1 ); m_nYourBottlesCredits = pStats->GetLocalPlayerBottleSpending( -1 ); m_nYourUpgradeCredits = pStats->GetLocalPlayerUpgradeSpending( -1 ); } //----------------------------------------------------------------------------- // Purpose: updates the target field based on the input args. Returns TRUE if transitioning to new state //----------------------------------------------------------------------------- bool CVictoryPanel::StateUpdateValue( vgui::EditablePanel *parent, char* field, float targetTime, float currentTime, int nextState, int endValue ) { float fPercent = currentTime / targetTime; fPercent = 1.0 < fPercent ? 1.0f : fPercent; int displayValue = (int)(endValue * fPercent); parent->SetDialogVariable( field, displayValue ); if ( displayValue != endValue ) { C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if ( pPlayer ) { pPlayer->EmitSound( "Credits.Updated" ); } } // transition to next state if ( fPercent >= 1.0f ) { m_fStateRunningTime = 0; m_eState = nextState; return true; } return false; } //----------------------------------------------------------------------------- // Purpose: updates the target field based on the input args. Returns TRUE if transitioning to new state // Adds "Credit" count text //----------------------------------------------------------------------------- bool CVictoryPanel::StateUpdateCreditText( vgui::EditablePanel *parent, char* field, float targetTime, float currentTime, int nextState, int useValue, int creditValue ) { float fPercent = currentTime / targetTime; fPercent = 1.0 < fPercent ? 1.0f : fPercent; int displayValue = (int)(useValue * fPercent); char szTmp[32]; Q_snprintf(szTmp, sizeof(szTmp), "%d (%d Credits)", displayValue, (int)(creditValue * fPercent)); parent->SetDialogVariable( field, szTmp ); if ( displayValue != useValue ) { C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if ( pPlayer ) { pPlayer->EmitSound( "Credits.Updated" ); } } // transition to next state if ( fPercent >= 1.0f ) { m_fStateRunningTime = 0; m_eState = nextState; return true; } return false; } //----------------------------------------------------------------------------- bool CVictoryPanel::CheckState( float targetTime, float currentTime, int nextState ) { if ( currentTime >= targetTime ) { m_fStateRunningTime = 0; m_eState = nextState; return true; } return false; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CVictoryPanel::RatingLabelUpdate( void ) { m_pRatingContainerPanel->SetDialogVariable( RATING_LABEL_STR, g_pVGuiLocalize->Find( "#TF_PVE_CreditRating" ) ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CVictoryPanel::RatingScoreUpdate( ) { //calc a score const char* pletterScore = "F"; float fPercent = (float)m_nCreditsCollected / (float)(m_nCreditsCollected + m_nCreditsMissed); if ( fPercent >= 1.0 ) { pletterScore = "A+"; } else if ( fPercent >= 0.9 ) { pletterScore = "A"; } else if ( fPercent >= 0.8 ) { pletterScore = "B"; } else if ( fPercent >= 0.7 ) { pletterScore = "C"; } else if ( fPercent >= 0.6 ) { pletterScore = "D"; } m_pRatingContainerPanel->SetDialogVariable( RATING_SCORE_STR, pletterScore ); } //----------------------------------------------------------------------------- // CMvMVictoryMannUpLoot //----------------------------------------------------------------------------- DECLARE_BUILD_FACTORY( CMvMVictoryMannUpLoot ); CMvMVictoryMannUpLoot::CMvMVictoryMannUpLoot( Panel *parent, const char *pName ): vgui::EditablePanel( parent, pName ) { m_pItemModelPanel = new CItemModelPanel( this, "EconItemModel" ); } //----------------------------------------------------------------------------- void CMvMVictoryMannUpLoot::ApplySchemeSettings( IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme ); LoadControlSettings( "resource/UI/MvMVictoryMannUpLoot.res" ); } //----------------------------------------------------------------------------- void CMvMVictoryMannUpLoot::SetEconItem ( CEconItem *econItem ) { if ( econItem != NULL ) { m_pItemModelPanel->SetEconItem( econItem ); m_pItemModelPanel->SetVisible( true ); } else { HideEconItem(); } } //----------------------------------------------------------------------------- void CMvMVictoryMannUpLoot::HideEconItem ( ) { m_pItemModelPanel->SetVisible( false ); } //----------------------------------------------------------------------------- void CMvMVictoryMannUpLoot::SetEconToolTip( CItemModelPanelToolTip *pToolTip) { m_pItemModelPanel->SetTooltip( pToolTip, "" ); } //----------------------------------------------------------------------------- DECLARE_BUILD_FACTORY( CMvMVictoryMannUpEntry ); CMvMVictoryMannUpEntry::CMvMVictoryMannUpEntry( Panel *parent, const char *pName ) : vgui::EditablePanel( parent, pName ) , m_LootLables( DefLessFunc(int) ) , m_pPlayerModelPanel( NULL ) , m_bHasData( false ) { m_bBadgeUpdated = false; m_iProgressWidthStart = 0; m_iProgressWidthEnd = 0; m_iLootAnimIndex = 0; m_flLootAnimTime = 0.f; m_pTourProgress = new EditablePanel( this, "TourProgress" ); m_pProgressBarBG = new EditablePanel( m_pTourProgress, "LevelProgressBarBG" ); m_pProgressBarFGAnim = new EditablePanel( m_pProgressBarBG, "LevelProgressBarFGAnim" ); m_pProgressBarFGStatic = new EditablePanel( m_pProgressBarBG, "LevelProgressBarFGStatic" ); m_pProgressCheckOnBackground = new EditablePanel( this, "MannUpTicketBackground" ); m_pProgressCheckOn = new vgui::ImagePanel( m_pProgressCheckOnBackground, "CompletedCheckOn" ); m_pSquadSurplusBackground = new EditablePanel( this, "SquadSurplusTicketBackground" ); m_pSquadSurplus = new vgui::ImagePanel( m_pSquadSurplusBackground, "SquadSurplus" ); m_pMissingVoucher = new vgui::Label( this, "MissingVoucher", "" ); #ifdef USE_MVM_TOUR m_nChallengeCount = 1; #else // new mm m_nMissionIndex = -1; #endif // USE_MVM_TOUR m_nItemColumns = 1; m_nItemXSpacing = 100; m_nItemYSpacing = 100; m_pItemModelPanelKVs = NULL; m_pRowKVs = NULL; m_pUnopenedLootKVs = NULL; m_pListPanel = new vgui::PanelListPanel( this, "PanelListPanel" ); m_pListPanel->SetVerticalBufferPixels( 0 ); m_pListPanel->SetFirstColumnWidth( 0 ); m_pPlayerModelPanel = new CTFPlayerModelPanel( this, "playermodelpanel" ); m_LootLables.Purge(); m_LootLables.Insert( CMsgMvMVictoryInfo_GrantReason_BADGE_LEVELED, new CExLabel( this, "TourOfDutyLabel", "" ) ); m_LootLables.Insert( CMsgMvMVictoryInfo_GrantReason_MANN_UP, new CExLabel( this, "MannUpLabel", "" ) ); m_LootLables.Insert( CMsgMvMVictoryInfo_GrantReason_SQUAD_SURPLUS, new CExLabel( this, "SquadSurplusLabel", "" ) ); m_LootLables.Insert( CMsgMvMVictoryInfo_GrantReason_HELP_A_NOOB, new CExLabel( this, "VeteranBonusLabel", "" ) ); m_pBehindItemParticlePanel = new CTFParticlePanel( this, "BehindItemParticlePanel" ); } CMvMVictoryMannUpEntry::~CMvMVictoryMannUpEntry() { // Dont let the list panel delete everything it owns. The labels and dividers // technically belong to this panel's buildgroup, which would cause a double free. m_pListPanel->RemoveAll(); ClearPlayerData(); if ( m_pItemModelPanelKVs ) { m_pItemModelPanelKVs->deleteThis(); m_pItemModelPanelKVs = NULL; } if ( m_pRowKVs ) { m_pRowKVs->deleteThis(); m_pRowKVs = NULL; } if ( m_pUnopenedLootKVs ) { m_pUnopenedLootKVs->deleteThis(); m_pUnopenedLootKVs = NULL; } } void CMvMVictoryMannUpEntry::ApplySettings( KeyValues *inResourceData ) { BaseClass::ApplySettings( inResourceData ); KeyValues *pItemKV = inResourceData->FindKey( "modelpanels_kv" ); if ( pItemKV ) { if ( m_pItemModelPanelKVs ) { m_pItemModelPanelKVs->deleteThis(); } m_pItemModelPanelKVs = new KeyValues( "modelpanels_kv" ); pItemKV->CopySubkeys( m_pItemModelPanelKVs ); } KeyValues *pRowKV = inResourceData->FindKey( "rowpanel_kvs" ); if ( pRowKV ) { if ( m_pRowKVs ) { m_pRowKVs->deleteThis(); } m_pRowKVs = new KeyValues( "rowpanel_kvs" ); pRowKV->CopySubkeys( m_pRowKVs ); } KeyValues *pUnopenedKV = inResourceData->FindKey( "unopenedPanel_kvs" ); if ( pUnopenedKV ) { if ( m_pUnopenedLootKVs ) { m_pUnopenedLootKVs->deleteThis(); } m_pUnopenedLootKVs = new KeyValues( "unopenedPanel_kvs" ); pUnopenedKV->CopySubkeys( m_pUnopenedLootKVs ); } m_nItemColumns = inResourceData->GetInt( "items_columns", 1 ); m_nItemXSpacing = inResourceData->GetInt( "items_xspacing", 100 ); m_nItemYSpacing = inResourceData->GetInt( "items_yspacing", 100 ); } //----------------------------------------------------------------------------- void CMvMVictoryMannUpEntry::ApplySchemeSettings( vgui::IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme ); // load control settings... LoadControlSettings( "resource/UI/MvMVictoryMannUpEntry.res" ); UpdatePlayerData(); } //----------------------------------------------------------------------------- void CMvMVictoryMannUpEntry::SetItemsToolTip( CItemModelPanelToolTip *pToolTip ) { FOR_EACH_VEC( m_vecLootPanels, i ) { m_vecLootPanels[i]->SetTooltip( pToolTip, "" ); } } //----------------------------------------------------------------------------- void CMvMVictoryMannUpEntry::ClearPlayerData ( ) { SetDialogVariable( "name", ""); if ( m_pSquadSurplus ) m_pSquadSurplus->SetVisible( false ); if ( m_pProgressCheckOn ) m_pProgressCheckOn->SetVisible( false ); m_pProgressBarBG->SetVisible( false ); m_pProgressBarFGAnim->SetVisible( false ); m_pProgressBarFGStatic->SetVisible( false ); m_pMissingVoucher->SetVisible( false ); ClearEconItems(); } //----------------------------------------------------------------------------- void CMvMVictoryMannUpEntry::UpdatePlayerData() { if ( !m_bHasData ) return; if ( steamapicontext == NULL ) return; m_pListPanel->RemoveAll(); CSteamID steamID = CSteamID( m_playerData.steam_id() ); m_hPlayer = GetPlayerBySteamID( steamID ); // Setup our model panel SetModelPanelInfo( ToTFPlayer( m_hPlayer ) ); SetDialogVariable( "name", steamapicontext->SteamFriends()->GetFriendPersonaName( steamID ) ); // Reset m_pProgressBarBG->SetVisible( true ); m_pProgressBarFGAnim->SetVisible( true ); m_pProgressBarFGStatic->SetVisible( true ); CheckBadgeLevel( m_playerData ); // Check Squad Surplus for this player CTFGSLobby *pLobby = GTFGCClientSystem()->GetLobby(); if ( pLobby ) { const CTFLobbyMember *pMember = pLobby->GetMemberDetails( steamID ); if ( pMember ) { m_pSquadSurplus->SetVisible( pMember->squad_surplus() ); } } #ifdef STAGING_ONLY if ( tf_mvm_fake_loot.GetBool() ) { m_pSquadSurplus->SetVisible( true ); } #endif // Loot ClearEconItems(); for( int i = 0; i < m_playerData.items_size(); ++i ) { m_vecLootPanels[ m_vecLootPanels.AddToTail() ] = new CMvMLootItem( this, VarArgs( "modelpanel%d", i ) ); } #ifdef STAGING_ONLY if ( tf_mvm_fake_loot.GetBool() ) { CPlayerInventory *pInventory = InventoryManager()->GetLocalInventory(); if ( !pInventory ) return; int nRandom = RandomInt(5,10); for( int i = 0; i < nRandom; ++i ) { m_vecLootPanels[ m_vecLootPanels.AddToTail() ] = new CMvMLootItem( this, VarArgs( "modelpanel%d", i ) ); CMvMLootItem* pLootItem = m_vecLootPanels.Tail(); pLootItem->m_eReason = (CMsgMvMVictoryInfo_GrantReason)RandomInt(1,3); CEconItemView *pItemView = pInventory->GetItem(i); CEconItem* econItem = new CEconItem(); econItem = pItemView->GetSOCData(); pLootItem->SetEconItem( econItem ); } } #endif for ( int iItem = 0; iItem < m_playerData.items_size(); ++iItem ) { const CMsgMvMVictoryInfo_Item& item = m_playerData.items( iItem ); CEconItem *pEconItem = new CEconItem(); m_MannUpEconItems.AddToTail( pEconItem ); if ( pEconItem->BParseFromMessage( item.item_data() ) ) { CMvMLootItem *pLootItem = m_vecLootPanels[ iItem ]; pLootItem->SetVisible( false ); pLootItem->SetEconItem( pEconItem ); pLootItem->m_eReason = item.grant_reason(); } else { delete pEconItem; } } // Put the items into a map for ordering them later on CUtlMap< int, CCopyableUtlVector > mapItems( DefLessFunc(int) ); FOR_EACH_VEC( m_vecLootPanels, i ) { int nIndex = mapItems.Find( m_vecLootPanels[i]->m_eReason ); if ( mapItems.InvalidIndex() == nIndex ) { nIndex = mapItems.Insert( m_vecLootPanels[i]->m_eReason ); } mapItems[ nIndex ].AddToTail( m_vecLootPanels[i] ); } bool bAnyThisRow = true; vgui::EditablePanel* pItemPanelRow = NULL; // The order of the categories int nCategories[] = { CMsgMvMVictoryInfo_GrantReason_MANN_UP , CMsgMvMVictoryInfo_GrantReason_SQUAD_SURPLUS , CMsgMvMVictoryInfo_GrantReason_BADGE_LEVELED }; // Put the panels into rows in the scrollable panel for( int nRow = 0; bAnyThisRow; ++nRow ) { bAnyThisRow = false; pItemPanelRow = NULL; for( int i = 0; i < ARRAYSIZE( nCategories ); i++ ) { int nMapKey = mapItems.Find( nCategories[i] ); if ( nMapKey == mapItems.InvalidIndex() ) continue; for( int nColumn = 0; nColumn < m_nItemColumns; ++nColumn ) { int nIndex = ( nRow * m_nItemColumns ) + nColumn; if ( nIndex < mapItems[ nMapKey ].Count() ) { bAnyThisRow = true; CMvMLootItem *pLootItem = mapItems[ nMapKey ][ nIndex ]; // Create a row if we need to if ( pItemPanelRow == NULL ) { pItemPanelRow = AddLootRow(); } Assert( pItemPanelRow ); pLootItem->SetParent( pItemPanelRow ); pLootItem->m_pUnopenedPanel->SetParent( pItemPanelRow ); pLootItem->m_nIndex = ( i * m_nItemColumns ) + nColumn; } } } } // Put all the items into our list in the order that we want to reveal them m_vecLootPanels.Purge(); for( int i = 0; i < ARRAYSIZE( nCategories ); i++ ) { int nMapKey = mapItems.Find( nCategories[i] ); if ( nMapKey == mapItems.InvalidIndex() ) continue; FOR_EACH_VEC( mapItems[ nMapKey ], j ) { m_vecLootPanels.AddToTail( mapItems[ nMapKey ][ j ] ); } } // We want at least 5 rows just to fill the space while( m_vecRows.Count() < 5 ) { AddLootRow(); } // If player's voucher has gone missing, indicate it m_pMissingVoucher->SetVisible( m_playerData.voucher_missing() ); // Lots of stuff changed InvalidateLayout(); } #ifdef USE_MVM_TOUR //----------------------------------------------------------------------------- void CMvMVictoryMannUpEntry::SetPlayerData( const CMsgMvMVictoryInfo_Player& player, int nMissionCount ) { m_nChallengeCount = nMissionCount; m_playerData = player; m_bHasData = true; UpdatePlayerData(); } #else // new mm //----------------------------------------------------------------------------- void CMvMVictoryMannUpEntry::SetPlayerData( const CMsgMvMVictoryInfo_Player& player, int nMissionIndex ) { m_nMissionIndex = nMissionIndex; m_playerData = player; m_bHasData = true; UpdatePlayerData(); } #endif // USE_MVM_TOUR vgui::EditablePanel* CMvMVictoryMannUpEntry::AddLootRow() { vgui::EditablePanel* pItemPanelRow = new vgui::EditablePanel( m_pListPanel, "itemsrow" ) ; m_pListPanel->AddItem( NULL, pItemPanelRow ); m_vecRows.AddToTail( pItemPanelRow ); return pItemPanelRow; } static const float PROGRESS_ANIM_TIME = 2.0f; //----------------------------------------------------------------------------- bool CMvMVictoryMannUpEntry::AnimateProgressBar( void ) { if ( IsVisible() == false || m_bBadgeUpdated == false ) { m_pProgressBarFGAnim->SetWide( m_iProgressWidthEnd ); return true; } if ( m_flPBarCurrTime > PROGRESS_ANIM_TIME ) { if ( m_bBadgeUpdated == true && m_iProgressWidthEnd == m_pProgressBarBG->GetWide() ) { wchar_t wszTourUp[ 256 ]; wchar_t wszTourLevel[ 10 ]; m_pTourProgress->SetDialogVariable( "level", g_pVGuiLocalize->Find( "#TF_MVM_Victory_TourComplete" ) ); _snwprintf( wszTourLevel, ARRAYSIZE(wszTourLevel) - 1, L"%d", m_nBadgeLevel ); wszTourLevel[ ARRAYSIZE(wszTourLevel)-1 ] = '\0'; g_pVGuiLocalize->ConstructString_safe( wszTourUp, g_pVGuiLocalize->Find( "#TF_MvM_TourCount" ), 1, wszTourLevel ); m_pTourProgress->SetDialogVariable( "level", wszTourUp); } return true; } if ( m_flPBarPreviousTime == 0 ) { m_flPBarPreviousTime = gpGlobals->curtime; } m_flPBarCurrTime += gpGlobals->curtime - m_flPBarPreviousTime; m_flPBarPreviousTime = gpGlobals->curtime; float flRatio = m_flPBarCurrTime / PROGRESS_ANIM_TIME; SetBadgeProgressBarProgress( flRatio ); return false; } void CMvMVictoryMannUpEntry::SetBadgeProgressBarProgress( float flPercent ) { int nWidth = m_iProgressWidthStart; nWidth += ((float)m_iProgressWidthEnd - (float)m_iProgressWidthStart) * flPercent; m_pProgressBarFGAnim->SetWide(nWidth); } void CMvMVictoryMannUpEntry::ForceFinishAllAnimation() { // Badge progress bar m_flPBarCurrTime = PROGRESS_ANIM_TIME; SetBadgeProgressBarProgress( 1.f ); // Loot FOR_EACH_VEC( m_vecLootPanels, i ) { CMvMLootItem* pLootPanel = m_vecLootPanels[ i ]; pLootPanel->SetVisible( true ); pLootPanel->m_pUnopenedPanel->SetVisible( false ); } } void CMvMVictoryMannUpEntry::SetLootAnimationPause( float flPause ) { m_flLootAnimTime = gpGlobals->curtime + flPause; m_flLastLootAnimTime = gpGlobals->curtime + flPause; } void CMvMVictoryMannUpEntry::SetActive( bool bActive ) { SetVisible( bActive ); if ( bActive ) { PlayVCD( "class_select" ); } } void CMvMVictoryMannUpEntry::PerformLayout() { BaseClass::PerformLayout(); FOR_EACH_VEC( m_vecRows, i ) { if ( m_pRowKVs ) { m_vecRows[i]->ApplySettings( m_pRowKVs ); m_vecRows[i]->SetVisible( true ); m_vecRows[i]->InvalidateLayout( true, true ); } } FOR_EACH_VEC( m_vecLootPanels, i ) { CMvMLootItem* pItemPanel = m_vecLootPanels[i]; if ( m_pItemModelPanelKVs ) { pItemPanel->ApplySettings( m_pItemModelPanelKVs ); pItemPanel->InvalidateLayout( true ); if ( pItemPanel->GetParent() ) { vgui::EditablePanel* pBackground = dynamic_cast( pItemPanel->GetParent()->FindChildByName( VarArgs( "ItemBackground%d", pItemPanel->m_nIndex + 1 ), true ) ); if ( pBackground ) { int x,y; pBackground->GetPos(x,y); pItemPanel->SetPos( x - 5, 2 ); if ( m_pUnopenedLootKVs ) { pItemPanel->m_pUnopenedPanel->ApplySettings( m_pUnopenedLootKVs ); pItemPanel->m_pUnopenedPanel->SetVisible( true ); } // The unopened panel is in the same position int nXoffset = ( pItemPanel->m_pUnopenedPanel->GetWide() - pItemPanel->GetWide() ) / 2; int nYoffset = ( pItemPanel->m_pUnopenedPanel->GetTall() - pItemPanel->GetTall() ) / 2; pItemPanel->GetPos( x, y ); pItemPanel->m_pUnopenedPanel->SetPos( x - nXoffset, y - nYoffset ); // Update unopened panel's image pItemPanel->m_pUnopenedPanel->SetImage( CFmtStr( "../backpack/player/items/crafting/prize_crate_%d", RandomInt(1,5) ) ); } } } } m_pListPanel->InvalidateLayout( true, false ); } //----------------------------------------------------------------------------- // PRIVATE //----------------------------------------------------------------------------- bool CMvMVictoryMannUpEntry::AnimTimePassed( float flTime ) const { float flCurTime = gpGlobals->curtime - m_flLootAnimTime; float flLastTime = m_flLastLootAnimTime - m_flLootAnimTime; return ( flCurTime >= flTime && flLastTime < flTime ); } bool CMvMVictoryMannUpEntry::AnimateLoot( CTFParticlePanel* pParticlePanel ) { bool bDone = AnimateLoot_Internal( pParticlePanel ); m_flLastLootAnimTime = gpGlobals->curtime; return bDone; } //----------------------------------------------------------------------------- bool CMvMVictoryMannUpEntry::AnimateLoot_Internal( CTFParticlePanel *pParticlePanel ) { if ( m_vecLootPanels.Count() == 0 ) return true; if ( m_iLootAnimIndex >= m_vecLootPanels.Count() ) { m_iLootAnimIndex = 0; return true; } // Get the loot panel CMvMLootItem* pLootPanel = m_vecLootPanels[ m_iLootAnimIndex ]; if ( pLootPanel == NULL ) { m_iLootAnimIndex++; m_flLootAnimTime = gpGlobals->curtime; m_flLastLootAnimTime = gpGlobals->curtime; return false; } if ( AnimTimePassed( 0.1f ) ) { // Scroll to it. We want a little pause in here. for( int itemID = m_pListPanel->FirstItem(); itemID != m_pListPanel->InvalidItemID(); itemID = m_pListPanel->NextItem( itemID ) ) { if ( m_pListPanel->GetItemPanel( itemID ) == pLootPanel->GetParent() ) { m_pListPanel->ScrollToItem( itemID ); } } } // Get loot rarity uint32 nRarity = 0; static CSchemaAttributeDefHandle pAttrDef_LootRarity( "loot rarity" ); uint32 nAttribVal = 0; if ( pLootPanel->GetItem()->FindAttribute( pAttrDef_LootRarity, &nAttribVal ) ) { nRarity = (int)((float&)nAttribVal); } Assert( nRarity >= 0 && nRarity <= 2 ); nRarity = clamp( nRarity, 0, 2 ); #ifdef STAGING_ONLY if ( tf_mvm_fake_loot.GetBool() ) { int randomInt = pLootPanel->GetItem()->GetID() % 10; nRarity = randomInt % 7 == 0 ? 2 : ( randomInt % 3 == 0 ? 1 : 0 ); } #endif int nPanelXPos, nPanelYPos; pLootPanel->GetPos( nPanelXPos, nPanelYPos ); int nPanelCenterX = nPanelXPos + (pLootPanel->GetWide() / 2); int nPanelCenterY = nPanelYPos + (pLootPanel->GetTall() / 2); int iItemAbsX, iItemAbsY; vgui::ipanel()->GetAbsPos( pLootPanel->GetParent()->GetVPanel(), iItemAbsX, iItemAbsY ); int x = iItemAbsX + nPanelCenterX; int y = iItemAbsY + nPanelCenterY; C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); static const char* pszParticles [] = { "mvm_pow_bam", "mvm_pow_boing", "mvm_pow_crack", "mvm_pow_crash", "mvm_pow_crit", "mvm_pow_poof", "mvm_pow_pow", "mvm_pow_punch", "mvm_pow_smash", "mvm_pow_banana", "mvm_pow_boot", "mvm_pow_loot", "mvm_pow_mmph", "mvm_pow_caber" }; switch( nRarity ) { case 0: { if( AnimTimePassed( 0.1f ) ) { if ( pParticlePanel ) { pParticlePanel->FireParticleEffect( pszParticles[ RandomInt(0,ARRAYSIZE(pszParticles)-1)], x, y, 1.25f, false ); } } if ( AnimTimePassed( 0.3f ) ) { // Show it pLootPanel->SetVisible( true ); pLootPanel->m_pUnopenedPanel->SetVisible( false ); if ( pLocalPlayer ) { pLocalPlayer->EmitSound( "ui.cratesmash_common" ); } if ( pLocalPlayer == m_hPlayer ) { engine->ServerCmd( "loot_response common" ); } if ( pParticlePanel ) { pParticlePanel->FireParticleEffect( "mvm_loot_explosion", x, y, 0.4f, false ); } } break; } case 1: { if ( AnimTimePassed( 0.1f ) ) { if ( pParticlePanel ) { pParticlePanel->FireParticleEffect( "mvm_pow_fuse_movement", x, y, 5.f, false, 5.f ); } if ( pLocalPlayer ) { pLocalPlayer->EmitSound( "ui.cratesmash_rare_long" ); } } if ( AnimTimePassed( 2.0f ) ) { // Show it pLootPanel->SetVisible( true ); pLootPanel->m_pUnopenedPanel->SetVisible( false ); if ( pParticlePanel ) { pParticlePanel->FireParticleEffect( "mvm_pow_gold_seq_firework_mid", x, y, 0.8f, false ); pParticlePanel->FireParticleEffect( "mvm_loot_explosion", x, y, 0.4f, false ); } if ( pLocalPlayer == m_hPlayer ) { engine->ServerCmd( "loot_response rare" ); } } break; } case 2: default: // Above level 2? Do the super-cool effects { if ( AnimTimePassed( 0.3f ) ) { if ( pLocalPlayer ) { pLocalPlayer->EmitSound( "ui.cratesmash_ultrarare_long_fireworks" ); } if ( pParticlePanel ) { pParticlePanel->FireParticleEffect( "mvm_pow_gold_seq", x, y, 0.8f, false ); } } if ( AnimTimePassed( 3.3f ) ) { // Show it pLootPanel->SetVisible( true ); pLootPanel->m_pUnopenedPanel->SetVisible( false ); if ( pParticlePanel ) { pParticlePanel->FireParticleEffect( "mvm_loot_explosion", x, y, 0.6f, false ); } if ( m_pBehindItemParticlePanel ) { m_pBehindItemParticlePanel->FireParticleEffect( "mvm_item_godrays_glow", x, y, 5.f, false ); } if ( pLocalPlayer == m_hPlayer ) { engine->ServerCmd( "loot_response ultra_rare" ); } } break; } } float flTotalTime[] = { 0.3f, 3.f, 17.f }; float flEndTime = flTotalTime[nRarity]; // Add in a pause on the last item if we're not already giving some grand pause if ( m_iLootAnimIndex == ( m_vecLootPanels.Count() - 1 ) && ( flEndTime - gpGlobals->curtime ) < 1.f) { flEndTime += 3.f; } if ( AnimTimePassed( flEndTime ) ) { // Prime ourselves for the next one m_iLootAnimIndex++; m_flLootAnimTime = gpGlobals->curtime; m_flLastLootAnimTime = gpGlobals->curtime; } return false; } #ifdef USE_MVM_TOUR //----------------------------------------------------------------------------- int CMvMVictoryMannUpEntry::GetBadgeCompletionCount ( uint32 iProgressBits ) { int nCompleteCount = 0; for (int i = 0; i < 32; i++ ) { nCompleteCount += iProgressBits & 1; iProgressBits = iProgressBits >> 1; if ( iProgressBits == 0 ) { break; } } nCompleteCount = MIN( nCompleteCount, m_nChallengeCount ); return nCompleteCount; } #endif // USE_MVM_TOUR //----------------------------------------------------------------------------- void CMvMVictoryMannUpEntry::CheckBadgeLevel( const CMsgMvMVictoryInfo_Player& player ) { wchar_t wszTourUp[ 256 ]; wchar_t wszTourLevel[ 10 ]; m_nBadgeLevel = player.badge_level(); int nBadgeOffset = player.badge_leveled() ? 1 : 0; _snwprintf( wszTourLevel, ARRAYSIZE(wszTourLevel) - 1, L"%d", m_nBadgeLevel - nBadgeOffset ); #ifdef USE_MVM_TOUR int count = GetBadgeCompletionCount( player.badge_progress_bits() ); if ( player.badge_progress_updated() ) { m_bBadgeUpdated = true; m_flPBarCurrTime = 0; m_flPBarPreviousTime = 0; if ( player.badge_leveled() ) { m_iProgressWidthStart = m_pProgressBarBG->GetWide() * ( (float)(m_nChallengeCount - 1) / (float)m_nChallengeCount ); m_iProgressWidthEnd = m_pProgressBarBG->GetWide(); } else { m_iProgressWidthStart = m_pProgressBarBG->GetWide() * ( (float)(count - 1) / (float)m_nChallengeCount ); m_iProgressWidthEnd = m_pProgressBarBG->GetWide() * ( (float)(count) / (float)m_nChallengeCount ); } m_pProgressCheckOn->SetVisible( true ); m_pProgressBarFGStatic->SetWide( m_iProgressWidthStart ); } else { m_iProgressWidthEnd = m_pProgressBarBG->GetWide() * (float)( (float)count / (float)m_nChallengeCount ); m_pProgressBarFGStatic->SetWide( m_iProgressWidthEnd ); m_pProgressCheckOn->SetVisible( false ); m_pProgressBarFGAnim->SetVisible( false ); } #else // new mm const MvMMission_t& challenge = GetItemSchema()->GetMvmMissions()[m_nMissionIndex]; if ( player.badge_progress_updated() ) { m_bBadgeUpdated = true; m_flPBarCurrTime = 0; m_flPBarPreviousTime = 0; if ( player.badge_leveled() ) { m_iProgressWidthStart = m_pProgressBarBG->GetWide() * ( (float)( player.badge_points() - challenge.m_unMannUpPoints ) / (float)k_unMvMMaxPointsPerBadgeLevel ); m_iProgressWidthEnd = m_pProgressBarBG->GetWide(); } else { m_iProgressWidthStart = m_pProgressBarBG->GetWide() * ( (float)( player.badge_points() - challenge.m_unMannUpPoints ) / (float)k_unMvMMaxPointsPerBadgeLevel ); m_iProgressWidthEnd = m_pProgressBarBG->GetWide() * ( (float)player.badge_points() / (float)k_unMvMMaxPointsPerBadgeLevel ); } m_pProgressCheckOn->SetVisible( true ); m_pProgressBarFGStatic->SetWide( m_iProgressWidthStart ); } else { m_iProgressWidthEnd = m_pProgressBarBG->GetWide() * ( (float)player.badge_points() / (float)k_unMvMMaxPointsPerBadgeLevel ); m_pProgressBarFGStatic->SetWide( m_iProgressWidthEnd ); m_pProgressCheckOn->SetVisible( false ); m_pProgressBarFGAnim->SetVisible( false ); } #endif // USE_MVM_TOUR wszTourLevel[ ARRAYSIZE(wszTourLevel)-1 ] = '\0'; g_pVGuiLocalize->ConstructString_safe( wszTourUp, g_pVGuiLocalize->Find( "#TF_MvM_TourCount" ), 1, wszTourLevel ); m_pTourProgress->SetDialogVariable( "level", wszTourUp ); } //----------------------------------------------------------------------------- void CMvMVictoryMannUpEntry::ClearEconItems() { FOR_EACH_VEC ( m_vecLootPanels, i ) { m_vecLootPanels[ i ]->SetItem( NULL ); m_vecLootPanels[ i ]->SetVisible( false ); } m_vecRows.PurgeAndDeleteElements(); m_vecLootPanels.Purge(); // reset m_iLootAnimIndex = 0; SetLootAnimationPause( 2.f ); // + 2 gives us a pause of 2 seconds when the panel first opens } void CMvMVictoryMannUpEntry::PlayVCD( const char * pszVCDName ) { if (m_pPlayerModelPanel) { const int iClass = m_pPlayerModelPanel->GetPlayerClass(); m_pPlayerModelPanel->PlayVCD(pszVCDName, NULL, false); // This causes the VCD to be played. Yep. m_pPlayerModelPanel->HoldItemInSlot(g_iLegacyClassSelectWeaponSlots[iClass]); } } bool CMvMVictoryMannUpEntry::SetModelPanelInfo( C_TFPlayer* pPlayer ) { if ( !pPlayer ) return false; if ( !m_pPlayerModelPanel ) { AssertMsg1( 0, "No model panel in %s", __FUNCTION__ ); return false; } CSteamID steamID; if ( !pPlayer->GetSteamID( &steamID ) ) { AssertMsg1( 0, "No steamID for user %s", pPlayer->GetPlayerName() ); m_pPlayerModelPanel->SetVisible( false ); return false; } int nClass = pPlayer->GetPlayerClass()->GetClassIndex(); int nTeam = pPlayer->GetTeamNumber(); int nLoadoutSlot = g_iLegacyClassSelectWeaponSlots[nClass]; // We want to mirror the class select panel CEconItemView *pWeapon = TFInventoryManager()->GetItemInLoadoutForClass( nClass, nLoadoutSlot, &steamID ); bool bIsRobot = false; int iRobot = 0; CALL_ATTRIB_HOOK_INT_ON_OTHER( pPlayer, iRobot, appear_as_mvm_robot ); bIsRobot = iRobot ? true : false; m_pPlayerModelPanel->ClearCarriedItems(); m_pPlayerModelPanel->SetToPlayerClass( nClass, bIsRobot, true ); m_pPlayerModelPanel->SetTeam( nTeam ); for ( int wbl = pPlayer->GetNumWearables()-1; wbl >= 0; wbl-- ) { C_TFWearable *pItem = dynamic_cast( pPlayer->GetWearable( wbl ) ); if ( !pItem ) continue; if ( pItem->IsViewModelWearable() ) continue; CAttributeContainer *pCont = pItem->GetAttributeContainer(); CEconItemView *pEconItemView = pCont ? pCont->GetItem() : NULL; if ( pEconItemView && pEconItemView->IsValid() ) { m_pPlayerModelPanel->AddCarriedItem( pEconItemView ); } } if ( pWeapon ) { m_pPlayerModelPanel->AddCarriedItem( pWeapon ); } m_pPlayerModelPanel->HoldItemInSlot( nLoadoutSlot ); m_pPlayerModelPanel->SetVisible( true ); return true; } //----------------------------------------------------------------------------- // CMvMVictoryMannUpPlayerTab //----------------------------------------------------------------------------- DECLARE_BUILD_FACTORY( CMvMVictoryMannUpPlayerTab ); CMvMVictoryMannUpPlayerTab::CMvMVictoryMannUpPlayerTab( Panel *parent, const char *pName ) : BaseClass( parent, pName ) , m_pMouseoverHighlightPanel( NULL ) , m_pActiveTab( NULL ) , m_bIsActive( false ) , m_pAvatarImage( NULL ) { m_pAvatarImage = new CAvatarImagePanel( this, "PlayerAvatar" ); m_pMouseoverHighlightPanel = new vgui::EditablePanel( this, "MouseOverTabPanel" ); m_pActiveTab = new vgui::EditablePanel( this, "ActiveTabPanel" ); } void CMvMVictoryMannUpPlayerTab::ApplySchemeSettings( vgui::IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme ); // load control settings... LoadControlSettings( "resource/UI/MvMVictoryMannUpTab.res" ); } void CMvMVictoryMannUpPlayerTab::SetPlayer( const CSteamID& steamID ) { if ( m_pAvatarImage ) { m_pAvatarImage->SetShouldDrawFriendIcon( false ); m_pAvatarImage->SetPlayer( steamID, k_EAvatarSize64x64 ); } } void CMvMVictoryMannUpPlayerTab::SetSelected( bool bState ) { // Change in state? if ( m_bIsActive != bState ) { if ( m_pMouseoverHighlightPanel ) { m_pMouseoverHighlightPanel->SetVisible( false ); } // Becoming the active tab? if ( m_pActiveTab ) { m_pActiveTab->SetVisible( bState ); } } m_bIsActive = bState; } void CMvMVictoryMannUpPlayerTab::OnCommand( const char *command ) { if ( !Q_stricmp( command, "switch_tab" ) ) { Panel* pParent = GetParent(); if ( pParent ) { pParent->PostActionSignal( new KeyValues( "Command", "command", VarArgs( "%s_pressed", GetName() ) ) ); } return; } else if ( !Q_stricmp( command, "highlight_on" ) ) { // Active tab doesnt highlight if ( m_bIsActive ) return; if ( m_pMouseoverHighlightPanel ) { m_pMouseoverHighlightPanel->SetVisible( true ); } } else if ( !Q_stricmp( command, "highlight_off" ) ) { // Active tab doesnt highlight if ( m_bIsActive ) return; if ( m_pMouseoverHighlightPanel ) { m_pMouseoverHighlightPanel->SetVisible( false ); } } BaseClass::OnCommand( command ); } //----------------------------------------------------------------------------- // CMvMVictoryMannUpPanel //----------------------------------------------------------------------------- DECLARE_BUILD_FACTORY( CMvMVictoryMannUpPanel ); CMvMVictoryMannUpPanel::CMvMVictoryMannUpPanel( Panel *parent, const char *pName ) : vgui::EditablePanel( parent, pName ) , m_pNoItemServerContainer( NULL ) { SetMouseInputEnabled( true ); m_hasData = false; m_iMannUpLootIndex = 0; m_flChangeTabPauseTime = FLT_MAX; m_pMouseOverItemPanel = vgui::SETUP_PANEL( new CItemModelPanel( this, "mouseoveritempanel" ) ); m_pMouseOverTooltip = new CItemModelPanelToolTip( this ); m_pMouseOverTooltip->SetupPanels( this, m_pMouseOverItemPanel ); m_pMouseOverTooltip->SetPositioningStrategy( IPTTP_BOTTOM_SIDE ); m_pMouseOverItemPanel->MoveToFront(); m_pDoneButton = new CExImageButton( this, "DoneButton", g_pVGuiLocalize->Find( "#DoneButton" ), this ); for (int i = 0; i < MVM_PLAYER_COUNT; ++i) { m_PlayerEntryPanels.AddToTail(new CMvMVictoryMannUpEntry( this, "mannup_entry" ) ); m_PlayerEntryPanels.Tail()->SetVisible( true ); } } //----------------------------------------------------------------------------- void CMvMVictoryMannUpPanel::ApplySchemeSettings( IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme ); // load control settings... LoadControlSettings( "resource/UI/MvMVictoryMannUpPanel.res" ); m_pDoneButton->AddActionSignalTarget( GetParent() ); vgui::EditablePanel *pContainer = dynamic_cast( FindChildByName("MainPanelContainer") ); m_pMouseOverItemPanel->SetBorder( pScheme->GetBorder("LoadoutItemPopupBorder") ); m_vecTabs.Purge(); m_vecTabButtons.Purge(); for ( int i = 0; i < MVM_PLAYER_COUNT; ++i ) { CMvMVictoryMannUpPlayerTab *pTab = FindControl( VarArgs( "PlayerTab%d", i + 1), true ); if ( pTab ) { pTab->ApplySchemeSettings( pScheme ); pTab->SetVisible( false ); m_vecTabs.AddToTail( pTab ); vgui::Button* pButton = pTab->FindControl( "TabButton", true ); if ( pButton ) { pButton->SetCommand( CFmtStr( "switch_tab%d", i + 1 ) ); pButton->AddActionSignalTarget( this ); m_vecTabButtons.AddToTail( pButton ); } } } if ( pContainer ) { m_pNoItemServerContainer = dynamic_cast( pContainer->FindChildByName( "NoItemServerContainer" ) ); } m_pParticlePanel = FindControl( "ParticlePanel" ); LoadVictoryData(); } //----------------------------------------------------------------------------- void CMvMVictoryMannUpPanel::OnTick( void ) { if ( !IsVisible() ) { return; } UpdateHighlight(); // Still animating if ( !m_bAnimationComplete ) { // If the pause time is set if ( m_flChangeTabPauseTime != FLT_MAX ) { // Check if the timeer has passed if ( m_flChangeTabPauseTime < gpGlobals->curtime ) { // We're done. Change the tab. m_flChangeTabPauseTime = FLT_MAX; SetTabActive( m_iMannUpLootIndex ); m_PlayerEntryPanels[ m_iMannUpLootIndex ]->SetLootAnimationPause( 0.2f ); } else { // Has not passed yet. Dont animate anything. return; } } bool bBarComplete = false; bool bLootComplete = false; // progress bars FOR_EACH_VEC ( m_PlayerEntryPanels, i ) { bBarComplete = m_PlayerEntryPanels[i]->AnimateProgressBar(); } // Animate loot if ( m_iMannUpLootIndex < MVM_PLAYER_COUNT ) { if ( m_PlayerEntryPanels[ m_iMannUpLootIndex ]->AnimateLoot( m_pParticlePanel ) ) { // This entry is done. Increment the entry index, and set the pause timer. // When the timer goes off it will change to the next tab. ++m_iMannUpLootIndex; if ( m_iMannUpLootIndex < MVM_PLAYER_COUNT && m_vecTabs[m_iMannUpLootIndex]->IsVisible() ) { // Slight pause on showing the new tab m_flChangeTabPauseTime = gpGlobals->curtime + 0.2f; } else { // All loot has been animated bLootComplete = true; } } } else { bLootComplete = true; } // The bar and the loot must be complete to be considered totally complete m_bAnimationComplete = bBarComplete && bLootComplete; } } void CMvMVictoryMannUpPanel::SetVisible( bool bState ) { BaseClass::SetVisible( bState ); //int iRenderGroup = gHUD.LookupRenderGroupIndexByName( "global" ); if ( bState ) { // Hide all other UI //gHUD.LockRenderGroup( iRenderGroup ); } else { // Let the other UI elements show again // gHUD.UnlockRenderGroup( iRenderGroup ); } } void CMvMVictoryMannUpPanel::UpdateHighlight() { vgui::Panel *pMouseOverPanel = vgui::ipanel()->GetPanel( vgui::input()->GetMouseOver(), "ClientDLL" ); #ifdef DEBUG if ( pMouseOverPanel ) { const char * pszParentName = pMouseOverPanel->GetParent() ? pMouseOverPanel->GetParent()->GetName() : ""; engine->Con_NPrintf( 0, "%s %s", pMouseOverPanel->GetName(), pszParentName ); } #endif // If we're still animating, fake the that they're not highlighting anything if ( !m_bAnimationComplete #if defined STAGING_ONLY && !tf_mvm_fake_loot.GetBool() #endif ) { pMouseOverPanel = NULL; } FOR_EACH_VEC ( m_vecTabButtons, i ) { bool bOverMe = pMouseOverPanel && pMouseOverPanel == m_vecTabButtons[i]; m_vecTabs[i]->OnCommand( bOverMe? "highlight_on" : "highlight_off" ); } } //----------------------------------------------------------------------------- void CMvMVictoryMannUpPanel::ShowVictoryPanel() { SetVisible( true ); m_pMouseOverItemPanel->SetVisible( false ); } //----------------------------------------------------------------------------- void CMvMVictoryMannUpPanel::ClearData() { // Clear the MvM data m_hasData = false; // Clear / Reset All Panels int iPlayer = 0; FOR_EACH_VEC( m_PlayerEntryPanels, i ) { m_PlayerEntryPanels[iPlayer]->ClearPlayerData(); m_PlayerEntryPanels[iPlayer]->SetVisible( false ); } m_bAnimationComplete = false; m_iMannUpLootIndex = 0; m_flChangeTabPauseTime = FLT_MAX; if ( m_pNoItemServerContainer ) { m_pNoItemServerContainer->SetVisible( true ); } FOR_EACH_VEC( m_vecTabButtons, i ) { m_vecTabButtons[i]->SetVisible( false ); } FOR_EACH_VEC( m_vecTabs, i ) { m_vecTabs[i]->SetVisible( false ); } } void CMvMVictoryMannUpPanel::LoadVictoryData() { if ( !m_hasData ) return; // get the number of challenges in this mission #ifdef USE_MVM_TOUR int nMissionCount = 6; // default value int idxTour = GetItemSchema()->FindMvmTourByName( m_victoryInfo.tour_name().c_str() ); if ( idxTour >= 0 ) { const MvMTour_t &tour = GetItemSchema()->GetMvmTours()[ idxTour ]; nMissionCount = tour.m_vecMissions.Count(); } #else // new mm int nMissionIndex = GetItemSchema()->FindMvmMissionByName( m_victoryInfo.mission_name().c_str() ); Assert( nMissionIndex >= 0 ); #endif // USE_MVM_TOUR // Clear / Reset All Panels int iPlayer = 0; for ( iPlayer = 0; iPlayer < m_victoryInfo.players_size(); ++iPlayer ) { #ifdef USE_MVM_TOUR m_PlayerEntryPanels[iPlayer]->SetPlayerData( m_victoryInfo.players( iPlayer ), nMissionCount ); #else // new mm m_PlayerEntryPanels[iPlayer]->SetPlayerData( m_victoryInfo.players( iPlayer ), nMissionIndex ); #endif // USE_MVM_TOUR m_PlayerEntryPanels[iPlayer]->SetItemsToolTip( m_pMouseOverTooltip ); // Show the first player m_PlayerEntryPanels[iPlayer]->SetVisible( iPlayer == 0 ); // Setup the tab CSteamID steamID = CSteamID( m_victoryInfo.players( iPlayer ).steam_id() ); if ( iPlayer < m_vecTabs.Count() ) { m_vecTabs[iPlayer]->SetPlayer( steamID ); m_vecTabs[iPlayer]->SetVisible( true ); } if ( iPlayer < m_vecTabButtons.Count() ) { m_vecTabButtons[iPlayer]->SetVisible( true ); } } for ( int iNoPlayer = iPlayer; iNoPlayer < MVM_PLAYER_COUNT; ++iNoPlayer ) { m_PlayerEntryPanels[iNoPlayer]->SetVisible( false ); } } //----------------------------------------------------------------------------- void CMvMVictoryMannUpPanel::MannUpServerResponse( CMsgMvMVictoryInfo &pData ) { ClearData(); m_victoryInfo = pData; m_hasData = true; m_bAnimationComplete = false; LoadVictoryData(); // Set the first tab active. SetTabActive( 0 ); m_iMannUpLootIndex = 0; if ( m_pNoItemServerContainer ) { m_pNoItemServerContainer->SetVisible( false ); } } void CMvMVictoryMannUpPanel::ForceFinishAllAnimation() { m_bAnimationComplete = true; FOR_EACH_VEC( m_PlayerEntryPanels, i ) { m_PlayerEntryPanels[i]->ForceFinishAllAnimation(); } } void CMvMVictoryMannUpPanel::SetTabActive( int nIndex ) { FOR_EACH_VEC( m_PlayerEntryPanels, i ) { m_PlayerEntryPanels[i]->SetActive( i == nIndex ); if ( i < m_vecTabs.Count() ) { m_vecTabs[i]->SetSelected( i == nIndex ); } } } void CMvMVictoryMannUpPanel::OnCommand( const char *command ) { if ( !Q_strncmp( command, "switch_tab", ARRAYSIZE("switch_tab") - 1 ) ) { int nIndex = atoi( command + ARRAYSIZE("switch_tab") - 1 ) - 1; // Dont allow switching if we're still animating if ( m_bAnimationComplete ) { SetTabActive( nIndex ); } } BaseClass::OnCommand( command ); } //----------------------------------------------------------------------------- // CMvMVictoryPanelContainer //----------------------------------------------------------------------------- DECLARE_BUILD_FACTORY( CMvMVictoryPanelContainer ); CMvMVictoryPanelContainer::CMvMVictoryPanelContainer( Panel *parent, const char *pName ) : vgui::EditablePanel( parent, pName ) { SetMouseInputEnabled( true ); m_pVictoryPanelNormal = new CVictoryPanel( this, "VictoryPanelNormal" ); m_pVictoryPanelMannUp = new CMvMVictoryMannUpPanel( this, "VictoryPanelMannUp" ); m_pVictoryPanelMannUp->ClearData(); } //----------------------------------------------------------------------------- void CMvMVictoryPanelContainer::ApplySchemeSettings( vgui::IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme ); LoadControlSettings( "resource/UI/MvMVictoryContainer.res" ); m_pVictoryPanelNormal->SetVisible( false ); m_pVictoryPanelMannUp->SetVisible( false ); } //----------------------------------------------------------------------------- void CMvMVictoryPanelContainer::FireGameEvent( IGameEvent * event ) { } //----------------------------------------------------------------------------- void CMvMVictoryPanelContainer::OnTick( void ) { if ( !IsVisible() ) return; // The objective changed. This means we changedlevel // or went to the main menu. Hide everything! if ( m_pObjective != TFObjectiveResource() ) { SetVisible( false ); m_pVictoryPanelMannUp->SetVisible( false ); m_pVictoryPanelNormal->SetVisible( false ); } if ( m_pVictoryPanelMannUp->IsVisible() ) { m_pVictoryPanelMannUp->OnTick(); } if ( m_pVictoryPanelNormal->IsVisible() ) { m_pVictoryPanelNormal->OnTick(); } } //----------------------------------------------------------------------------- void CMvMVictoryPanelContainer::OnCommand( const char *command ) { if ( !Q_stricmp( command, "done" ) ) { SetMouseInputEnabled( false ); m_pVictoryPanelNormal->SetVisible( false ); m_pVictoryPanelMannUp->SetVisible( false ); SetVisible( false ); // Tell the population manager on the server that we're done viewing the panel engine->ServerCmd( "done_viewing_loot" ); CreateReOpenNotification(); } } void CMvMVictoryPanelContainer::OnKeyCodePressed( vgui::KeyCode code ) { if ( code == STEAMCONTROLLER_A || code == STEAMCONTROLLER_B ) { OnCommand( "done" ); } } void CMvMVictoryPanelContainer::CreateReOpenNotification() { // Only do this for Mann-Up CTFGSLobby *pLobby = GTFGCClientSystem()->GetLobby(); if ( !pLobby || !IsMannUpGroup( pLobby->GetMatchGroup() ) ) { return; } int iCount = NotificationQueue_Count( &CShowMannUpLootNotification::IsNotificationType ); if ( iCount == 0 ) { CShowMannUpLootNotification *pNotification = new CShowMannUpLootNotification(); pNotification->SetText( "#TF_MVM_Victory_Loot_Notification" ); pNotification->SetLifetime( 10000.0f ); // Last for quite a bit NotificationQueue_Add( pNotification ); } } //----------------------------------------------------------------------------- void CMvMVictoryPanelContainer::ShowVictoryPanel( bool bIsReopening ) { SetVisible( true ); MakePopup(); MoveToFront(); SetKeyBoardInputEnabled( false ); SetMouseInputEnabled( true ); m_pObjective = TFObjectiveResource(); m_pVictoryPanelNormal->ResetVictoryPanel(); // popfile name m_pVictoryPanelNormal->SetMapAndPopFile(); #ifdef STAGING_ONLY if ( tf_mvm_fake_loot.GetBool() ) { m_pVictoryPanelMannUp->ShowVictoryPanel(); return; } #endif // Which Panel to show CTFGSLobby *pLobby = GTFGCClientSystem()->GetLobby(); if ( pLobby && IsMannUpGroup( pLobby->GetMatchGroup() ) ) { m_pVictoryPanelMannUp->ShowVictoryPanel(); if ( bIsReopening ) { m_pVictoryPanelMannUp->ForceFinishAllAnimation(); } } else { m_pVictoryPanelNormal->SetVisible( true ); } } #ifdef STAGING_ONLY #include "tf_hud_mann_vs_machine_status.h" static void fake_mvm_victory_f() { tf_mvm_fake_loot.SetValue( 1 ); #ifdef USE_MVM_TOUR const MvMTour_t &tour = GetItemSchema()->GetMvmTours()[ 0 ]; #endif // USE_MVM_TOUR const MvMMission_t &chal = GetItemSchema()->GetMvmMissions()[ 0 ]; // We'll send everybody the same summary message describing what everybody got CMsgMvMVictoryInfo msgVictoryInfo; #ifdef USE_MVM_TOUR msgVictoryInfo.set_tour_name( tour.m_sTourInternalName.Get() ); #endif // USE_MVM_TOUR msgVictoryInfo.set_mission_name( chal.m_sPop.Get() ); CSteamID steamID; int nCount = 0; for ( int i = 1 ; i <= gpGlobals->maxClients ; i++ ) { CBasePlayer *pPlayer = UTIL_PlayerByIndex( i ); if ( pPlayer && pPlayer->GetTeamNumber() == TF_TEAM_RED && pPlayer->GetSteamID( &steamID ) ) { CMsgMvMVictoryInfo_Player *pVictoryMsgPlayer = msgVictoryInfo.add_players(); pVictoryMsgPlayer->set_steam_id( steamID.ConvertToUint64() ); pVictoryMsgPlayer->set_badge_leveled( true ); pVictoryMsgPlayer->set_badge_progress_updated( true ); pVictoryMsgPlayer->set_badge_level( RandomInt(0,5) ); pVictoryMsgPlayer->set_badge_progress_bits( RandomInt(1,4) ); ++nCount; } } if ( C_BasePlayer::GetLocalPlayer()->GetSteamID( &steamID ) ) { for ( nCount; nCount < 6; ++nCount ) { CMsgMvMVictoryInfo_Player *pVictoryMsgPlayer = msgVictoryInfo.add_players(); pVictoryMsgPlayer->set_steam_id(steamID.ConvertToUint64()); pVictoryMsgPlayer->set_badge_leveled(true); pVictoryMsgPlayer->set_badge_progress_updated(true); pVictoryMsgPlayer->set_badge_level(RandomInt(0, 5)); pVictoryMsgPlayer->set_badge_progress_bits(RandomInt(1, 4)); } } CTFHudMannVsMachineStatus *pMannVsMachineStatus = GET_HUDELEMENT( CTFHudMannVsMachineStatus ); if ( pMannVsMachineStatus ) { pMannVsMachineStatus->ForceVictoryRefresh(); pMannVsMachineStatus->MVMVictory( false, 9999 ); pMannVsMachineStatus->MVMVictoryGCResponse( msgVictoryInfo ); } } ConCommand fake_mvm_victory( "fake_mvm_victory", fake_mvm_victory_f ); #endif