aboutsummaryrefslogtreecommitdiff
path: root/sp/src/game/shared/takedamageinfo.cpp
diff options
context:
space:
mode:
authorJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
committerJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
commit39ed87570bdb2f86969d4be821c94b722dc71179 (patch)
treeabc53757f75f40c80278e87650ea92808274aa59 /sp/src/game/shared/takedamageinfo.cpp
downloadsource-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz
source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip
First version of the SOurce SDK 2013
Diffstat (limited to 'sp/src/game/shared/takedamageinfo.cpp')
-rw-r--r--sp/src/game/shared/takedamageinfo.cpp495
1 files changed, 495 insertions, 0 deletions
diff --git a/sp/src/game/shared/takedamageinfo.cpp b/sp/src/game/shared/takedamageinfo.cpp
new file mode 100644
index 00000000..1c3817ad
--- /dev/null
+++ b/sp/src/game/shared/takedamageinfo.cpp
@@ -0,0 +1,495 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "takedamageinfo.h"
+#include "ammodef.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+ConVar phys_pushscale( "phys_pushscale", "1", FCVAR_REPLICATED );
+
+BEGIN_SIMPLE_DATADESC( CTakeDamageInfo )
+ DEFINE_FIELD( m_vecDamageForce, FIELD_VECTOR ),
+ DEFINE_FIELD( m_vecDamagePosition, FIELD_POSITION_VECTOR),
+ DEFINE_FIELD( m_vecReportedPosition, FIELD_POSITION_VECTOR),
+ DEFINE_FIELD( m_hInflictor, FIELD_EHANDLE),
+ DEFINE_FIELD( m_hAttacker, FIELD_EHANDLE),
+ DEFINE_FIELD( m_hWeapon, FIELD_EHANDLE),
+ DEFINE_FIELD( m_flDamage, FIELD_FLOAT),
+ DEFINE_FIELD( m_flMaxDamage, FIELD_FLOAT),
+ DEFINE_FIELD( m_flBaseDamage, FIELD_FLOAT ),
+ DEFINE_FIELD( m_bitsDamageType, FIELD_INTEGER),
+ DEFINE_FIELD( m_iDamageCustom, FIELD_INTEGER),
+ DEFINE_FIELD( m_iDamageStats, FIELD_INTEGER),
+ DEFINE_FIELD( m_iAmmoType, FIELD_INTEGER),
+ DEFINE_FIELD( m_iDamagedOtherPlayers, FIELD_INTEGER),
+END_DATADESC()
+
+void CTakeDamageInfo::Init( CBaseEntity *pInflictor, CBaseEntity *pAttacker, CBaseEntity *pWeapon, const Vector &damageForce, const Vector &damagePosition, const Vector &reportedPosition, float flDamage, int bitsDamageType, int iCustomDamage )
+{
+ m_hInflictor = pInflictor;
+ if ( pAttacker )
+ {
+ m_hAttacker = pAttacker;
+ }
+ else
+ {
+ m_hAttacker = pInflictor;
+ }
+
+ m_hWeapon = pWeapon;
+
+ m_flDamage = flDamage;
+
+ m_flBaseDamage = BASEDAMAGE_NOT_SPECIFIED;
+
+ m_bitsDamageType = bitsDamageType;
+ m_iDamageCustom = iCustomDamage;
+
+ m_flMaxDamage = flDamage;
+ m_vecDamageForce = damageForce;
+ m_vecDamagePosition = damagePosition;
+ m_vecReportedPosition = reportedPosition;
+ m_iAmmoType = -1;
+ m_iDamagedOtherPlayers = 0;
+
+ m_iPlayerPenetrationCount = 0;
+ m_flDamageBonus = 0.f;
+}
+
+CTakeDamageInfo::CTakeDamageInfo()
+{
+ Init( NULL, NULL, NULL, vec3_origin, vec3_origin, vec3_origin, 0, 0, 0 );
+}
+
+CTakeDamageInfo::CTakeDamageInfo( CBaseEntity *pInflictor, CBaseEntity *pAttacker, float flDamage, int bitsDamageType, int iKillType )
+{
+ Set( pInflictor, pAttacker, flDamage, bitsDamageType, iKillType );
+}
+
+CTakeDamageInfo::CTakeDamageInfo( CBaseEntity *pInflictor, CBaseEntity *pAttacker, CBaseEntity *pWeapon, float flDamage, int bitsDamageType, int iKillType )
+{
+ Set( pInflictor, pAttacker, pWeapon, flDamage, bitsDamageType, iKillType );
+}
+
+CTakeDamageInfo::CTakeDamageInfo( CBaseEntity *pInflictor, CBaseEntity *pAttacker, const Vector &damageForce, const Vector &damagePosition, float flDamage, int bitsDamageType, int iKillType, Vector *reportedPosition )
+{
+ Set( pInflictor, pAttacker, damageForce, damagePosition, flDamage, bitsDamageType, iKillType, reportedPosition );
+}
+
+CTakeDamageInfo::CTakeDamageInfo( CBaseEntity *pInflictor, CBaseEntity *pAttacker, CBaseEntity *pWeapon, const Vector &damageForce, const Vector &damagePosition, float flDamage, int bitsDamageType, int iKillType, Vector *reportedPosition )
+{
+ Set( pInflictor, pAttacker, pWeapon, damageForce, damagePosition, flDamage, bitsDamageType, iKillType, reportedPosition );
+}
+
+void CTakeDamageInfo::Set( CBaseEntity *pInflictor, CBaseEntity *pAttacker, float flDamage, int bitsDamageType, int iKillType )
+{
+ Init( pInflictor, pAttacker, NULL, vec3_origin, vec3_origin, vec3_origin, flDamage, bitsDamageType, iKillType );
+}
+
+void CTakeDamageInfo::Set( CBaseEntity *pInflictor, CBaseEntity *pAttacker, CBaseEntity *pWeapon, float flDamage, int bitsDamageType, int iKillType )
+{
+ Init( pInflictor, pAttacker, pWeapon, vec3_origin, vec3_origin, vec3_origin, flDamage, bitsDamageType, iKillType );
+}
+
+void CTakeDamageInfo::Set( CBaseEntity *pInflictor, CBaseEntity *pAttacker, const Vector &damageForce, const Vector &damagePosition, float flDamage, int bitsDamageType, int iKillType, Vector *reportedPosition )
+{
+ Set( pInflictor, pAttacker, NULL, damageForce, damagePosition, flDamage, bitsDamageType, iKillType, reportedPosition );
+}
+
+void CTakeDamageInfo::Set( CBaseEntity *pInflictor, CBaseEntity *pAttacker, CBaseEntity *pWeapon, const Vector &damageForce, const Vector &damagePosition, float flDamage, int bitsDamageType, int iKillType, Vector *reportedPosition )
+{
+ Vector vecReported = vec3_origin;
+ if ( reportedPosition )
+ {
+ vecReported = *reportedPosition;
+ }
+ Init( pInflictor, pAttacker, pWeapon, damageForce, damagePosition, vecReported, flDamage, bitsDamageType, iKillType );
+}
+
+//-----------------------------------------------------------------------------
+// Squirrel the damage value away as BaseDamage, which will later be used to
+// calculate damage force.
+//-----------------------------------------------------------------------------
+void CTakeDamageInfo::AdjustPlayerDamageInflictedForSkillLevel()
+{
+#ifndef CLIENT_DLL
+ CopyDamageToBaseDamage();
+ SetDamage( g_pGameRules->AdjustPlayerDamageInflicted(GetDamage()) );
+#endif
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CTakeDamageInfo::AdjustPlayerDamageTakenForSkillLevel()
+{
+#ifndef CLIENT_DLL
+ CopyDamageToBaseDamage();
+ g_pGameRules->AdjustPlayerDamageTaken(this);
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: get the name of the ammo that caused damage
+// Note: returns the ammo name, or the classname of the object, or the model name in the case of physgun ammo.
+//-----------------------------------------------------------------------------
+const char *CTakeDamageInfo::GetAmmoName() const
+{
+ const char *pszAmmoType;
+
+ if ( m_iAmmoType >= 0 )
+ {
+ pszAmmoType = GetAmmoDef()->GetAmmoOfIndex( m_iAmmoType )->pName;
+ }
+ // no ammoType, so get the ammo name from the inflictor
+ else if ( m_hInflictor != NULL )
+ {
+ pszAmmoType = m_hInflictor->GetClassname();
+
+ // check for physgun ammo. unfortunate that this is in game_shared.
+ if ( Q_strcmp( pszAmmoType, "prop_physics" ) == 0 )
+ {
+ pszAmmoType = STRING( m_hInflictor->GetModelName() );
+ }
+ }
+ else
+ {
+ pszAmmoType = "Unknown";
+ }
+
+ return pszAmmoType;
+}
+
+// -------------------------------------------------------------------------------------------------- //
+// MultiDamage
+// Collects multiple small damages into a single damage
+// -------------------------------------------------------------------------------------------------- //
+BEGIN_SIMPLE_DATADESC_( CMultiDamage, CTakeDamageInfo )
+ DEFINE_FIELD( m_hTarget, FIELD_EHANDLE),
+END_DATADESC()
+
+CMultiDamage g_MultiDamage;
+
+CMultiDamage::CMultiDamage()
+{
+ m_hTarget = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiDamage::Init( CBaseEntity *pTarget, CBaseEntity *pInflictor, CBaseEntity *pAttacker, CBaseEntity *pWeapon, const Vector &damageForce, const Vector &damagePosition, const Vector &reportedPosition, float flDamage, int bitsDamageType, int iKillType )
+{
+ m_hTarget = pTarget;
+ BaseClass::Init( pInflictor, pAttacker, pWeapon, damageForce, damagePosition, reportedPosition, flDamage, bitsDamageType, iKillType );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Resets the global multi damage accumulator
+//-----------------------------------------------------------------------------
+void ClearMultiDamage( void )
+{
+ g_MultiDamage.Init( NULL, NULL, NULL, NULL, vec3_origin, vec3_origin, vec3_origin, 0, 0, 0 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: inflicts contents of global multi damage register on gMultiDamage.pEntity
+//-----------------------------------------------------------------------------
+void ApplyMultiDamage( void )
+{
+ Vector vecSpot1;//where blood comes from
+ Vector vecDir;//direction blood should go
+ trace_t tr;
+
+ if ( !g_MultiDamage.GetTarget() )
+ return;
+
+#ifndef CLIENT_DLL
+ const CBaseEntity *host = te->GetSuppressHost();
+ te->SetSuppressHost( NULL );
+
+ g_MultiDamage.GetTarget()->TakeDamage( g_MultiDamage );
+
+ te->SetSuppressHost( (CBaseEntity*)host );
+#endif
+
+ // Damage is done, clear it out
+ ClearMultiDamage();
+}
+
+//-----------------------------------------------------------------------------
+// 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" );
+ }
+ }
+ }
+ }
+}
+
+
+//============================================================================================================
+// Utility functions for physics damage force calculation
+//============================================================================================================
+//-----------------------------------------------------------------------------
+// Purpose: Returns an impulse scale required to push an object.
+// Input : flTargetMass - Mass of the target object, in kg
+// flDesiredSpeed - Desired speed of the target, in inches/sec.
+//-----------------------------------------------------------------------------
+float ImpulseScale( float flTargetMass, float flDesiredSpeed )
+{
+ return (flTargetMass * flDesiredSpeed);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Fill out a takedamageinfo with a damage force for an explosive
+//-----------------------------------------------------------------------------
+void CalculateExplosiveDamageForce( CTakeDamageInfo *info, const Vector &vecDir, const Vector &vecForceOrigin, float flScale )
+{
+ info->SetDamagePosition( vecForceOrigin );
+
+ float flClampForce = ImpulseScale( 75, 400 );
+
+ // Calculate an impulse large enough to push a 75kg man 4 in/sec per point of damage
+ float flForceScale = info->GetBaseDamage() * ImpulseScale( 75, 4 );
+
+ if( flForceScale > flClampForce )
+ flForceScale = flClampForce;
+
+ // Fudge blast forces a little bit, so that each
+ // victim gets a slightly different trajectory.
+ // This simulates features that usually vary from
+ // person-to-person variables such as bodyweight,
+ // which are all indentical for characters using the same model.
+ flForceScale *= random->RandomFloat( 0.85, 1.15 );
+
+ // Calculate the vector and stuff it into the takedamageinfo
+ Vector vecForce = vecDir;
+ VectorNormalize( vecForce );
+ vecForce *= flForceScale;
+ vecForce *= phys_pushscale.GetFloat();
+ vecForce *= flScale;
+ info->SetDamageForce( vecForce );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Fill out a takedamageinfo with a damage force for a bullet impact
+//-----------------------------------------------------------------------------
+void CalculateBulletDamageForce( CTakeDamageInfo *info, int iBulletType, const Vector &vecBulletDir, const Vector &vecForceOrigin, float flScale )
+{
+ info->SetDamagePosition( vecForceOrigin );
+ Vector vecForce = vecBulletDir;
+ VectorNormalize( vecForce );
+ vecForce *= GetAmmoDef()->DamageForce( iBulletType );
+ vecForce *= phys_pushscale.GetFloat();
+ vecForce *= flScale;
+ info->SetDamageForce( vecForce );
+ Assert(vecForce!=vec3_origin);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Fill out a takedamageinfo with a damage force for a melee impact
+//-----------------------------------------------------------------------------
+void CalculateMeleeDamageForce( CTakeDamageInfo *info, const Vector &vecMeleeDir, const Vector &vecForceOrigin, float flScale )
+{
+ info->SetDamagePosition( vecForceOrigin );
+
+ // Calculate an impulse large enough to push a 75kg man 4 in/sec per point of damage
+ float flForceScale = info->GetBaseDamage() * ImpulseScale( 75, 4 );
+ Vector vecForce = vecMeleeDir;
+ VectorNormalize( vecForce );
+ vecForce *= flForceScale;
+ vecForce *= phys_pushscale.GetFloat();
+ vecForce *= flScale;
+ info->SetDamageForce( vecForce );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Try and guess the physics force to use.
+// This shouldn't be used for any damage where the damage force is unknown.
+// i.e. only use it for mapmaker specified damages.
+//-----------------------------------------------------------------------------
+void GuessDamageForce( CTakeDamageInfo *info, const Vector &vecForceDir, const Vector &vecForceOrigin, float flScale )
+{
+ if ( info->GetDamageType() & DMG_BULLET )
+ {
+ CalculateBulletDamageForce( info, GetAmmoDef()->Index("SMG1"), vecForceDir, vecForceOrigin, flScale );
+ }
+ else if ( info->GetDamageType() & DMG_BLAST )
+ {
+ CalculateExplosiveDamageForce( info, vecForceDir, vecForceOrigin, flScale );
+ }
+ else
+ {
+ CalculateMeleeDamageForce( info, vecForceDir, vecForceOrigin, flScale );
+ }
+}
+
+
+// Debug functions for printing out damage types
+
+// This table maps the DMG_* defines to their strings such that
+// for DMG_XXX = i << x then table[i] = string for DMG_XXX
+
+static const char * const s_DamageTypeToStrTable[] =
+{
+ "GENERIC",
+ "CRUSH",
+ "BULLET",
+ "SLASH",
+ "BURN",
+ "VEHICLE",
+ "FALL",
+ "BLAST",
+ "CLUB",
+ "SHOCK",
+ "SONIC",
+ "ENERGYBEAM",
+ "PREVENT_PHYSICS_FORCE",
+ "NEVERGIB",
+ "ALWAYSGIB",
+ "DROWN",
+ "PARALYZE",
+ "NERVEGAS",
+ "POISON",
+ "RADIATION",
+ "DROWNRECOVER",
+ "ACID",
+ "SLOWBURN",
+ "REMOVENORAGDOLL",
+ "PHYSGUN",
+ "PLASMA",
+ "AIRBOAT",
+ "DISSOLVE",
+ "BLAST_SURFACE",
+ "DIRECT",
+ "BUCKSHOT"
+};
+#define DAMAGE_TYPE_STR_TABLE_ENTRIES 31 // number of entries in table above
+
+void CTakeDamageInfo::DebugGetDamageTypeString(unsigned int damageType, char *outbuf, int outbuflength )
+{
+ Assert(outbuflength > 0);
+
+ // we need to use snprintf to actually copy out the strings here because that's the only function that returns
+ // how much text was output
+ if ( damageType == 0 )
+ {
+ int charsWrit = Q_snprintf(outbuf, outbuflength, "%s", s_DamageTypeToStrTable[0]);
+
+ outbuflength -= charsWrit;
+ outbuf += charsWrit; // advance the output pointer (now it sits on the null terminator)
+ }
+
+ // loop through the other entries in the table
+ for (int i = 0;
+ outbuflength > 0 && i < (DAMAGE_TYPE_STR_TABLE_ENTRIES - 1);
+ ++i )
+ {
+ if ( damageType & (1 << i) )
+ {
+ // this bit was set. Print the corresponding entry from the table
+ // (the index is +1 because entry 1 in the table corresponds to 1 << 0)
+ int charsWrit = Q_snprintf(outbuf, outbuflength, "%s ", s_DamageTypeToStrTable[i + 1]);
+
+ outbuflength -= charsWrit; // reduce the chars left
+ outbuf += charsWrit; // advance the output pointer (now it sits on the null terminator)
+ }
+ }
+}
+
+
+/*
+// instant damage
+
+#define DMG_GENERIC 0 // generic damage was done
+#define DMG_CRUSH (1 << 0) // crushed by falling or moving object.
+// NOTE: It's assumed crush damage is occurring as a result of physics collision, so no extra physics force is generated by crush damage.
+// DON'T use DMG_CRUSH when damaging entities unless it's the result of a physics collision. You probably want DMG_CLUB instead.
+#define DMG_BULLET (1 << 1) // shot
+#define DMG_SLASH (1 << 2) // cut, clawed, stabbed
+#define DMG_BURN (1 << 3) // heat burned
+#define DMG_VEHICLE (1 << 4) // hit by a vehicle
+#define DMG_FALL (1 << 5) // fell too far
+#define DMG_BLAST (1 << 6) // explosive blast damage
+#define DMG_CLUB (1 << 7) // crowbar, punch, headbutt
+#define DMG_SHOCK (1 << 8) // electric shock
+#define DMG_SONIC (1 << 9) // sound pulse shockwave
+#define DMG_ENERGYBEAM (1 << 10) // laser or other high energy beam
+#define DMG_PREVENT_PHYSICS_FORCE (1 << 11) // Prevent a physics force
+#define DMG_NEVERGIB (1 << 12) // with this bit OR'd in, no damage type will be able to gib victims upon death
+#define DMG_ALWAYSGIB (1 << 13) // with this bit OR'd in, any damage type can be made to gib victims upon death.
+#define DMG_DROWN (1 << 14) // Drowning
+
+
+#define DMG_PARALYZE (1 << 15) // slows affected creature down
+#define DMG_NERVEGAS (1 << 16) // nerve toxins, very bad
+#define DMG_POISON (1 << 17) // blood poisoning - heals over time like drowning damage
+#define DMG_RADIATION (1 << 18) // radiation exposure
+#define DMG_DROWNRECOVER (1 << 19) // drowning recovery
+#define DMG_ACID (1 << 20) // toxic chemicals or acid burns
+#define DMG_SLOWBURN (1 << 21) // in an oven
+
+#define DMG_REMOVENORAGDOLL (1<<22) // with this bit OR'd in, no ragdoll will be created, and the target will be quietly removed.
+// use this to kill an entity that you've already got a server-side ragdoll for
+
+#define DMG_PHYSGUN (1<<23) // Hit by manipulator. Usually doesn't do any damage.
+#define DMG_PLASMA (1<<24) // Shot by Cremator
+#define DMG_AIRBOAT (1<<25) // Hit by the airboat's gun
+
+#define DMG_DISSOLVE (1<<26) // Dissolving!
+#define DMG_BLAST_SURFACE (1<<27) // A blast on the surface of water that cannot harm things underwater
+#define DMG_DIRECT (1<<28)
+#define DMG_BUCKSHOT (1<<29) // not quite a bullet. Little, rounder, different.
+*/ \ No newline at end of file