//----------------------------------------------------------------------------- // Purpose: Add damage to the existing multidamage, and apply if it won't fit //----------------------------------------------------------------------------- void AddMultiDamage( const CTakeDamageInfo &info, CBaseEntity *pEntity ) { if ( !pEntity ) return; if ( pEntity != g_MultiDamage.GetTarget() ) { ApplyMultiDamage(); g_MultiDamage.Init( pEntity, info.GetInflictor(), info.GetAttacker(), info.GetWeapon(), vec3_origin, vec3_origin, vec3_origin, 0.0, info.GetDamageType(), info.GetDamageCustom() ); } g_MultiDamage.AddDamageType( info.GetDamageType() ); g_MultiDamage.SetDamage( g_MultiDamage.GetDamage() + info.GetDamage() ); g_MultiDamage.SetDamageForce( g_MultiDamage.GetDamageForce() + info.GetDamageForce() ); g_MultiDamage.SetDamagePosition( info.GetDamagePosition() ); g_MultiDamage.SetReportedPosition( info.GetReportedPosition() ); g_MultiDamage.SetMaxDamage( MAX( g_MultiDamage.GetMaxDamage(), info.GetDamage() ) ); g_MultiDamage.SetAmmoType( info.GetAmmoType() ); if ( g_MultiDamage.GetPlayerPenetrationCount() == 0 ) { g_MultiDamage.SetPlayerPenetrationCount( info.GetPlayerPenetrationCount() ); } bool bHasPhysicsForceDamage = !g_pGameRules->Damage_NoPhysicsForce( info.GetDamageType() ); if ( bHasPhysicsForceDamage && g_MultiDamage.GetDamageType() != DMG_GENERIC ) { // If you hit this assert, you've called TakeDamage with a damage type that requires a physics damage // force & position without specifying one or both of them. Decide whether your damage that's causing // this is something you believe should impart physics force on the receiver. If it is, you need to // setup the damage force & position inside the CTakeDamageInfo (Utility functions for this are in // takedamageinfo.cpp. If you think the damage shouldn't cause force (unlikely!) then you can set the // damage type to DMG_GENERIC, or | DMG_CRUSH if you need to preserve the damage type for purposes of HUD display. if ( g_MultiDamage.GetDamageForce() == vec3_origin || g_MultiDamage.GetDamagePosition() == vec3_origin ) { static int warningCount = 0; if ( ++warningCount < 10 ) { if ( g_MultiDamage.GetDamageForce() == vec3_origin ) { Warning( "AddMultiDamage: g_MultiDamage.GetDamageForce() == vec3_origin\n" ); } if ( g_MultiDamage.GetDamagePosition() == vec3_origin) { Warning( "AddMultiDamage: g_MultiDamage.GetDamagePosition() == vec3_origin\n" ); } } } } }
//----------------------------------------------------------------------------- // 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 ); } }