summaryrefslogtreecommitdiff
path: root/game/shared/tf/tf_mann_vs_machine_stats.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/shared/tf/tf_mann_vs_machine_stats.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/shared/tf/tf_mann_vs_machine_stats.cpp')
-rw-r--r--game/shared/tf/tf_mann_vs_machine_stats.cpp1689
1 files changed, 1689 insertions, 0 deletions
diff --git a/game/shared/tf/tf_mann_vs_machine_stats.cpp b/game/shared/tf/tf_mann_vs_machine_stats.cpp
new file mode 100644
index 0000000..985f684
--- /dev/null
+++ b/game/shared/tf/tf_mann_vs_machine_stats.cpp
@@ -0,0 +1,1689 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+
+#include "tf_mann_vs_machine_stats.h"
+#include "filesystem.h"
+#include "steamworks_gamestats.h"
+#include "econ_item_description.h"
+#include "econ_item_system.h"
+#include "econ_item_schema.h"
+#include "econ_item_constants.h"
+
+#ifdef GAME_DLL
+ #include "dt_utlvector_send.h"
+ #include "tf_gamerules.h"
+ #include "tf_player.h"
+ #include "tf_gc_server.h"
+#else
+ #include "dt_utlvector_recv.h"
+ #include "c_tf_player.h"
+ #include "hud_macros.h"
+ #include "tf_hud_mann_vs_machine_status.h"
+ #include "c_tf_objective_resource.h"
+ #include "player_vs_environment/c_tf_upgrades.h"
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+extern ConVar tf_mm_trusted;
+
+extern ConVar tf_mvm_respec_limit;
+extern ConVar tf_mvm_respec_credit_goal;
+
+static CMannVsMachineStats *g_pMVMStats = NULL;
+
+//-----------------------------------------------------------------------------
+#ifdef CLIENT_DLL
+ // Avoid redef warnings
+ #undef CTFPlayer
+ #define CTFPlayer C_TFPlayer
+ #define CMannVsMachineStats C_MannVsMachineStats
+#endif
+
+BEGIN_NETWORK_TABLE_NOBASE( CMannVsMachineWaveStats, DT_CMannVsMachineWaveStats )
+#if defined( GAME_DLL )
+ SendPropInt( SENDINFO( nCreditsDropped ), 16, SPROP_UNSIGNED ),
+ SendPropInt( SENDINFO( nCreditsAcquired ), 16, SPROP_UNSIGNED ),
+ SendPropInt( SENDINFO( nCreditsBonus ), 16, SPROP_UNSIGNED ),
+ SendPropInt( SENDINFO( nPlayerDeaths ), 16, SPROP_UNSIGNED ),
+ SendPropInt( SENDINFO( nBuyBacks ), 8, SPROP_UNSIGNED ),
+#else
+
+ RecvPropInt( RECVINFO( nCreditsDropped ) ),
+ RecvPropInt( RECVINFO( nCreditsAcquired ) ),
+ RecvPropInt( RECVINFO( nCreditsBonus ) ),
+ RecvPropInt( RECVINFO( nPlayerDeaths ) ),
+ RecvPropInt( RECVINFO( nBuyBacks ) ),
+#endif
+END_NETWORK_TABLE()
+
+LINK_ENTITY_TO_CLASS( tf_mann_vs_machine_stats, CMannVsMachineStats );
+IMPLEMENT_NETWORKCLASS_ALIASED( MannVsMachineStats, DT_MannVsMachineStats )
+
+BEGIN_NETWORK_TABLE( CMannVsMachineStats, DT_MannVsMachineStats )
+#if defined ( GAME_DLL )
+ SendPropInt( SENDINFO( m_iCurrentWaveIdx ), 8, SPROP_UNSIGNED ),
+ SendPropInt( SENDINFO( m_iServerWaveID ), 8, SPROP_UNSIGNED ),
+ SendPropDataTable( SENDINFO_DT(m_runningTotalWaveStats), &REFERENCE_SEND_TABLE(DT_CMannVsMachineWaveStats) ),
+ SendPropDataTable( SENDINFO_DT(m_previousWaveStats), &REFERENCE_SEND_TABLE(DT_CMannVsMachineWaveStats) ),
+ SendPropDataTable( SENDINFO_DT(m_currentWaveStats), &REFERENCE_SEND_TABLE(DT_CMannVsMachineWaveStats) ),
+ SendPropInt( SENDINFO( m_iCurrencyCollectedForRespec ), -1, SPROP_VARINT ),
+ SendPropInt( SENDINFO( m_nRespecsAwardedInWave ), 8, SPROP_UNSIGNED ),
+#else
+ RecvPropInt( RECVINFO( m_iCurrentWaveIdx ) ),
+ RecvPropInt( RECVINFO( m_iServerWaveID ) ),
+ RecvPropDataTable(RECVINFO_DT(m_runningTotalWaveStats), 0, &REFERENCE_RECV_TABLE(DT_CMannVsMachineWaveStats)),
+ RecvPropDataTable(RECVINFO_DT(m_previousWaveStats), 0, &REFERENCE_RECV_TABLE(DT_CMannVsMachineWaveStats)),
+ RecvPropDataTable(RECVINFO_DT(m_currentWaveStats), 0, &REFERENCE_RECV_TABLE(DT_CMannVsMachineWaveStats)),
+ RecvPropInt( RECVINFO( m_iCurrencyCollectedForRespec ) ),
+ RecvPropInt( RECVINFO( m_nRespecsAwardedInWave ) ),
+#endif
+END_NETWORK_TABLE()
+
+#ifdef CLIENT_DLL
+
+//-----------------------------------------------------------------------------
+// Purpose: Server message that tells that a mann vs machine event occurred
+//-----------------------------------------------------------------------------
+static void __MsgFunc_MVMStatsReset( bf_read &msg )
+{
+ if ( g_pMVMStats )
+ {
+ g_pMVMStats->ResetStats( );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Server message that tells that a mann vs machine event occurred
+//-----------------------------------------------------------------------------
+static void __MsgFunc_MVMPlayerEvent( bf_read &msg )
+{
+ // Deprecated.
+ // Dont delete this or its HOOK_MESSAGE below or else demos will break
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Reports Player Spending
+//-----------------------------------------------------------------------------
+static void __MsgFunc_MVMLocalPlayerWaveSpendingValue( bf_read &msg )
+{
+ if ( !g_pMVMStats )
+ return;
+
+ // PlayerIdx(8), Wave(1), Type(1), Cost(2)
+ uint64 playerID;
+ if ( !msg.ReadBytes( &playerID, sizeof(playerID) ) )
+ {
+ DevMsg( " Unable to Get Player SteamID from __MsgFunc_MVMLocalPlayerWaveSpendingValue() " );
+ return;
+ }
+
+ uint8 idxWave = msg.ReadByte();
+ eMannVsMachineEvent eType = (eMannVsMachineEvent)msg.ReadByte();
+ int16 nCost = msg.ReadWord();
+
+ CPlayerWaveSpendingStats *pPlayerStats = g_pMVMStats->GetSpending( idxWave, playerID );
+ if ( !pPlayerStats )
+ return;
+
+ CSteamID steamId( playerID );
+ C_TFPlayer *pTFPlayer = ToTFPlayer( GetPlayerBySteamID( steamId ) );
+ C_TFPlayer *pTFLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
+
+ switch ( eType )
+ {
+ case kMVMEvent_Player_BoughtInstantRespawn:
+ pPlayerStats->nCreditsSpentOnBuyBacks += nCost;
+ // Read the event msg and pass it on to MVMStats
+ if ( pTFPlayer == pTFLocalPlayer )
+ {
+ g_pMVMStats->SW_ReportClientBuyBackPurchase( idxWave, nCost );
+ }
+ break;
+ case kMVMEvent_Player_BoughtBottle:
+ pPlayerStats->nCreditsSpentOnBottles += nCost;
+ break;
+ case kMVMEvent_Player_BoughtUpgrade:
+ pPlayerStats->nCreditsSpentOnUpgrades += nCost;
+ break;
+ case kMVMEvent_Player_ActiveUpgrades:
+ g_pMVMStats->SetPlayerActiveUpgradeCosts( playerID, nCost );
+ break;
+ } // switch
+
+}
+//-----------------------------------------------------------------------------
+// Purpose: Server message that tells that a mann vs machine event occurred
+//-----------------------------------------------------------------------------
+static void __MsgFunc_MVMResetPlayerStats( bf_read &msg )
+{
+ if ( !g_pMVMStats )
+ return;
+
+ uint8 playerIndex = msg.ReadByte();
+
+ C_TFPlayer *pTFPlayer = ToTFPlayer( UTIL_PlayerByIndex( playerIndex ) );
+ if ( !pTFPlayer )
+ return;
+
+ g_pMVMStats->ResetPlayerEvents( pTFPlayer );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handling a Server message that notifies that a player has upgraded in MvM
+//-----------------------------------------------------------------------------
+static void __MsgFunc_MVMPlayerUpgradedEvent( bf_read &msg )
+{
+ //if ( !g_pMVMStats )
+ // return;
+ //
+ //// Read the data
+ //// PlayerIdx(1), WaveIdx(1), ItemDef(2), AttributeDef(2), Quality(1), cost(2)
+ //uint8 playerIndex = msg.ReadByte();
+ //uint8 idxWave = msg.ReadByte();
+ //uint16 nItemDef = msg.ReadWord();
+ //uint16 nAttributeDef = msg.ReadWord();
+ //uint8 nQuality = msg.ReadByte();
+ //int16 nCost = msg.ReadWord();
+
+ //CMannVsMachineUpgradeEvent upgrade;
+ //upgrade.nItemDef = nItemDef;
+ //upgrade.nAttributeDef = nAttributeDef;
+ //upgrade.nQuality = nQuality;
+
+ //C_TFPlayer *pTFPlayer = ToTFPlayer( UTIL_PlayerByIndex( playerIndex ) );
+ //C_TFPlayer *pTFLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
+
+ //// Report Stats if Local Player
+ //if ( pTFPlayer && pTFLocalPlayer && ( pTFPlayer == pTFLocalPlayer ) )
+ //{
+ // // Read the event msg and pass it on to MVMStats
+ // g_pMVMStats->SW_ReportClientUpgradePurchase( idxWave, nItemDef, nAttributeDef, nQuality, nCost );
+ //}
+}
+
+//-----------------------------------------------------------------------------
+// Message for the Local Player that it should clear its upgrade vector
+static void __MsgFunc_MVMLocalPlayerUpgradesClear( bf_read &msg )
+{
+ if ( !g_pMVMStats )
+ return;
+
+ // Read the data
+ //uint8 count = msg.ReadByte();
+
+ g_pMVMStats->ClearLocalPlayerUpgrades();
+}
+
+//-----------------------------------------------------------------------------
+// Message for the local player about an upgrade that it owns
+static void __MsgFunc_MVMLocalPlayerUpgradesValue( bf_read &msg )
+{
+ if ( !g_pMVMStats )
+ return;
+
+ // Read the data
+ // Class(1), ItemDef(2), Upgrade(1), cost(1)
+ uint8 playerClass = msg.ReadByte();
+ uint16 nItemDef = msg.ReadWord();
+ //uint8 upgrade = msg.ReadByte();
+ //uint16 cost = msg.ReadByte();
+
+ g_pMVMStats->AddLocalPlayerUpgrade( playerClass, (item_definition_index_t)nItemDef );
+}
+
+//-----------------------------------------------------------------------------
+// Message for the player that it should clear spending stats history for target wave
+static void __MsgFunc_MVMResetPlayerWaveSpendingStats( bf_read &msg )
+{
+ if ( !g_pMVMStats )
+ return;
+
+ // Read the data
+ // Wave(1)
+ uint8 idxWave = msg.ReadByte();
+
+ g_pMVMStats->ClearCurrentPlayerWaveSpendingStats( idxWave );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Server message that tells that the current wave has ended and a new one has begun (including resets)
+//-----------------------------------------------------------------------------
+static void __MsgFunc_MVMWaveChange( bf_read &msg )
+{
+ if ( !g_pMVMStats )
+ return;
+
+ // Read the data
+ uint16 waveID = msg.ReadWord();
+
+ CMannVsMachinePlayerStats stats;
+
+ stats.nDeaths = msg.ReadByte();
+ stats.nBotDamage = msg.ReadLong();
+ stats.nGiantDamage = msg.ReadLong();
+ stats.nTankDamage = msg.ReadLong();
+
+ // Send the Stats
+ g_pMVMStats->SW_ReportClientWaveSummary( waveID, stats );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+static void __MsgFunc_MVMResetPlayerUpgradeSpending( bf_read &msg )
+{
+ if ( !g_pMVMStats )
+ return;
+
+ uint8 playerIndex = msg.ReadByte();
+
+ C_TFPlayer *pTFPlayer = ToTFPlayer( UTIL_PlayerByIndex( playerIndex ) );
+ if ( !pTFPlayer )
+ return;
+
+ g_pMVMStats->ResetUpgradeSpending( pTFPlayer );
+}
+
+#endif // CLIENT_DLL
+
+//------------------------------------------------------------------------------
+// CMannVsMachineStats
+//------------------------------------------------------------------------------
+CMannVsMachineStats::CMannVsMachineStats()
+{
+ g_pMVMStats = this;
+
+#ifdef GAME_DLL
+ SetCurrentWave( 0 );
+ Q_memset( m_playerStats, 0, sizeof( m_playerStats ) );
+#else
+ m_iCurrentWaveIdx = 0;
+
+ m_teamActiveUpgrades.Purge();
+ m_teamActiveUpgrades.SetLessFunc( DefLessFunc (uint64) );
+#endif
+ m_currWaveSpendingStats.SetLessFunc( DefLessFunc (uint64) );
+ m_prevWaveSpendingStats.SetLessFunc( DefLessFunc (uint64) );
+ m_allPrevWaveSpendingStats.SetLessFunc( DefLessFunc (uint64) );
+
+ m_iCurrencyCollectedForRespec = 0;
+ m_nRespecsAwardedInWave = 0;
+ //m_nEventID = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: DTOR
+//-----------------------------------------------------------------------------
+CMannVsMachineStats::~CMannVsMachineStats()
+{
+ g_pMVMStats = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::ResetStats( )
+{
+#ifdef GAME_DLL
+ // notify everyone to reset everything
+ CBroadcastRecipientFilter filter;
+ filter.MakeReliable();
+ UserMessageBegin( filter, "MVMStatsReset" );
+ MessageEnd();
+
+ SetCurrentWave( 0 );
+
+ m_runningTotalWaveStats.ClearStats();
+ m_previousWaveStats.ClearStats();
+ m_currentWaveStats.ClearStats();
+
+#else
+ m_vecLocalPlayerUpgrades.Purge();
+ m_teamActiveUpgrades.Purge();
+#endif
+
+ m_currWaveSpendingStats.RemoveAll();
+ m_prevWaveSpendingStats.RemoveAll();
+ m_allPrevWaveSpendingStats.RemoveAll();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::ResetPlayerEvents( CTFPlayer *pTFPlayer )
+{
+ if ( pTFPlayer->IsBot() )
+ return;
+
+#ifdef GAME_DLL
+ CBroadcastRecipientFilter filter;
+ filter.MakeReliable();
+ UserMessageBegin( filter, "MVMResetPlayerStats" );
+ WRITE_BYTE( (uint8)pTFPlayer->entindex() );
+ MessageEnd();
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::ResetUpgradeSpending( CTFPlayer *pTFPlayer )
+{
+ if ( !pTFPlayer )
+ return;
+
+ if ( pTFPlayer->IsBot() )
+ return;
+
+ CSteamID steamID;
+ if ( pTFPlayer && pTFPlayer->GetSteamID( &steamID ) )
+ {
+ int iWave = m_currWaveSpendingStats.Find( steamID.ConvertToUint64() );
+ if ( iWave != m_currWaveSpendingStats.InvalidIndex() )
+ {
+ m_currWaveSpendingStats[iWave].nCreditsSpentOnUpgrades = 0;
+ }
+
+ iWave = m_allPrevWaveSpendingStats.Find( steamID.ConvertToUint64() );
+ if ( iWave != m_allPrevWaveSpendingStats.InvalidIndex() )
+ {
+ m_allPrevWaveSpendingStats[iWave].nCreditsSpentOnUpgrades = 0;
+ }
+
+ iWave = m_prevWaveSpendingStats.Find( steamID.ConvertToUint64() );
+ if ( iWave != m_prevWaveSpendingStats.InvalidIndex() )
+ {
+ m_prevWaveSpendingStats[iWave].nCreditsSpentOnUpgrades = 0;
+ }
+ }
+
+#ifdef GAME_DLL
+ CBroadcastRecipientFilter filter;
+ filter.MakeReliable();
+ UserMessageBegin( filter, "MVMResetPlayerUpgradeSpending" );
+ WRITE_BYTE( (uint8)pTFPlayer->entindex() );
+ MessageEnd();
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns acquired credits - default is all waves
+//-----------------------------------------------------------------------------
+uint32 CMannVsMachineStats::GetAcquiredCredits( int iWaveIdx, bool bWithBonus /*= true*/ )
+{
+ CMannVsMachineLocalWaveStats waveStats = GetWaveStats( iWaveIdx );
+
+ if ( bWithBonus )
+ return waveStats.nCreditsAcquired + waveStats.nCreditsBonus;
+ else
+ return waveStats.nCreditsAcquired;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns dropped credits for a target wave. If target wave is -1, returns sum of all waves
+//-----------------------------------------------------------------------------
+uint32 CMannVsMachineStats::GetDroppedCredits( int iWaveIdx )
+{
+ CMannVsMachineLocalWaveStats waveStats = GetWaveStats( iWaveIdx );
+ return waveStats.nCreditsDropped;
+}
+
+//-----------------------------------------------------------------------------
+// Number of Credits missed (dropped and not collected)
+//-----------------------------------------------------------------------------
+uint32 CMannVsMachineStats::GetMissedCredits( int iWaveIdx )
+{
+ CMannVsMachineLocalWaveStats waveStats = GetWaveStats( iWaveIdx );
+ return waveStats.nCreditsDropped - waveStats.nCreditsAcquired;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns credit bonus for a target wave. If target wave is -1, returns sum of all waves
+//-----------------------------------------------------------------------------
+uint32 CMannVsMachineStats::GetBonusCredits( int iWaveIdx )
+{
+ CMannVsMachineLocalWaveStats waveStats = GetWaveStats( iWaveIdx );
+ return waveStats.nCreditsBonus;
+}
+//=============================================================================//
+#ifdef GAME_DLL
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::RoundOver( bool bHumansWon )
+{
+ // Send Stats to OGS
+ // Increment server wave id since victory uses the previous "wave" and this one has yet to be incremented
+ m_iServerWaveID++;
+ SW_ReportWaveSummary( m_iCurrentWaveIdx, bHumansWon );
+ m_iServerWaveID--;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::SetCurrentWave( uint32 idxWave )
+{
+ // Advancing Wave, compact in the stats
+ if ( idxWave > m_iCurrentWaveIdx )
+ {
+ m_runningTotalWaveStats += m_previousWaveStats;
+ m_previousWaveStats = m_currentWaveStats;
+ }
+
+ if ( idxWave == 0 )
+ {
+ // Purge it all
+ m_runningTotalWaveStats.ClearStats();
+ m_previousWaveStats.ClearStats();
+ m_currentWaveStats.ClearStats();
+ }
+
+ m_iCurrentWaveIdx = idxWave;
+
+ // Notify Players of Reset of current Wave for PlayerStats
+ CBroadcastRecipientFilter filter;
+ filter.MakeReliable();
+
+ UserMessageBegin( filter, "MVMResetPlayerWaveSpendingStats" );
+ WRITE_BYTE( (uint8)m_iCurrentWaveIdx );
+ MessageEnd();
+
+ ResetWaveStats();
+ OnStatsChanged();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::RoundEvent_WaveStart()
+{
+ // Starting a new wave
+ // Report the previous successful wave.
+ if ( m_iCurrentWaveIdx > 0 && m_currentWaveStats.nAttempts == 0)
+ {
+ SW_ReportWaveSummary( m_iCurrentWaveIdx - 1, true );
+ }
+
+ // reset stats
+ ResetWaveStats();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::RoundEvent_WaveEnd( bool bSuccess )
+{
+ // if failed, report immediately,
+ // report successes on starting the next wave because of currency picked up late
+ ConVar *sv_cheats = g_pCVar->FindVar( "sv_cheats" );
+ if ( !bSuccess && ( !sv_cheats || !sv_cheats->GetBool() ) )
+ {
+ m_currentWaveStats.nAttempts++;
+ SW_ReportWaveSummary( m_iCurrentWaveIdx, false );
+ ResetWaveStats();
+ OnStatsChanged();
+
+ CBroadcastRecipientFilter filter;
+ filter.MakeReliable();
+ UserMessageBegin( filter, "MVMWaveFailed" );
+ MessageEnd();
+ }
+
+ // Send a User message to Clients to send there data
+ // Tell each client their damage
+ CUtlVector< CTFPlayer * > playerVector;
+ CollectPlayers( &playerVector, TF_TEAM_PVE_DEFENDERS );
+ for( int i=0; i<playerVector.Count(); ++i )
+ {
+ CTFPlayer *player = playerVector[i];
+ CMannVsMachinePlayerStats stats = m_playerStats[player->entindex()];
+
+ CSingleUserRecipientFilter filter( player );
+ filter.MakeReliable();
+
+ // ServerWaveID(2), deaths(1), damageBot(4), damageGiant(4), damageTank(4)
+ UserMessageBegin( filter, "MVMWaveChange" );
+ WRITE_WORD( (uint16)m_iServerWaveID );
+ WRITE_BYTE( (uint8)stats.nDeaths );
+ WRITE_LONG( stats.nBotDamage );
+ WRITE_LONG( stats.nGiantDamage );
+ WRITE_LONG( stats.nTankDamage );
+ MessageEnd();
+ }
+
+ // Increment the ServerId
+ m_iServerWaveID++;
+ Q_memset( m_playerStats, 0, sizeof( m_playerStats ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::RoundEvent_AcquiredCredits( uint32 idxWave, int nAmount, bool bIsBonus )
+{
+ if ( idxWave == (int)m_iCurrentWaveIdx )
+ {
+ if ( bIsBonus )
+ {
+ m_currentWaveStats.nCreditsBonus += nAmount;
+ }
+ else
+ {
+ m_currentWaveStats.nCreditsAcquired += nAmount;
+ }
+ }
+ else if ( idxWave == m_iCurrentWaveIdx - 1 )
+ {
+ if ( bIsBonus )
+ {
+ m_previousWaveStats.nCreditsBonus += nAmount;
+ }
+ else
+ {
+ m_previousWaveStats.nCreditsAcquired += nAmount;
+ }
+ }
+
+ OnStatsChanged();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::RoundEvent_CreditsDropped( uint32 idxWave, int nAmount )
+{
+ if ( idxWave == m_iCurrentWaveIdx )
+ {
+ m_currentWaveStats.nCreditsDropped += nAmount;
+ }
+ else if ( idxWave == m_iCurrentWaveIdx - 1 )
+ {
+ m_previousWaveStats.nCreditsDropped += nAmount;
+ }
+ OnStatsChanged();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::PlayerEvent_PointsChanged( CTFPlayer *pTFPlayer, int nPoints )
+{
+ //
+ // Deprecated
+ //
+
+ //if ( pTFPlayer->IsBot() || !TFGameRules() || !TFGameRules()->IsPVEModeActive() )
+ // return;
+
+ //OnStatsChanged();
+ //NotifyPlayerEvent( pTFPlayer, m_iCurrentWaveIdx, kMVMEvent_Player_Points, nPoints );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::PlayerEvent_Died( CTFPlayer *pTFPlayer )
+{
+ if ( pTFPlayer->IsBot() || !TFGameRules() || !TFGameRules()->IsPVEModeActive() )
+ return;
+
+ m_playerStats[pTFPlayer->entindex()].nDeaths += 1;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::PlayerEvent_Upgraded( CTFPlayer *pTFPlayer, uint16 nItemDef, uint16 nAttributeDef, uint8 nQuality, int16 nCost, bool bIsBottle )
+{
+ if ( pTFPlayer->IsBot() || !TFGameRules() || !TFGameRules()->IsPVEModeActive() )
+ return;
+
+ OnStatsChanged();
+
+ CBroadcastRecipientFilter filter;
+ filter.MakeReliable();
+
+ // PlayerIdx(1), WaveIdx(1), ItemDef(2), AttributeDef(2), Quality(1), cost(2)
+ // send user message
+ UserMessageBegin( filter, "MVMPlayerUpgradedEvent" );
+ WRITE_BYTE( (uint8)pTFPlayer->entindex() );
+ WRITE_BYTE( (uint8)m_iCurrentWaveIdx );
+ WRITE_WORD( nItemDef );
+ WRITE_WORD( nAttributeDef );
+ WRITE_BYTE( nQuality);
+ WRITE_WORD( nCost );
+ MessageEnd();
+
+ if ( bIsBottle )
+ {
+ NotifyTargetPlayerEvent( pTFPlayer, m_iCurrentWaveIdx, kMVMEvent_Player_BoughtBottle, nCost );
+ }
+ else
+ {
+ NotifyTargetPlayerEvent( pTFPlayer, m_iCurrentWaveIdx, kMVMEvent_Player_BoughtUpgrade, nCost );
+ }
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::PlayerEvent_PickedUpCredits( CTFPlayer *pTFPlayer, uint32 idxWave, int nCreditsAmount )
+{
+ if ( pTFPlayer->IsBot() || !TFGameRules() || !TFGameRules()->IsPVEModeActive() )
+ return;
+
+ OnStatsChanged();
+ NotifyPlayerEvent( pTFPlayer, idxWave, kMVMEvent_Player_PickedUpCredits, nCreditsAmount );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::PlayerEvent_BoughtInstantRespawn( CTFPlayer *pTFPlayer, int nCost )
+{
+ if ( pTFPlayer->IsBot() || !TFGameRules() || !TFGameRules()->IsPVEModeActive() )
+ return;
+
+ m_currentWaveStats.nBuyBacks++;
+ OnStatsChanged();
+
+ NotifyTargetPlayerEvent( pTFPlayer, m_iCurrentWaveIdx, kMVMEvent_Player_BoughtInstantRespawn, nCost );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::PlayerEvent_DealtDamageToBots( CTFPlayer *pTFPlayer, int damage )
+{
+ if ( pTFPlayer->IsBot() || !TFGameRules() || !TFGameRules()->IsPVEModeActive() )
+ return;
+
+ m_playerStats[pTFPlayer->entindex()].nBotDamage += damage;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::PlayerEvent_DealtDamageToGiants( CTFPlayer *pTFPlayer, int damage )
+{
+ if ( pTFPlayer->IsBot() || !TFGameRules() || !TFGameRules()->IsPVEModeActive() )
+ return;
+
+ m_playerStats[pTFPlayer->entindex()].nGiantDamage += damage;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::PlayerEvent_DealtDamageToTanks( CTFPlayer *pTFPlayer, int damage )
+{
+ if ( pTFPlayer->IsBot() || !TFGameRules() || !TFGameRules()->IsPVEModeActive() )
+ return;
+
+ m_playerStats[pTFPlayer->entindex()].nTankDamage += damage;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::NotifyPlayerEvent( CTFPlayer *pTFPlayer, uint32 idxWave, eMannVsMachineEvent eType, int nValue, int nParam )
+{
+ // Deprecated
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::NotifyTargetPlayerEvent( CTFPlayer *pTFPlayer, uint32 idxWave, eMannVsMachineEvent eType, int nCost )
+{
+ CBroadcastRecipientFilter filter;
+ filter.MakeReliable();
+
+ // Client
+ UserMessageBegin( filter, "MVMLocalPlayerWaveSpendingValue" );
+ uint64 id = pTFPlayer->GetSteamIDAsUInt64();
+
+ WRITE_BITS( &id, 64 );
+ WRITE_BYTE( (uint8)idxWave );
+ WRITE_BYTE( (uint8)eType );
+ WRITE_WORD( (uint16)nCost );
+ MessageEnd();
+
+ // Server
+ uint64 steamID = pTFPlayer->GetSteamIDAsUInt64();
+ CPlayerWaveSpendingStats *pPlayerStats = g_pMVMStats->GetSpending( idxWave, steamID );
+ if ( !pPlayerStats )
+ return;
+
+ switch ( eType )
+ {
+ case kMVMEvent_Player_BoughtInstantRespawn:
+ // Don't track refunds (permanent cost)
+ pPlayerStats->nCreditsSpentOnBuyBacks += nCost;
+ break;
+ case kMVMEvent_Player_BoughtBottle:
+ // Don't track refunds (permanent cost)
+ pPlayerStats->nCreditsSpentOnBottles += nCost;
+ break;
+ case kMVMEvent_Player_BoughtUpgrade:
+ pPlayerStats->nCreditsSpentOnUpgrades += nCost;
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Tell the Player What Upgrades they have
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::SendUpgradesToPlayer( CTFPlayer *pTFPlayer, CUtlVector< CUpgradeInfo > *upgrades )
+{
+ CRecipientFilter filter;
+ filter.AddRecipient( pTFPlayer );
+
+ if ( upgrades == NULL )
+ {
+ UserMessageBegin( filter, "MVMLocalPlayerUpgradesClear" );
+ WRITE_BYTE( 0 );
+ MessageEnd();
+ return;
+ }
+
+ // Send the reset command
+ UserMessageBegin( filter, "MVMLocalPlayerUpgradesClear" );
+ WRITE_BYTE( 0 );
+ MessageEnd();
+
+ // send all the upgrades
+ // Class(1), ItemDef(2), Upgrade(1), cost(2)
+ for ( int i = 0; i < upgrades->Count(); ++i )
+ {
+ UserMessageBegin( filter, "MVMLocalPlayerUpgradesValue" );
+ WRITE_BYTE( (uint8)upgrades->Element(i).m_iPlayerClass );
+ WRITE_WORD( (uint16)upgrades->Element(i).m_itemDefIndex );
+ WRITE_BYTE( (uint8)upgrades->Element(i).m_upgrade );
+ WRITE_WORD( (uint16)upgrades->Element(i).m_nCost );
+ MessageEnd();
+ }
+}
+
+//=============================================================================//
+void CMannVsMachineStats::NotifyPlayerActiveUpgradeCosts( CTFPlayer *pTFPlayer, int nSpending )
+{
+ NotifyTargetPlayerEvent( pTFPlayer, 0, kMVMEvent_Player_ActiveUpgrades, nSpending );
+}
+#endif // GAME_DLL
+
+//-----------------------------------------------------------------------------
+// Purpose: Clear The Player spending stats for this wave
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::ClearCurrentPlayerWaveSpendingStats( int idxWave )
+{
+ // If the wave is different then the current, we're changing waves and need to save this stuff off if we're advancing
+
+ if ( idxWave != (int)m_iCurrentWaveIdx )
+ {
+ // if wave incremented, we changed waves to save off the previous wave data
+ m_prevWaveSpendingStats.RemoveAll();
+
+ FOR_EACH_MAP_FAST( m_currWaveSpendingStats, i )
+ {
+ // Save off current wave in to previous
+ int iWave = m_prevWaveSpendingStats.Insert(m_currWaveSpendingStats.Key(i), CPlayerWaveSpendingStats() );
+ m_prevWaveSpendingStats[iWave] = m_currWaveSpendingStats[i];
+
+ // Append current wave in to all prev
+ int allIndex = m_allPrevWaveSpendingStats.Find( m_currWaveSpendingStats.Key(i) );
+ if ( allIndex != m_allPrevWaveSpendingStats.InvalidIndex() )
+ {
+ m_allPrevWaveSpendingStats[allIndex] += m_currWaveSpendingStats[i];
+ }
+ else
+ {
+ allIndex = m_allPrevWaveSpendingStats.Insert( m_currWaveSpendingStats.Key(i), CPlayerWaveSpendingStats() );
+ m_allPrevWaveSpendingStats[allIndex] = m_currWaveSpendingStats[i];
+ }
+ }
+ }
+ // Purge away current stats
+ m_currWaveSpendingStats.RemoveAll();
+}
+
+//-----------------------------------------------------------------------------
+CPlayerWaveSpendingStats *CMannVsMachineStats::GetSpending( int iWaveIndex, uint64 steamId )
+{
+ if ( iWaveIndex == (int)m_iCurrentWaveIdx )
+ {
+ int iWave = m_currWaveSpendingStats.Find( steamId );
+ if ( iWave != m_currWaveSpendingStats.InvalidIndex() )
+ {
+ return &m_currWaveSpendingStats[iWave];
+ }
+ else
+ {
+ iWave = m_currWaveSpendingStats.Insert( steamId, CPlayerWaveSpendingStats() );
+ return &m_currWaveSpendingStats[iWave];
+ }
+ }
+ else if ( iWaveIndex == -1 )
+ {
+ int iWave = m_allPrevWaveSpendingStats.Find( steamId );
+ if ( iWave != m_allPrevWaveSpendingStats.InvalidIndex() )
+ {
+ return &m_allPrevWaveSpendingStats[iWave];
+ }
+ else
+ {
+ iWave = m_allPrevWaveSpendingStats.Insert( steamId, CPlayerWaveSpendingStats() );
+ return &m_allPrevWaveSpendingStats[iWave];
+ }
+ }
+ else if ( iWaveIndex == (int)(m_iCurrentWaveIdx - 1) )
+ {
+ int iWave = m_prevWaveSpendingStats.Find( steamId );
+ if ( iWave != m_prevWaveSpendingStats.InvalidIndex() )
+ {
+ return &m_prevWaveSpendingStats[iWave];
+ }
+ else
+ {
+ iWave = m_prevWaveSpendingStats.Insert( steamId, CPlayerWaveSpendingStats() );
+ return &m_prevWaveSpendingStats[iWave];
+ }
+ }
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+int CMannVsMachineStats::GetUpgradeSpending( CTFPlayer *pTFPlayer /*= NULL*/ )
+{
+ int spending = 0;
+
+ CSteamID steamID;
+ if ( pTFPlayer && pTFPlayer->GetSteamID( &steamID ) )
+ {
+ int iWave = m_currWaveSpendingStats.Find( steamID.ConvertToUint64() );
+ if ( iWave != m_currWaveSpendingStats.InvalidIndex() )
+ {
+ spending += m_currWaveSpendingStats[iWave].nCreditsSpentOnUpgrades;
+ }
+
+ iWave = m_allPrevWaveSpendingStats.Find( steamID.ConvertToUint64() );
+ if ( iWave != m_allPrevWaveSpendingStats.InvalidIndex() )
+ {
+ spending += m_allPrevWaveSpendingStats[iWave].nCreditsSpentOnUpgrades;
+ }
+ }
+ else
+ {
+ FOR_EACH_MAP_FAST ( m_currWaveSpendingStats, iPlayer )
+ {
+ CBasePlayer * pPlayer = GetPlayerBySteamID( CSteamID( m_currWaveSpendingStats.Key( iPlayer ) ) );
+ if ( pPlayer )
+ {
+ spending += m_currWaveSpendingStats[iPlayer].nCreditsSpentOnUpgrades;
+ }
+ }
+
+ FOR_EACH_MAP_FAST ( m_allPrevWaveSpendingStats, iPlayer )
+ {
+ CBasePlayer * pPlayer = GetPlayerBySteamID( CSteamID( m_allPrevWaveSpendingStats.Key( iPlayer ) ) );
+ if ( pPlayer )
+ {
+ spending += m_allPrevWaveSpendingStats[iPlayer].nCreditsSpentOnUpgrades;
+ }
+ }
+ }
+
+ return spending;
+}
+
+//-----------------------------------------------------------------------------
+int CMannVsMachineStats::GetBottleSpending( CTFPlayer *pTFPlayer /*= NULL*/ )
+{
+ int spending = 0;
+
+ CSteamID steamID;
+ if ( pTFPlayer && pTFPlayer->GetSteamID( &steamID ) )
+ {
+ int iWave = m_currWaveSpendingStats.Find( steamID.ConvertToUint64() );
+ if ( iWave != m_currWaveSpendingStats.InvalidIndex() )
+ {
+ spending += m_currWaveSpendingStats[iWave].nCreditsSpentOnBottles;
+ }
+
+ iWave = m_allPrevWaveSpendingStats.Find( steamID.ConvertToUint64() );
+ if ( iWave != m_allPrevWaveSpendingStats.InvalidIndex() )
+ {
+ spending += m_allPrevWaveSpendingStats[iWave].nCreditsSpentOnBottles;
+ }
+ }
+ else
+ {
+ FOR_EACH_MAP_FAST ( m_currWaveSpendingStats, iPlayer )
+ {
+ CBasePlayer * pPlayer = GetPlayerBySteamID( CSteamID( m_currWaveSpendingStats.Key( iPlayer ) ) );
+ if ( pPlayer )
+ {
+ spending += m_currWaveSpendingStats[iPlayer].nCreditsSpentOnBottles;
+ }
+ }
+
+ FOR_EACH_MAP_FAST ( m_allPrevWaveSpendingStats, iPlayer )
+ {
+ CBasePlayer * pPlayer = GetPlayerBySteamID( CSteamID( m_allPrevWaveSpendingStats.Key( iPlayer ) ) );
+ if ( pPlayer )
+ {
+ spending += m_allPrevWaveSpendingStats[iPlayer].nCreditsSpentOnBottles;
+ }
+ }
+ }
+
+ return spending;
+}
+
+//-----------------------------------------------------------------------------
+int CMannVsMachineStats::GetBuyBackSpending( CTFPlayer *pTFPlayer /*= NULL*/ )
+{
+ int spending = 0;
+
+ CSteamID steamID;
+ if ( pTFPlayer && pTFPlayer->GetSteamID( &steamID ) )
+ {
+ int iWave = m_currWaveSpendingStats.Find( steamID.ConvertToUint64() );
+ if ( iWave != m_currWaveSpendingStats.InvalidIndex() )
+ {
+ spending += m_currWaveSpendingStats[iWave].nCreditsSpentOnBuyBacks;
+ }
+
+ iWave = m_allPrevWaveSpendingStats.Find( steamID.ConvertToUint64() );
+ if ( iWave != m_allPrevWaveSpendingStats.InvalidIndex() )
+ {
+ spending += m_allPrevWaveSpendingStats[iWave].nCreditsSpentOnBuyBacks;
+ }
+ }
+ else
+ {
+ FOR_EACH_MAP_FAST ( m_currWaveSpendingStats, iPlayer )
+ {
+ CBasePlayer * pPlayer = GetPlayerBySteamID( CSteamID( m_currWaveSpendingStats.Key( iPlayer ) ) );
+ if ( pPlayer )
+ {
+ spending += m_currWaveSpendingStats[iPlayer].nCreditsSpentOnBuyBacks;
+ }
+ }
+
+ FOR_EACH_MAP_FAST ( m_allPrevWaveSpendingStats, iPlayer )
+ {
+ CBasePlayer * pPlayer = GetPlayerBySteamID( CSteamID( m_allPrevWaveSpendingStats.Key( iPlayer ) ) );
+ if ( pPlayer )
+ {
+ spending += m_allPrevWaveSpendingStats[iPlayer].nCreditsSpentOnBuyBacks;
+ }
+ }
+ }
+
+ return spending;
+}
+
+//=============================================================================//
+#ifdef CLIENT_DLL
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::OnDataChanged( DataUpdateType_t updateType )
+{
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Clear Local Player Upgrades
+//-----------------------------------------------------------------------------
+CPlayerWaveSpendingStats *CMannVsMachineStats::GetLocalSpending ( int iWaveIdx )
+{
+ CSteamID steamId;
+ if ( C_TFPlayer::GetLocalTFPlayer()->GetSteamID( &steamId ) )
+ {
+ return GetSpending( iWaveIdx, steamId.ConvertToUint64() );
+ }
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Set the active upgrade costs for this player
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::SetPlayerActiveUpgradeCosts( uint64 steamId, int nSpending )
+{
+ int iUpgrade = m_teamActiveUpgrades.Find(steamId);
+ if ( iUpgrade != m_teamActiveUpgrades.InvalidIndex() )
+ {
+ m_teamActiveUpgrades[iUpgrade] = nSpending;
+ }
+ else
+ {
+ m_teamActiveUpgrades.Insert( steamId, nSpending );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Get Player Active Upgrade Costs
+//-----------------------------------------------------------------------------
+int CMannVsMachineStats::GetPlayerActiveUpgradeCosts( uint64 steamId64 )
+{
+ // 0, give team total
+ if ( steamId64 == 0 )
+ {
+ int nSpending = 0;
+ FOR_EACH_MAP_FAST ( m_teamActiveUpgrades, i )
+ {
+ CSteamID steamId( m_teamActiveUpgrades.Key( i ) );
+ CBasePlayer * pPlayer = GetPlayerBySteamID( steamId );
+ if ( pPlayer )
+ {
+ nSpending += m_teamActiveUpgrades[ i ];
+ }
+ }
+
+ return nSpending;
+ }
+ else
+ {
+ CSteamID steamId( steamId64 );
+ CBasePlayer * pPlayer = GetPlayerBySteamID( steamId );
+ if ( pPlayer )
+ {
+ int iUpgrade = m_teamActiveUpgrades.Find( steamId64 );
+ if ( iUpgrade != m_teamActiveUpgrades.InvalidIndex() )
+ return m_teamActiveUpgrades[iUpgrade];
+ }
+ }
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Clear Local Player Upgrades
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::ClearLocalPlayerUpgrades ()
+{
+ m_vecLocalPlayerUpgrades.Purge();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Add Local Player Upgrade
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::AddLocalPlayerUpgrade ( int iPlayerClass, item_definition_index_t iItemDef )
+{
+ CUpgradeInfo upgrade;
+ upgrade.m_iPlayerClass = iPlayerClass;
+ upgrade.m_itemDefIndex = iItemDef;
+ upgrade.m_upgrade = 0;
+ upgrade.m_nCost = 0;
+
+ m_vecLocalPlayerUpgrades.AddToTail( upgrade );
+}
+
+//-----------------------------------------------------------------------------
+int CMannVsMachineStats::GetLocalPlayerUpgradeSpending( int idxWave )
+{
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( pPlayer == NULL )
+ return 0;
+
+ CPlayerWaveSpendingStats *pStats = GetLocalSpending( idxWave );
+ return pStats ? pStats->nCreditsSpentOnUpgrades : 0;
+}
+
+//-----------------------------------------------------------------------------
+int CMannVsMachineStats::GetLocalPlayerBottleSpending( int idxWave )
+{
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( pPlayer == NULL )
+ return 0;
+
+ CPlayerWaveSpendingStats *pStats = GetLocalSpending( idxWave );
+ return pStats ? pStats->nCreditsSpentOnBottles : 0;
+}
+
+//-----------------------------------------------------------------------------
+int CMannVsMachineStats::GetLocalPlayerBuyBackSpending ( int idxWave )
+{
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( pPlayer == NULL )
+ return 0;
+
+ CPlayerWaveSpendingStats *pStats = GetLocalSpending( idxWave );
+ return pStats ? pStats->nCreditsSpentOnBuyBacks : 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Submits the use of MvM Credits
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::SW_ReportClientUpgradePurchase( uint8 waveIdx, uint16 nItemDef, uint16 nAttributeDef, uint8 nQuality, int16 nCost )
+{
+ // Disabled due to bad key indexing.
+ // Make a V2 if this data is wanted
+
+// Old Table
+ //-----------------------------------------------------------------------------
+ // OGS TF2ClientMvMWaveCreditSpend: MvM mode - credit spend
+ //-----------------------------------------------------------------------------
+ //START_TABLE( k_ESchemaCatalogOGS, TF2ClientMvMWaveCreditSpend, TABLE_PROP_NORMAL )
+ //INT_FIELD( nID, ID, int32 ) // Auto-increment fake key
+ //INT_FIELD( llSessionID, SessionID, uint64 )
+ //INT_FIELD( llServerSessionID, ServerSessionID, uint64 ) // Duplicated data from Session table due to game client anomalies
+ //INT_FIELD( nServerWaveID, ServerWaveID, int32 ) // Incrementing WaveId PerAttempt
+ //INT_FIELD( ulAccountID, AccountID, uint64 ) // Duplicated data from Session table due to game client anomalies
+ //INT_FIELD( nWaveNumber, WaveNumber, uint8 )
+ //INT_FIELD( nItemCategoryID, MvMItemCategoryID, int16 ) // References TF2MvMItemCategoryReference
+ //INT_FIELD( nItemNameID, MvMItemNameID, int32 ) // References TF2MvMItemNameReference
+ //INT_FIELD( nItemCost, ItemCost, int32 )
+ //INT_FIELD( RTime32EventTime, EventTime, RTime32 )
+ //PRIMARY_KEY_CLUSTERED( 100, nID )
+ //WIPE_TABLE_BETWEEN_TESTS( k_EWipePolicyWipeForAllTests )
+ //AUTOINCREMENT_FIELD( nID )
+ //PARTITION_INTERVAL( k_EPartitionIntervalDaily )
+ //OWNING_APPLICATION( 440 )
+ //END_TABLE
+
+
+
+//#if !defined(NO_STEAM)
+// ConVar *sv_cheats = g_pCVar->FindVar( "sv_cheats" );
+// if ( sv_cheats && sv_cheats->GetBool() )
+// return;
+//
+// C_TFPlayer *pTFPlayer = C_TFPlayer::GetLocalTFPlayer();
+// if ( !pTFPlayer )
+// return;
+//
+// // Get Data needed for this report
+// const CEconItemAttributeDefinition *pAttributeDef = ItemSystem()->GetItemSchema()->GetAttributeDefinition( nAttributeDef );
+// if ( !pAttributeDef )
+// return;
+//
+// float flValue = 1.0f;
+// if ( !MannVsMachine_GetUpgradeInfo( pAttributeDef->GetDefinitionIndex(), nQuality, flValue ) )
+// return;
+//
+// CSteamID steamIDForPlayer;
+// if ( !pTFPlayer->GetSteamID( &steamIDForPlayer ) )
+// return;
+//
+// KeyValuesAD pKeyValues( "data" );
+//
+// // Create and Send the report
+// //SessionId, ServerSessionId, AccountID, ServerWaveID, WaveNumber, MvMItemCategoryID, MvMItemNameID, ItemCost, EventTime
+// KeyValues* pKVData = new KeyValues( "TF2ClientMvMWaveCreditSpend" );
+// pKVData->SetInt( "ID", ++m_nEventID );
+//
+// // ServerSessionID - Auto
+// // SessionID - Auto
+//
+// // AccountID
+// pKVData->SetUint64( "AccountID", steamIDForPlayer.ConvertToUint64() );
+//
+// //ServerWaveID - Use provided ID not m_iServerWaveID as that may have changed
+// pKVData->SetInt( "ServerWaveID", m_iServerWaveID );
+//
+// // WaveNumber
+// pKVData->SetInt( "WaveNumber", waveIdx + 1 );
+//
+// // MvMItemNameID
+// if ( nItemDef )
+// {
+// const CEconItemDefinition *pItemDef = ItemSystem()->GetItemSchema()->GetItemDefinition( nItemDef );
+// pKVData->SetString( "MvMItemNameID", pItemDef->GetDefinitionName() );
+// }
+// else
+// {
+// pKVData->SetString( "MvMItemNameID", g_aPlayerClassNames_NonLocalized[ pTFPlayer->GetPlayerClass()->GetClassIndex() ] );
+// }
+//
+// // MvMItemCategoryID
+// pKVData->SetString( "MvMItemCategoryID", pAttributeDef->GetDefinitionName() );
+//
+// // ItemCost
+// pKVData->SetInt( "ItemCost", nCost );
+//
+// // EventTime
+// pKVData->SetInt( "EventTime", GetSteamWorksSGameStatsUploader().GetTimeSinceEpoch() );
+//
+// // Send to DB
+// GetSteamWorksSGameStatsUploader().AddStatsForUpload( pKVData );
+//
+//#endif // !defined(NO_STEAM)
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Submits the use of MvM Credits
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::SW_ReportClientBuyBackPurchase ( uint8 waveIdx, uint16 nCost )
+{
+//#if !defined(NO_STEAM)
+// ConVar *sv_cheats = g_pCVar->FindVar( "sv_cheats" );
+// if ( sv_cheats && sv_cheats->GetBool() )
+// return;
+//
+// C_TFPlayer *pTFPlayer = C_TFPlayer::GetLocalTFPlayer();
+// if ( !pTFPlayer )
+// return;
+//
+// CSteamID steamIDForPlayer;
+// if ( !pTFPlayer->GetSteamID( &steamIDForPlayer ) )
+// return;
+//
+// // Create and Send the report
+// //SessionId, ServerSessionId, AccountID, ServerWaveID, WaveNumber, MvMItemCategoryID, MvMItemNameID, ItemCost, EventTime
+// KeyValues* pKVData = new KeyValues( "TF2ClientMvMWaveCreditSpend" );
+//
+// // ID - Auto
+// // ServerSessionID - Auto
+// // SessionID - Auto
+//
+// // AccountID
+// pKVData->SetUint64( "AccountID", steamIDForPlayer.ConvertToUint64() );
+//
+// //ServerWaveID - Use provided ID not m_iServerWaveID as that may have changed
+// pKVData->SetInt( "ServerWaveID", m_iServerWaveID );
+//
+// // WaveNumber
+// pKVData->SetInt( "WaveNumber", waveIdx + 1 );
+//
+// // MvMItemNameID
+// static char szAnsi[64];
+// g_pVGuiLocalize->ConvertUnicodeToANSI( g_pVGuiLocalize->Find( g_aPlayerClassNames[ pTFPlayer->GetPlayerClass()->GetClassIndex() ] ), szAnsi, sizeof(szAnsi) );
+// pKVData->SetString( "MvMItemNameID", szAnsi );
+//
+// // MvMItemCategoryID
+// pKVData->SetString( "MvMItemCategoryID", "BuyBack");
+//
+// // ItemCost
+// pKVData->SetInt( "ItemCost", nCost );
+//
+// // EventTime
+// pKVData->SetInt( "EventTime", GetSteamWorksSGameStatsUploader().GetTimeSinceEpoch() );
+//
+// // Send to DB
+// GetSteamWorksSGameStatsUploader().AddStatsForUpload( pKVData );
+//
+//#endif // !defined(NO_STEAM)
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Submits the use of MvM Credits
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::SW_ReportClientWaveSummary( uint16 waveID, CMannVsMachinePlayerStats stats )
+{
+ // Disabled due to bad key indexing.
+ // Make a V2 if this data is wanted
+ // Old Table
+ //-----------------------------------------------------------------------------
+ // OGS TF2ClientMvMWaveSummary: MvM mode � Player wave summary information
+ //-----------------------------------------------------------------------------
+ //START_TABLE( k_ESchemaCatalogOGS, TF2ClientMvMWaveSummary, TABLE_PROP_NORMAL )
+ //INT_FIELD( nID, ID, int32 ) // Auto-increment fake key
+ //INT_FIELD( nServerWaveID, ServerWaveID, int32 ) // ID of ServerMvMWaveSummary Entry this is linked with, How do we get this?
+ //INT_FIELD( llSessionID, SessionID, uint64 )
+ //INT_FIELD( llServerSessionID, ServerSessionID, uint64 ) // Duplicated data from Session table due to game client anomalies
+ //INT_FIELD( ulAccountID, AccountID, uint64 ) // Duplicated data from Session table due to game client anomalies
+ //INT_FIELD( nDamageToBots, DamageToBots, int32 )
+ //INT_FIELD( nDamageToTanks, DamageToTanks, int32 )
+ //INT_FIELD( nDamageToGiants, DamageToGiants, int32 )
+ //INT_FIELD( nDeaths, Deaths, uint8 )
+ //INT_FIELD( nClass, Class, int64 ) // References TF2ClassReference
+ //INT_FIELD( nPrimaryWeapon, PrimaryWeapon, int32 ) // References TF2MvMItemNameReference
+ //INT_FIELD( nSecondaryWeapon, SecondaryWeapon, int32 ) // References TF2MvMItemNameReference
+ //INT_FIELD( nMeleeWeapon, MeleeWeapon, int32 ) // References TF2MvMItemNameReference
+ //INT_FIELD( bHasBottle, HasBottle, int8 )
+ //PRIMARY_KEY_CLUSTERED( 100, nID )
+ //WIPE_TABLE_BETWEEN_TESTS( k_EWipePolicyWipeForAllTests )
+ //AUTOINCREMENT_FIELD( nID )
+ //PARTITION_INTERVAL( k_EPartitionIntervalDaily )
+ //OWNING_APPLICATION( 440 )
+ //END_TABLE
+
+
+//#if !defined(NO_STEAM)
+// ConVar *sv_cheats = g_pCVar->FindVar( "sv_cheats" );
+// if ( sv_cheats && sv_cheats->GetBool() )
+// return;
+//
+// C_TFPlayer *pTFPlayer = C_TFPlayer::GetLocalTFPlayer();
+// if ( !pTFPlayer )
+// return;
+//
+// CSteamID steamIDForPlayer;
+// if ( !pTFPlayer->GetSteamID( &steamIDForPlayer ) )
+// return;
+//
+// // Class
+// int iClass = pTFPlayer->GetPlayerClass()->GetClassIndex();
+//
+// // Invalid Class, Spectators?
+// if ( iClass < TF_FIRST_NORMAL_CLASS || iClass >= TF_LAST_NORMAL_CLASS )
+// return;
+//
+// // Create and Send the report
+// //[ID] ,[ServerWaveID] ,[SessionID] ,[AccountID] ,[DamageToBots] ,[DamageToTanks] ,[DamageToGiants]
+// //,[Deaths] ,[Class] ,[PrimaryWeapon] ,[SecondaryWeapon] ,[MeleeWeapon] ,[HasBottle]
+// KeyValues* pKVData = new KeyValues( "TF2ClientMvMWaveSummary" );
+// pKVData->SetInt( "ID", ++m_nEventID );
+//
+// // ServerSessionID - Auto
+// // SessionID - Auto
+//
+// // AccountID
+// pKVData->SetUint64( "AccountID", steamIDForPlayer.ConvertToUint64() );
+//
+// //Damage
+// pKVData->SetInt( "DamageToBots", stats.nBotDamage );
+// pKVData->SetInt( "DamageToGiants", stats.nGiantDamage );
+// pKVData->SetInt( "DamageToTanks", stats.nTankDamage );
+//
+// // Death
+// pKVData->SetInt( "Deaths", stats.nDeaths );
+//
+// //ServerWaveID - Use provided ID not m_iServerWaveID as that may have changed
+// pKVData->SetInt( "ServerWaveID", waveID );
+//
+// static char szAnsi[512];
+// pKVData->SetString( "Class", g_aPlayerClassNames_NonLocalized[ iClass ] );
+//
+// // Primary
+// CEconItemView *pPrimaryView = TFInventoryManager()->GetItemInLoadoutForClass( iClass, LOADOUT_POSITION_PRIMARY );
+// const CEconItemDefinition *pPrimaryDef = pPrimaryView->GetItemDefinition();
+//
+// if ( pPrimaryDef )
+// {
+// g_pVGuiLocalize->ConvertUnicodeToANSI( g_pVGuiLocalize->Find ( pPrimaryDef->GetItemBaseName() ) , szAnsi, sizeof(szAnsi) );
+// pKVData->SetString( "PrimaryWeapon", szAnsi );
+// }
+//
+// // Secondary
+// CEconItemView *pSecondaryView = TFInventoryManager()->GetItemInLoadoutForClass( iClass, LOADOUT_POSITION_SECONDARY );
+// const CEconItemDefinition *pSecondaryDef = pSecondaryView->GetItemDefinition();
+//
+// if ( pSecondaryDef )
+// {
+// g_pVGuiLocalize->ConvertUnicodeToANSI( g_pVGuiLocalize->Find ( pSecondaryDef->GetItemBaseName() ) , szAnsi, sizeof(szAnsi) );
+// pKVData->SetString( "SecondaryWeapon", szAnsi );
+// }
+//
+// // Melee
+// CEconItemView *pMeleeView = TFInventoryManager()->GetItemInLoadoutForClass( iClass, LOADOUT_POSITION_MELEE );
+// const CEconItemDefinition *pMeleeDef = pMeleeView->GetItemDefinition();
+//
+// if ( pMeleeDef )
+// {
+// g_pVGuiLocalize->ConvertUnicodeToANSI( g_pVGuiLocalize->Find ( pMeleeDef->GetItemBaseName() ) , szAnsi, sizeof(szAnsi) );
+// pKVData->SetString( "MeleeWeapon", szAnsi );
+// }
+//
+// // Check for power up bottle
+// CEconItemView *pActionView = TFInventoryManager()->GetItemInLoadoutForClass( iClass, LOADOUT_POSITION_ACTION );
+// //489 is bottle - Power Up Canteen (MvM)
+// pKVData->SetBool( "HasBottle", pActionView->GetItemDefIndex() == 489 );
+//
+// // Send to DB
+// GetSteamWorksSGameStatsUploader().AddStatsForUpload( pKVData );
+//
+//#endif // !defined(NO_STEAM)
+}
+#endif // CLIENT_DLL
+//=============================================================================//
+//-----------------------------------------------------------------------------
+// PRIVATE
+//-----------------------------------------------------------------------------
+// Purpose: Returns a copy of the WaveStats if legit
+//-----------------------------------------------------------------------------
+CMannVsMachineLocalWaveStats CMannVsMachineStats::GetWaveStats( int iWaveIdx )
+{
+ CMannVsMachineLocalWaveStats waveStats;
+
+ if ( iWaveIdx == (int)m_iCurrentWaveIdx )
+ {
+ waveStats = m_currentWaveStats;
+ }
+ else if ( iWaveIdx >= 0 && iWaveIdx == (int)m_iCurrentWaveIdx - 1 )
+ {
+ waveStats = m_previousWaveStats;
+ }
+ else if ( iWaveIdx == -1 )
+ {
+ waveStats = m_runningTotalWaveStats;
+ waveStats += m_previousWaveStats;
+ waveStats += m_currentWaveStats;
+ }
+ return waveStats;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Advances Event time for the next set of events
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::OnStatsChanged()
+{
+ NetworkStateChanged();
+}
+
+#ifdef GAME_DLL
+
+//-----------------------------------------------------------------------------
+// Purpose: Reset the tracked wave stats
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::ResetWaveStats()
+{
+ m_currentWaveStats.ClearStats();
+ m_nRespecsAwardedInWave = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Submits the WaveSummary Data to OGS
+//-----------------------------------------------------------------------------
+void CMannVsMachineStats::SW_ReportWaveSummary ( int waveIdx, bool bIsSuccess )
+{
+// Disabled due to bad key indexing.
+// Make a V2 if this data is wanted
+//#if !defined(NO_STEAM)
+// ConVar *sv_cheats = g_pCVar->FindVar( "sv_cheats" );
+// if ( sv_cheats && sv_cheats->GetBool() )
+// return;
+//
+// CMannVsMachineWaveStats stats;
+// if ( waveIdx == (int)m_iCurrentWaveIdx )
+// {
+// stats = m_currentWaveStats;
+// }
+// else if ( waveIdx == (int)m_iCurrentWaveIdx - 1)
+// {
+// stats = m_previousWaveStats;
+// }
+// else
+// {
+// return;
+// }
+//
+// KeyValues* pKVData = new KeyValues( "TF2ServerMvMWaveSummary" );
+//
+// // ServerSessionID - Auto
+// pKVData->SetUint64( "ServerSessionID", GetSteamWorksSGameStatsUploader().GetSessionID());
+// pKVData->SetInt( "ID", ++m_nEventID );
+// //ServerWaveID, if we won this wave, use the previous WaveID
+// int iServerWaveID = m_iServerWaveID;
+// if ( bIsSuccess )
+// {
+// iServerWaveID--;
+// }
+// pKVData->SetInt( "ServerWaveID", iServerWaveID );
+//
+// // WaveNumber
+// pKVData->SetInt( "WaveNumber", waveIdx + 1 );
+//
+// // PopulationFileID
+// pKVData->SetString( "PopulationFileID", m_pPopFileName );
+//
+// //// MoneyCollected
+// pKVData->SetInt( "MoneyCollected", stats.nCreditsAcquired );
+// //
+// //// MoneyMissed
+// pKVData->SetInt( "MoneyMissed", stats.nCreditsDropped - stats.nCreditsAcquired );
+// //
+// //// Attempts
+// pKVData->SetInt( "Attempts", stats.nAttempts );
+//
+// // IsSuccess
+// pKVData->SetBool( "IsSuccess", bIsSuccess );
+//
+// // IsSuccess
+// bool bMannUp = false;
+// bool bInLobby = false;
+// CTFLobby *pLobby = GTFGCClientSystem()->GetLobby();
+// if ( pLobby )
+// {
+// bInLobby = true;
+// bMannUp = IsMannUpGroup( pLobby->GetMatchGroup() );
+// }
+//
+// pKVData->SetBool( "IsTrustedServer", bInLobby );
+//
+// pKVData->SetBool( "IsMannUp", bMannUp );
+//
+// // EventTime
+// pKVData->SetInt( "EventTime", GetSteamWorksSGameStatsUploader().GetTimeSinceEpoch() );
+//
+// // Send to DB
+// GetSteamWorksSGameStatsUploader().AddStatsForUpload( pKVData );
+//
+//#endif // !defined(NO_STEAM)
+}
+
+#endif // GAME_DLL
+
+//-----------------------------------------------------------------------------
+// End CMannVsMachineStats
+//-----------------------------------------------------------------------------
+
+void MannVsMachineStats_Init()
+{
+#ifdef GAME_DLL
+ CBaseEntity::Create( "tf_mann_vs_machine_stats", vec3_origin, vec3_angle );
+#else
+ HOOK_MESSAGE( MVMPlayerEvent );
+ HOOK_MESSAGE( MVMResetPlayerStats );
+ HOOK_MESSAGE( MVMStatsReset );
+ HOOK_MESSAGE( MVMPlayerUpgradedEvent );
+ HOOK_MESSAGE( MVMLocalPlayerUpgradesClear );
+ HOOK_MESSAGE( MVMLocalPlayerUpgradesValue );
+ HOOK_MESSAGE( MVMResetPlayerWaveSpendingStats );
+ HOOK_MESSAGE( MVMLocalPlayerWaveSpendingValue );
+ HOOK_MESSAGE( MVMWaveChange );
+ HOOK_MESSAGE( MVMResetPlayerUpgradeSpending );
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Helper Functions
+//-----------------------------------------------------------------------------
+uint32 MannVsMachineStats_GetCurrentWave()
+{
+ return g_pMVMStats ? g_pMVMStats->GetCurrentWave() : 0;
+}
+
+uint32 MannVsMachineStats_GetAcquiredCredits( int idxWave /*= - 1 */, bool bIncludeBonus /*= true*/ )
+{
+ return g_pMVMStats ? g_pMVMStats->GetAcquiredCredits( idxWave, bIncludeBonus ) : 0;
+}
+
+uint32 MannVsMachineStats_GetDroppedCredits( int idxWave )
+{
+ return g_pMVMStats ? g_pMVMStats->GetDroppedCredits( idxWave ) : 0;
+}
+
+uint32 MannVsMachineStats_GetMissedCredits( int idxWave )
+{
+ return g_pMVMStats ? g_pMVMStats->GetMissedCredits( idxWave ) : 0;
+}
+
+CMannVsMachineStats *MannVsMachineStats_GetInstance()
+{
+ return g_pMVMStats;
+}
+
+
+#ifdef GAME_DLL
+
+void MannVsMachineStats_ResetPlayerEvents( CTFPlayer *pTFPlayer )
+{
+ if ( g_pMVMStats )
+ {
+ g_pMVMStats->ResetPlayerEvents( pTFPlayer );
+ }
+}
+
+void MannVsMachineStats_RoundEvent_CreditsDropped( uint32 waveIdx, int nAmount )
+{
+ if ( g_pMVMStats )
+ {
+ g_pMVMStats->RoundEvent_CreditsDropped( waveIdx, nAmount );
+ }
+}
+
+void MannVsMachineStats_PlayerEvent_PointsChanged( CTFPlayer *pTFPlayer, int nPoints )
+{
+ if ( g_pMVMStats )
+ {
+ g_pMVMStats->PlayerEvent_PointsChanged( pTFPlayer, nPoints );
+ }
+}
+
+void MannVsMachineStats_PlayerEvent_Died( CTFPlayer *pTFPlayer )
+{
+ if ( g_pMVMStats )
+ {
+ g_pMVMStats->PlayerEvent_Died( pTFPlayer );
+ }
+}
+
+void MannVsMachineStats_PlayerEvent_Upgraded( CTFPlayer *pTFPlayer, uint16 nItemDef, uint16 nAttributeDef, uint16 nQuality, int16 nCost, bool bIsBottle )
+{
+ if ( g_pMVMStats )
+ {
+ g_pMVMStats->PlayerEvent_Upgraded( pTFPlayer, nItemDef, nAttributeDef, nQuality, nCost, bIsBottle );
+ }
+}
+
+void MannVsMachineStats_PlayerEvent_PickedUpCredits( CTFPlayer *pTFPlayer, uint32 idxWave, int nCreditsAmount )
+{
+ if ( g_pMVMStats )
+ {
+ g_pMVMStats->PlayerEvent_PickedUpCredits( pTFPlayer, idxWave, nCreditsAmount );
+ }
+}
+
+void MannVsMachineStats_PlayerEvent_BoughtInstantRespawn( CTFPlayer *pTFPlayer, int nCost )
+{
+ if ( g_pMVMStats )
+ {
+ g_pMVMStats->PlayerEvent_BoughtInstantRespawn( pTFPlayer, nCost );
+ }
+}
+
+void MannVsMachineStats_SetPopulationFile( const char * pPopulationFile)
+{
+ if ( g_pMVMStats )
+ {
+ g_pMVMStats->SetPopFile( pPopulationFile );
+ }
+}
+
+#endif // GAME_DLL
+