//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFGameStats::Event_PlayerFiredWeapon( CTFPlayer *pPlayer, bool bCritical ) { // If normal gameplay state, track weapon stats. if ( TFGameRules()->State_Get() == GR_STATE_RND_RUNNING ) { CTFWeaponBase *pTFWeapon = pPlayer->GetActiveTFWeapon(); if ( pTFWeapon ) { // record shots fired in reported per-weapon stats int iWeaponID = pTFWeapon->GetWeaponID(); if ( m_reportedStats.m_pCurrentGame != NULL ) { TF_Gamestats_WeaponStats_t *pWeaponStats = &m_reportedStats.m_pCurrentGame->m_aWeaponStats[iWeaponID]; pWeaponStats->iShotsFired++; if ( bCritical ) { pWeaponStats->iCritShotsFired++; } } } } IncrementStat( pPlayer, TFSTAT_SHOTS_FIRED, 1 ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFGameStats::Event_PlayerUsedTeleport( CTFPlayer *pTeleportOwner, CTFPlayer *pTeleportingPlayer ) { // We don't count the builder's teleports if ( pTeleportOwner != pTeleportingPlayer ) { IncrementStat( pTeleportOwner, TFSTAT_TELEPORTS, 1 ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFGameStats::Event_PlayerDestroyedBuilding( CTFPlayer *pPlayer, CBaseObject *pBuilding ) { // sappers are buildings from the code's point of view but not from the player's, don't count them CObjectSapper *pSapper = dynamic_cast<CObjectSapper *>( pBuilding ); if ( pSapper ) return; IncrementStat( pPlayer, TFSTAT_BUILDINGSDESTROYED, 1 ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFGameStats::Event_AssistDestroyBuilding( CTFPlayer *pPlayer, CBaseObject *pBuilding ) { // sappers are buildings from the code's point of view but not from the player's, don't count them CObjectSapper *pSapper = dynamic_cast<CObjectSapper *>( pBuilding ); if ( pSapper ) return; IncrementStat( pPlayer, TFSTAT_KILLASSISTS, 1 ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFGameStats::Event_PlayerCapturedPoint( CTFPlayer *pPlayer ) { // increment player stats IncrementStat( pPlayer, TFSTAT_CAPTURES, 1 ); // increment reported stats int iClass = pPlayer->GetPlayerClass()->GetClassIndex(); if ( m_reportedStats.m_pCurrentGame != NULL ) { m_reportedStats.m_pCurrentGame->m_aClassStats[iClass].iCaptures++; } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFGameStats::Event_AssistKill( CTFPlayer *pAttacker, CBaseEntity *pVictim ) { // increment player's stat IncrementStat( pAttacker, TFSTAT_KILLASSISTS, 1 ); // increment reported class stats int iClass = pAttacker->GetPlayerClass()->GetClassIndex(); if ( m_reportedStats.m_pCurrentGame != NULL ) { m_reportedStats.m_pCurrentGame->m_aClassStats[iClass].iAssists++; } if ( pVictim->IsPlayer() ) { // keep track of how many times every player kills every other player CTFPlayer *pPlayerVictim = ToTFPlayer( pVictim ); TrackKillStats( pAttacker, pPlayerVictim ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFGameStats::Event_PlayerLeachedHealth( CTFPlayer *pPlayer, bool bDispenserHeal, float amount ) { if ( !bDispenserHeal ) { // If this was a heal by enemy medic and the first such heal that the server is aware of for this player, // send an achievement event to client. On the client, it will award achievement if player doesn't have it yet PlayerStats_t &stats = m_aPlayerStats[pPlayer->entindex()]; if ( 0 == stats.statsAccumulated.m_iStat[TFSTAT_HEALTHLEACHED] ) { CSingleUserRecipientFilter filter( pPlayer ); UserMessageBegin( filter, "AchievementEvent" ); WRITE_BYTE( ACHIEVEMENT_TF_GET_HEALED_BYENEMY ); MessageEnd(); } } IncrementStat( pPlayer, TFSTAT_HEALTHLEACHED, (int) amount ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFGameStats::Event_PlayerKilledOther( CBasePlayer *pAttacker, CBaseEntity *pVictim, const CTakeDamageInfo &info ) { // This also gets called when the victim is a building. That gets tracked separately as building destruction, don't count it here if ( !pVictim->IsPlayer() ) return; CTFPlayer *pPlayerAttacker = static_cast< CTFPlayer * >( pAttacker ); IncrementStat( pPlayerAttacker, TFSTAT_KILLS, 1 ); // keep track of how many times every player kills every other player CTFPlayer *pPlayerVictim = ToTFPlayer( pVictim ); TrackKillStats( pAttacker, pPlayerVictim ); int iClass = pPlayerAttacker->GetPlayerClass()->GetClassIndex(); if ( m_reportedStats.m_pCurrentGame != NULL ) { m_reportedStats.m_pCurrentGame->m_aClassStats[iClass].iKills++; } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFGameStats::Event_PlayerDamage( CBasePlayer *pBasePlayer, const CTakeDamageInfo &info, int iDamageTaken ) { CObjectSentrygun *pSentry = NULL; CTFPlayer *pTarget = ToTFPlayer( pBasePlayer ); CTFPlayer *pAttacker = ToTFPlayer( info.GetAttacker() ); if ( !pAttacker ) { pSentry = dynamic_cast< CObjectSentrygun * >( info.GetAttacker() ); if ( !pSentry ) return; pAttacker = pSentry->GetOwner(); if ( !pAttacker ) { // Sentry with no builder? Must be a pre-placed sentry. // It's easier to just cut off here and don't count damage. return; } } // don't count damage to yourself if ( pTarget == pAttacker ) return; IncrementStat( pAttacker, TFSTAT_DAMAGE, iDamageTaken ); TF_Gamestats_LevelStats_t::PlayerDamageLump_t damage; Vector killerOrg; // set the location where the target was hit const Vector &org = pTarget->GetAbsOrigin(); damage.nTargetPosition[ 0 ] = static_cast<int>( org.x ); damage.nTargetPosition[ 1 ] = static_cast<int>( org.y ); damage.nTargetPosition[ 2 ] = static_cast<int>( org.z ); // set the class of the attacker CBaseEntity *pInflictor = info.GetInflictor(); CBasePlayer *pScorer = TFGameRules()->GetDeathScorer( pAttacker, pInflictor, pTarget ); if ( !pSentry ) { pSentry = dynamic_cast< CObjectSentrygun * >( pInflictor ); } if ( pSentry != NULL ) { killerOrg = pSentry->GetAbsOrigin(); damage.iAttackClass = TF_CLASS_ENGINEER; damage.iWeapon = ( info.GetDamageType() & DMG_BLAST ) ? TF_WEAPON_SENTRY_ROCKET : TF_WEAPON_SENTRY_BULLET; } else if ( dynamic_cast<CObjectDispenser *>( pInflictor ) ) { damage.iAttackClass = TF_CLASS_ENGINEER; damage.iWeapon = TF_WEAPON_DISPENSER; } else { CTFPlayer *pTFAttacker = ToTFPlayer( pScorer ); if ( pTFAttacker ) { CTFPlayerClass *pAttackerClass = pTFAttacker->GetPlayerClass(); damage.iAttackClass = ( !pAttackerClass ) ? TF_CLASS_UNDEFINED : pAttackerClass->GetClassIndex(); killerOrg = pTFAttacker->GetAbsOrigin(); } else { damage.iAttackClass = TF_CLASS_UNDEFINED; killerOrg = org; } // find the weapon the killer used damage.iWeapon = GetWeaponFromDamage( info ); } // If normal gameplay state, track weapon stats. if ( ( TFGameRules()->State_Get() == GR_STATE_RND_RUNNING ) && ( damage.iWeapon != TF_WEAPON_NONE ) ) { // record hits & damage in reported per-weapon stats if ( m_reportedStats.m_pCurrentGame != NULL ) { TF_Gamestats_WeaponStats_t *pWeaponStats = &m_reportedStats.m_pCurrentGame->m_aWeaponStats[damage.iWeapon]; pWeaponStats->iHits++; pWeaponStats->iTotalDamage += iDamageTaken; // Try and figure out where the damage is coming from Vector vecDamageOrigin = info.GetReportedPosition(); // If we didn't get an origin to use, try using the attacker's origin if ( vecDamageOrigin == vec3_origin ) { if ( pSentry ) { vecDamageOrigin = pSentry->GetAbsOrigin(); } else { vecDamageOrigin = killerOrg; } } if ( vecDamageOrigin != vec3_origin ) { pWeaponStats->iHitsWithKnownDistance++; int iDistance = (int) vecDamageOrigin.DistTo( pBasePlayer->GetAbsOrigin() ); // Msg( "Damage distance: %d\n", iDistance ); pWeaponStats->iTotalDistance += iDistance; } } } Assert( damage.iAttackClass != TF_CLASS_UNDEFINED ); // record the time the damage occurred damage.fTime = gpGlobals->curtime; // store the attacker's position damage.nAttackerPosition[ 0 ] = static_cast<int>( killerOrg.x ); damage.nAttackerPosition[ 1 ] = static_cast<int>( killerOrg.y ); damage.nAttackerPosition[ 2 ] = static_cast<int>( killerOrg.z ); // set the class of the target CTFPlayer *pTFPlayer = ToTFPlayer( pTarget ); CTFPlayerClass *pTargetClass = ( pTFPlayer ) ? pTFPlayer->GetPlayerClass() : NULL; damage.iTargetClass = ( !pTargetClass ) ? TF_CLASS_UNDEFINED : pTargetClass->GetClassIndex(); Assert( damage.iTargetClass != TF_CLASS_UNDEFINED ); // record the damage done damage.iDamage = info.GetDamage(); // record if it was a crit damage.iCrit = ( ( info.GetDamageType() & DMG_CRITICAL ) != 0 ); // record if it was a kill damage.iKill = ( pTarget->GetHealth() <= 0 ); // add it to the list of damages if ( m_reportedStats.m_pCurrentGame != NULL ) { m_reportedStats.m_pCurrentGame->m_aPlayerDamage.AddToTail( damage ); } }
void IncrementMagic(void) { IncrementStat(&characterData.stats.magic); }
void IncrementMagicDefense(void) { IncrementStat(&characterData.stats.magicDefense); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFGameStats::Event_Backstab( CTFPlayer *pKiller ) { IncrementStat( pKiller, TFSTAT_BACKSTABS, 1 ); }
void IncrementDefense(void) { IncrementStat(&characterData.stats.defense); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFGameStats::Event_PlayerRevenge( CTFPlayer *pAttacker ) { IncrementStat( pAttacker, TFSTAT_REVENGE, 1 ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFGameStats::Event_PlayerDefendedPoint( CTFPlayer *pPlayer ) { IncrementStat( pPlayer, TFSTAT_DEFENSES, 1 ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFGameStats::Event_PlayerInvulnerable( CTFPlayer *pPlayer ) { IncrementStat( pPlayer, TFSTAT_INVULNS, 1 ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFGameStats::Event_PlayerHealedOther( CTFPlayer *pPlayer, float amount ) { IncrementStat( pPlayer, TFSTAT_HEALING, (int) amount ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFGameStats::Event_PlayerDominatedOther( CTFPlayer *pAttacker ) { IncrementStat( pAttacker, TFSTAT_DOMINATIONS, 1 ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFGameStats::Event_Headshot( CTFPlayer *pKiller ) { IncrementStat( pKiller, TFSTAT_HEADSHOTS, 1 ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFGameStats::Event_PlayerKilled( CBasePlayer *pPlayer, const CTakeDamageInfo &info ) { Assert( pPlayer ); CTFPlayer *pTFPlayer = ToTFPlayer( pPlayer ); IncrementStat( pTFPlayer, TFSTAT_DEATHS, 1 ); SendStatsToPlayer( pTFPlayer, STATMSG_PLAYERDEATH ); AccumulateAndResetPerLifeStats( pTFPlayer ); TF_Gamestats_LevelStats_t::PlayerDeathsLump_t death; Vector killerOrg; // set the location where the target died const Vector &org = pPlayer->GetAbsOrigin(); death.nPosition[ 0 ] = static_cast<int>( org.x ); death.nPosition[ 1 ] = static_cast<int>( org.y ); death.nPosition[ 2 ] = static_cast<int>( org.z ); // set the class of the attacker CBaseEntity *pInflictor = info.GetInflictor(); CBaseEntity *pKiller = info.GetAttacker(); CTFPlayer *pScorer = ToTFPlayer( TFGameRules()->GetDeathScorer( pKiller, pInflictor, pPlayer ) ); if ( dynamic_cast< CObjectSentrygun * >( pInflictor ) != NULL ) { killerOrg = pInflictor->GetAbsOrigin(); } else { if ( pScorer ) { CTFPlayerClass *pAttackerClass = pScorer->GetPlayerClass(); death.iAttackClass = ( !pAttackerClass ) ? TF_CLASS_UNDEFINED : pAttackerClass->GetClassIndex(); killerOrg = pScorer->GetAbsOrigin(); } else { death.iAttackClass = TF_CLASS_UNDEFINED; killerOrg = org; } } // set the class of the target CTFPlayerClass *pTargetClass = ( pTFPlayer ) ? pTFPlayer->GetPlayerClass() : NULL; death.iTargetClass = ( !pTargetClass ) ? TF_CLASS_UNDEFINED : pTargetClass->GetClassIndex(); // find the weapon the killer used death.iWeapon = GetWeaponFromDamage( info ); // calculate the distance to the killer death.iDistance = static_cast<unsigned short>( ( killerOrg - org ).Length() ); // add it to the list of deaths TF_Gamestats_LevelStats_t *map = m_reportedStats.m_pCurrentGame; if ( map ) { map->m_aPlayerDeaths.AddToTail( death ); int iClass = ToTFPlayer( pPlayer )->GetPlayerClass()->GetClassIndex(); if ( m_reportedStats.m_pCurrentGame != NULL ) { m_reportedStats.m_pCurrentGame->m_aClassStats[iClass].iDeaths++; m_reportedStats.m_pCurrentGame->m_aClassStats[iClass].iTotalTime += (int) ( gpGlobals->curtime - pTFPlayer->GetSpawnTime() ); } } }
void IncrementStrength(void) { IncrementStat(&characterData.stats.strength); }