diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/client/tf/tf_hud_mann_vs_machine_victory.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/client/tf/tf_hud_mann_vs_machine_victory.cpp')
| -rw-r--r-- | game/client/tf/tf_hud_mann_vs_machine_victory.cpp | 2049 |
1 files changed, 2049 insertions, 0 deletions
diff --git a/game/client/tf/tf_hud_mann_vs_machine_victory.cpp b/game/client/tf/tf_hud_mann_vs_machine_victory.cpp new file mode 100644 index 0000000..f557d41 --- /dev/null +++ b/game/client/tf/tf_hud_mann_vs_machine_victory.cpp @@ -0,0 +1,2049 @@ +//========= 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<CExButton*>( FindChildByName("DoneButton") ); + if ( pButton ) + { + pButton->AddActionSignalTarget( this ); + } + + vgui::EditablePanel* pStatsContainer = dynamic_cast<vgui::EditablePanel*>( FindChildByName("StatsContainer") ); + if ( pStatsContainer ) + { + m_pHeaderContainer = dynamic_cast<vgui::EditablePanel*>( pStatsContainer->FindChildByName("HeaderContainer") ); + m_pCreditContainerPanel = dynamic_cast<vgui::EditablePanel*>( pStatsContainer->FindChildByName("CreditContainer") ); + m_pRatingContainerPanel = dynamic_cast<vgui::EditablePanel*>( pStatsContainer->FindChildByName("RatingContainer") ); + m_pTotalGameCreditSpendPanel = dynamic_cast<CCreditSpendPanel*>( 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<CMvMLootItem*> > 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<vgui::EditablePanel*>( 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<C_TFWearable*>( 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<vgui::EditablePanel*>( 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<CMvMVictoryMannUpPlayerTab>( VarArgs( "PlayerTab%d", i + 1), true ); + if ( pTab ) + { + pTab->ApplySchemeSettings( pScheme ); + pTab->SetVisible( false ); + m_vecTabs.AddToTail( pTab ); + + vgui::Button* pButton = pTab->FindControl<vgui::Button>( "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<vgui::EditablePanel*>( pContainer->FindChildByName( "NoItemServerContainer" ) ); + } + + m_pParticlePanel = FindControl<CTFParticlePanel>( "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 |