Knife Distance by SchlumPF
Description
This plugin will measure how far your enemy stood away when you hit it with your knife. The origins for measuring this plugin uses are the origins which are used by the engine to verifiy whether a attack hit or not which makes it as accurate as possible.
Currently this is the only 100% accurate KD-plugin which's sourcecode is public.
Difference between TraceLine-Hits and TraceHull-Hits
First of all the engine tries to draw a line (TraceLine) which has a length of 32.0 or 48.0 units, depending on the attacktype, between your gunposition, which is about the center of the players head, to where you are aiming. If this line hits anything, everything is fine: We get a hitgroup (head, chest, stomach, left arm, right arm, left leg, right leg). But if this line hits nothing on it's way, which happens if you don't aim directly at you opponent or are too far away, the engine performs a second check which is a TraceHull. The TraceHull is not a line, it's a rectangular which moves to the place your aiming, too. If this box hits anything on its way, the engine also recognizes hit with a huge difference: The hit's hitgroup is generic because the engine doesn't determine a specific hitgroup. This difference simply means, we cannot do a headshot or any special amount of damage apart the default ones with a Tracehull hit. Also, a TraceHull distance can be less than 16.0 (TraceLine limit) or even 0.0.
CVars
kd_sound_wickedsick_stab "30.0"- minimum distance for a public wickedsick announcment of stabs
kd_sound_godlike_stab "31.0"- minimum distance for a public godlike announcment of stabs
kd_sound_wickedsick_slash "46.0"- minimum distance for a public wickedsick announcment of slashes
kd_sound_godlike_slash "47.0"- minimum distance for a public godlike announcment of slashes
kd_hud_color "0 250 150"- color of the hudmessages, which is used to show stats, on screen
kd_hud_coords "-0.75 -1.0"- position of the hudmessages, which is used to show stats, on screen
kd_hud_holdtime "2.0"- duration of the hudmessages, which is used to show stats, on screen
Changelog
Code:
05/11/2009 - v0.1
!: Initial release
05/14/2009 - v0.2
c: Changed the whole detection code
c: Changed the displaying of information from a chatmessage to a hudmessage to avoid to much spam in future updates
05/15/2009 - v0.3
+: Prints the latest hit data of your killer if you died
+: Prints hitdata and plays a sound to everyone if you kill somebody with a attack within a long distance
+: Added comments, I think the plugin gets more hard to read
c: Changed the detection a bit again
c: Fully supports teamattack now
-: Removed unnecessarry code
05/17/2009 - v0.4
+: Added bot-support
+: Added CVars
c: Detection to be finally perfect and accurate
Credits
- DeepBlueSea for pointing out that the calculation which is used in Alka's plugin is wrong and sharing the right way with me
- arkshine for supporting me in this thread
- xPaw for testing this plugin with me and begging me to post it here
HLSDK (my comments beginn with ////)
PHP Code:
// crowbar.cpp
int CCrowbar::Swing( int fFirst )
{
int fDidHit = FALSE;
TraceResult tr;
UTIL_MakeVectors (m_pPlayer->pev->v_angle);
Vector vecSrc = m_pPlayer->GetGunPosition( ); //// not m_HackedGunPosition, origin + view_ofs
Vector vecEnd = vecSrc + gpGlobals->v_forward * 32; //// 32 for stabs, 48 for slashes; basically that constant is the distance of the trace
UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, ENT( m_pPlayer->pev ), &tr );
if ( tr.flFraction >= 1.0 )
{
UTIL_TraceHull( vecSrc, vecEnd, dont_ignore_monsters, head_hull, ENT( m_pPlayer->pev ), &tr );
if ( tr.flFraction < 1.0 )
{
// Calculate the point of intersection of the line (or hull) and the object we hit
// This is and approximation of the "best" intersection
CBaseEntity *pHit = CBaseEntity::Instance( tr.pHit );
if ( !pHit || pHit->IsBSPModel() ) //// if we hit something which is not an entity (= we hit worldspawn ) the engine looks for the exact hit place
FindHullIntersection( vecSrc, tr, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, m_pPlayer->edict() );
vecEnd = tr.vecEndPos; // This is the point on the actual surface (the hull could have hit space)
}
}
if ( tr.flFraction >= 1.0 )
{
if (fFirst)
{
// miss
switch( (m_iSwing++) % 3 )
{
case 0:
SendWeaponAnim( CROWBAR_ATTACK1MISS ); break;
case 1:
SendWeaponAnim( CROWBAR_ATTACK2MISS ); break;
case 2:
SendWeaponAnim( CROWBAR_ATTACK3MISS ); break;
}
m_flNextPrimaryAttack = gpGlobals->time + 0.5;
// play wiff or swish sound
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/cbar_miss1.wav", 1, ATTN_NORM, 0, 94 + RANDOM_LONG(0,0xF));
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
}
}
else
{
// hit
fDidHit = TRUE;
CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit);
switch( ((m_iSwing++) % 2) + 1 )
{
case 0:
SendWeaponAnim( CROWBAR_ATTACK1HIT ); break;
case 1:
SendWeaponAnim( CROWBAR_ATTACK2HIT ); break;
case 2:
SendWeaponAnim( CROWBAR_ATTACK3HIT ); break;
}
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
ClearMultiDamage( );
//// if you check the following code you will see that TraceAttack is called first but the damage which is caused is set in TakeDamage
if ( (m_flNextPrimaryAttack + 1 < gpGlobals->time) || g_pGameRules->IsMultiplayer() )
{
// first swing does full damage
pEntity->TraceAttack(m_pPlayer->pev, gSkillData.plrDmgCrowbar, gpGlobals->v_forward, &tr, DMG_CLUB );
}
else
{
// subsequent swings do half
pEntity->TraceAttack(m_pPlayer->pev, gSkillData.plrDmgCrowbar / 2, gpGlobals->v_forward, &tr, DMG_CLUB );
}
ApplyMultiDamage( m_pPlayer->pev, m_pPlayer->pev );
m_flNextPrimaryAttack = gpGlobals->time + 0.25;
// play thwack, smack, or dong sound
float flVol = 1.0;
int fHitWorld = TRUE;
if (pEntity)
{
if (pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE)
{
// play thwack or smack sound
switch( RANDOM_LONG(0,2) )
{
case 0:
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/cbar_hitbod1.wav", 1, ATTN_NORM); break;
case 1:
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/cbar_hitbod2.wav", 1, ATTN_NORM); break;
case 2:
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/cbar_hitbod3.wav", 1, ATTN_NORM); break;
}
m_pPlayer->m_iWeaponVolume = CROWBAR_BODYHIT_VOLUME;
if (!pEntity->IsAlive() )
return TRUE;
else
flVol = 0.1;
fHitWorld = FALSE;
}
}
// play texture hit sound
// UNDONE: Calculate the correct point of intersection when we hit with the hull instead of the line
if (fHitWorld)
{
float fvolbar = TEXTURETYPE_PlaySound(&tr, vecSrc, vecSrc + (vecEnd-vecSrc)*2, BULLET_PLAYER_CROWBAR);
if ( g_pGameRules->IsMultiplayer() )
{
// override the volume here, cause we don't play texture sounds in multiplayer,
// and fvolbar is going to be 0 from the above call.
fvolbar = 1;
}
// also play crowbar strike
switch( RANDOM_LONG(0,1) )
{
case 0:
//UTIL_EmitAmbientSound(ENT(0), ptr->vecEndPos, "weapons/cbar_hit1.wav", fvolbar, ATTN_NORM, 0, 98 + RANDOM_LONG(0,3));
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hit1.wav", fvolbar, ATTN_NORM, 0, 98 + RANDOM_LONG(0,3));
break;
case 1:
//UTIL_EmitAmbientSound(ENT(0), ptr->vecEndPos, "weapons/cbar_hit2.wav", fvolbar, ATTN_NORM, 0, 98 + RANDOM_LONG(0,3));
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hit2.wav", fvolbar, ATTN_NORM, 0, 98 + RANDOM_LONG(0,3));
break;
}
}
// delay the decal a bit
m_trHit = tr;
SetThink( Smack );
pev->nextthink = gpGlobals->time + 0.2;
m_pPlayer->m_iWeaponVolume = flVol * CROWBAR_WALLHIT_VOLUME;
}
return fDidHit;
}
void FindHullIntersection( const Vector &vecSrc, TraceResult &tr, float *mins, float *maxs, edict_t *pEntity )
{
int i, j, k;
float distance;
float *minmaxs[2] = {mins, maxs};
TraceResult tmpTrace;
Vector vecHullEnd = tr.vecEndPos;
Vector vecEnd;
distance = 1e6f;
vecHullEnd = vecSrc + ((vecHullEnd - vecSrc)*2);
UTIL_TraceLine( vecSrc, vecHullEnd, dont_ignore_monsters, pEntity, &tmpTrace );
if ( tmpTrace.flFraction < 1.0 )
{
tr = tmpTrace;
return;
}
for ( i = 0; i < 2; i++ )
{
for ( j = 0; j < 2; j++ )
{
for ( k = 0; k < 2; k++ )
{
vecEnd.x = vecHullEnd.x + minmaxs[i][0];
vecEnd.y = vecHullEnd.y + minmaxs[j][1];
vecEnd.z = vecHullEnd.z + minmaxs[k][2];
UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, pEntity, &tmpTrace );
if ( tmpTrace.flFraction < 1.0 )
{
float thisDistance = (tmpTrace.vecEndPos - vecSrc).Length();
if ( thisDistance < distance )
{
tr = tmpTrace;
distance = thisDistance;
}
}
}
}
}
}
Related Links
[1]
Knife-Tracing explained by DeepBlueSea
Notes
DeepBlueSea and Alka confirmed the distance to be accurate.
Fell free to ask, use the code, post suggestions or w/e