View Single Post
Dragokas
Veteran Member
Join Date: Nov 2017
Location: Ukraine on fire
Old 05-07-2021 , 13:56   Re: [L4D] How accurately calculate tank damage with SDKHook?
Reply With Quote #7

Just as a final, for somebody else.

SDKHook version:

PHP Code:
#pragma semicolon 1
#pragma newdecls required

#include <sourcemod>
#include <sdktools>
#include <sdkhooks>

int         g_iDamage[MAXPLAYERS+1][MAXPLAYERS+1];
bool         g_bDied[MAXPLAYERS+1];

int times;

public 
void OnPluginStart()
{
    
HookEvent("tank_spawn",                 Event_TankSpawn);
    
HookEvent("tank_killed",                 Event_TankKilled);
}

public 
Action Event_TankSpawn(Event eventchar[] namebool dontBroadcast)
{
    
int tank GetClientOfUserId(event.GetInt("userid"));
    if( 
tank && IsClientInGame(tank) )
    {
        
TraceTank(tank);
    }
}

void TraceTank(int tank)
{
    
g_bDied[tank] = false;
    
    for( 
int i 1<= MaxClientsi++ )
    {
        
g_iDamage[i][tank] = 0;
    }
    
times 0;
    
    
SDKHook(tankSDKHook_OnTakeDamageOnTakeDamage);
    
    
//Seemse, not useul at all
    //SDKHook(tank, SDKHook_OnTakeDamageAlive, OnTakeDamage); // alternate
}

public 
Action OnTakeDamage(int victimint &attackerint &inflictorfloat &damageint &damagetypeint &weaponfloat damageForce[3], float damagePosition[3])
{
    if( 
g_bDied[victim] )
    {
        return 
Plugin_Continue;
    }
    
    
int health GetEntProp(victimProp_Data"m_iHealth");
    if( 
RoundToFloor(damage) >= health )
    {
        
PrintToChatAll("incap. Damage = %f. Health: %i"damagehealth);
        
damage float(health);
        
g_bDied[victim] = true;
    }
    
    
times ++;
    
    if( 
attacker <= MaxClients )
    {
        
g_iDamage[attacker][victim] += RoundToFloor(damage);
        
PrintToChatAll("[%i] [%i] damage = %i. Health: %i"g_iDamage[attacker][victim], timesRoundToFloor(damage), GetEntProp(victimProp_Data"m_iHealth") );
    }
    return 
Plugin_Continue;
}

public 
Action Event_TankKilled(Event eventchar[] namebool dontBroadcast)
{
    
int victim GetClientOfUserId(event.GetInt("userid"));
    if( !
victim )
    {
        return 
Plugin_Continue;
    }
    for( 
int i 1<= MaxClientsi++ )
    {
        if( 
IsClientInGame(i) && !IsFakeClient(i) )
        {
            
PrintToChatAll("Damage done: %i"g_iDamage[i][victim]);
        }
    }
    return 
Plugin_Continue;

"player_hurt" event version:

PHP Code:
#pragma semicolon 1
#pragma newdecls required

#include <sourcemod>
#include <sdktools>

int         g_iDamage[MAXPLAYERS+1][MAXPLAYERS+1];
int         g_iLastAttacker[MAXPLAYERS+1];
bool         g_bDied[MAXPLAYERS+1];
float        g_fLastHP[MAXPLAYERS+1];

int times;

public 
void OnPluginStart()
{
    
HookEvent("tank_spawn",                 Event_TankSpawn);
    
HookEvent("tank_killed",                 Event_TankKilled);
    
HookEvent("player_hurt",                 Event_PlayerHurt,    EventHookMode_Pre);
}

public 
Action Event_TankSpawn(Event eventchar[] namebool dontBroadcast)
{
    
int tank GetClientOfUserId(event.GetInt("userid"));
    if( 
tank && IsClientInGame(tank) )
    {
        
TraceTank(tank);
    }
}

void TraceTank(int tank)
{
    
g_bDied[tank] = false;
    
g_fLastHP[tank] = float(GetEntProp(tankProp_Data"m_iHealth"));
    
    for( 
int i 1<= MaxClientsi++ )
    {
        
g_iDamage[i][tank] = 0;
    }
    
times 0;
}

public 
Action Event_PlayerHurt(Event eventchar[] namebool dontBroadcast)
{
    
int victim GetClientOfUserId(event.GetInt("userid"));
    
int attacker GetClientOfUserId(event.GetInt("attacker"));
    
float damage event.GetFloat("dmg_health");
    
    if( 
g_bDied[victim] )
    {
        return 
Plugin_Continue;
    }
    
    if( 
GetEntProp(victimProp_Send"m_isIncapacitated") )
    {
        
g_bDied[victim] = true;
        
damage g_fLastHP[victim];
        if( !
attacker attacker g_iLastAttacker[victim];
        
PrintToChatAll("incap. dmg: %f. att: %i. vic: %i"damageattackervictim);
    }
    
    
g_fLastHP[victim] = event.GetFloat("health");
    
g_iLastAttacker[victim] = attacker;
    
    
times ++;
    
    if( 
attacker <= MaxClients && victim <= MaxClients )
    {
        
g_iDamage[attacker][victim] += RoundToFloor(damage);
        
PrintToChatAll("[%i] [%i] damage = %i. Health: %f"g_iDamage[attacker][victim], timesRoundToFloor(damage), event.GetFloat("health") );
    }
    
    return 
Plugin_Continue;
}

public 
Action Event_TankKilled(Event eventchar[] namebool dontBroadcast)
{
    
int victim GetClientOfUserId(event.GetInt("userid"));
    if( !
victim )
    {
        return 
Plugin_Continue;
    }
    for( 
int i 1<= MaxClientsi++ )
    {
        if( 
IsClientInGame(i) && !IsFakeClient(i) )
        {
            
PrintToChatAll("Damage done: %i"g_iDamage[i][victim]);
        }
    }
    return 
Plugin_Continue;

Event Hook version is much more complicated, because hook is called after health is already set (even with Pre-mode). Even more, after incap, hurt event is called with 0 attacker index. So, both attacker and hp are required to be pre-saved beforehand to get a reliable results.
__________________
Expert of CMD/VBS/VB6. Malware analyst. L4D fun (Bloody Witch & FreeZone)
[My plugins] [My tools] [GitHub] [Articles] [HiJackThis+] [Donate]

Last edited by Dragokas; 05-07-2021 at 13:58.
Dragokas is offline