Raised This Month: $32 Target: $400
 8% 

Solved [L4D] How accurately calculate tank damage with SDKHook?


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
Dragokas
Veteran Member
Join Date: Nov 2017
Location: Ukraine on fire
Old 05-07-2021 , 08:16   [L4D] How accurately calculate tank damage with SDKHook?
Reply With Quote #1

Hi,

I want to get damage deal to tank by player (solo) using SDKHook method.

Let's say tank hp is exactly 1000:

Code:
sm_cvar z_tank_health 1000
There are no bots. You are using a pump shotgun.

PHP Code:
#pragma semicolon 1
#pragma newdecls required

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

float         g_fDamage[MAXPLAYERS+1][MAXPLAYERS+1];
bool         g_bIncapped[MAXPLAYERS+1];

public 
void OnPluginStart()
{
    
HookEvent("tank_spawn",                 Event_TankSpawn);
    
HookEvent("tank_killed",                 Event_TankKilled);
    
HookEvent("player_incapacitated",         Event_Incap,        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_bIncapped[tank] = false;
    
    for( 
int i 1<= MaxClientsi++ )
    {
        
g_fDamage[i][tank] = 0.0;
    }
    
SDKHook(tankSDKHook_OnTakeDamageOnTakeDamage);
    
    
//SDKHook(tank, SDKHook_OnTakeDamageAlive, OnTakeDamage); // alternate
}

public 
Action OnTakeDamage(int victimint &attackerint &inflictorfloat &damageint &damagetypeint &weaponfloat damageForce[3], float damagePosition[3])
{
    if( 
GetEntProp(victimProp_Send"m_isIncapacitated") )
        return 
Plugin_Continue;
    
    if( 
g_bIncapped[victim] ) // alternate
    
{
        return 
Plugin_Continue;
    }

    if( 
attacker <= MaxClients )
    {
        
g_fDamage[attacker][victim] += damage;
    }
    return 
Plugin_Continue;
}

public 
Action Event_Incap(Event eventchar[] namebool dontBroadcast)
{
    
int victim GetClientOfUserId(event.GetInt("userid"));
    
g_bIncapped[victim] = true;
}

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: %f"g_fDamage[i][victim]);
        }
    }
    return 
Plugin_Continue;

With OnTakeDamage (+ incap filter), total damage solo == 1032 ± 6.
With OnTakeDamageAlive (+ incap filter), total damage solo == 990 ± 6.

How to get exactly 1000 ?

Thanks.

-
PS. Just if somebody don't know, before tank die, incap animation is played, and tank still receiving damage, that's why incap filter is required.
__________________
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:19.
Dragokas is offline
Marttt
Veteran Member
Join Date: Jan 2019
Location: Brazil
Old 05-07-2021 , 10:59   Re: [L4D] How accurately calculate tank damage with SDKHook?
Reply With Quote #2

Try checking if "damage > tank health" in the "last hit" then subtract.
__________________
Marttt is offline
Lux
Veteran Member
Join Date: Jan 2015
Location: Cat
Old 05-07-2021 , 11:07   Re: [L4D] How accurately calculate tank damage with SDKHook?
Reply With Quote #3

Use the player_hurt event may give better results.

Or

You can patch out the CTerrorPlayer::OnIncapacitatedAsTank in CTerrorPlayer::AllowDamage and let the tank just die
__________________
Connect
My Plugins: KlickME
[My GitHub]

Commission me for L4D
Lux is offline
Dragokas
Veteran Member
Join Date: Nov 2017
Location: Ukraine on fire
Old 05-07-2021 , 12:28   Re: [L4D] How accurately calculate tank damage with SDKHook?
Reply With Quote #4

Thank you, Lux.

Quote:
Originally Posted by Lux View Post
Use the player_hurt event may give better results.
"player_hurt" still returns sometimes 984, but sometimes even 999.

PHP Code:
public void OnPluginStart()
{
...
    
HookEvent("player_hurt",                 Event_PlayerHurt);
...
}

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( GetEntProp(victim, Prop_Send, "m_isIncapacitated") )
        return Plugin_Continue;
    */
    
    
if( g_bIncapped[victim] ) // alternate
    
{
        return 
Plugin_Continue;
    }
    
    if( 
attacker <= MaxClients && victim <= MaxClients )
    {
        
g_fDamage[attacker][victim] += damage;
    }

Quote:
Originally Posted by Lux View Post
You can patch out the CTerrorPlayer::OnIncapacitatedAsTank in CTerrorPlayer::AllowDamage and let the tank just die
If you mean NOP, patching those made tank invulnerable

Quote:
Originally Posted by Marttt View Post
Try checking if "damage > tank health" in the "last hit" then subtract.
Thank you, Marttt.
In incap state tank still receiving a lot of "1.0" damage. Last damage value == 5000.0
So, if I remove incap filter, total damage will be like > 7.000 (with the start tank hp == 1000.0).
__________________
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 12:30.
Dragokas is offline
Dragokas
Veteran Member
Join Date: Nov 2017
Location: Ukraine on fire
Old 05-07-2021 , 12:43   Re: [L4D] How accurately calculate tank damage with SDKHook?
Reply With Quote #5

---
__________________
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 12:50.
Dragokas is offline
Dragokas
Veteran Member
Join Date: Nov 2017
Location: Ukraine on fire
Old 05-07-2021 , 13:16   Re: [L4D] How accurately calculate tank damage with SDKHook?
Reply With Quote #6

Marttt, nice, I undertood what you suggested.

I did some tests, and now I know how it works.

When you do the last shoot (before incap), the damage is > than tank hp elapsed.
This is where incap event is fired, but OnTankDamage (or "player_hurt") are not called before incap. It is called after incap. And even more, the damage is passed as full, which is > tank hp elapsed at the last moment of its life.
Also, when OnTakeDamage is fired, the float damage is rounding to zero (even if value is 0.9), and those value is get written to "m_iHealth" prop of tank's entity.

With the proper calculations we are receiving the correct final value, using SDKHook_OnTakeDamage:

PHP Code:
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_fDamage[attacker][victim] += RoundToFloor(damage);
        
PrintToChatAll("[%f] [%i] damage = %f. Health: %i"g_fDamage[attacker][victim], timesdamageGetEntProp(victimProp_Data"m_iHealth") );
    }
    return 
Plugin_Continue;

Quote:
// For sm_cvar z_tank_health 100

[22.000000] [1] damage = 22.803766. Health: 100
[44.000000] [2] damage = 22.806159. Health: 78
[66.000000] [3] damage = 22.811071. Health: 56
[89.000000] [4] damage = 23.212322. Health: 34
incap. Damage = 22.794973. Health: 11
[100.000000] [5] damage = 11.000000. Health: 11
Damage done: 100.000000
Topic solved.
__________________
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:18.
Dragokas is offline
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
cravenge
Veteran Member
Join Date: Nov 2015
Location: Chocolate Factory
Old 05-07-2021 , 20:20   Re: [L4D] How accurately calculate tank damage with SDKHook?
Reply With Quote #8

The SDKHook version should return Plugin_Changed when the damage gets modified so it would also reflect on the scoreboard when transitioning between maps.
cravenge is offline
Dragokas
Veteran Member
Join Date: Nov 2017
Location: Ukraine on fire
Old 05-08-2021 , 08:48   Re: [L4D] How accurately calculate tank damage with SDKHook?
Reply With Quote #9

cravenge, sorry, I don't understand the relationship to my topic. I don't change damage, only measure.
__________________
Expert of CMD/VBS/VB6. Malware analyst. L4D fun (Bloody Witch & FreeZone)
[My plugins] [My tools] [GitHub] [Articles] [HiJackThis+] [Donate]
Dragokas is offline
cravenge
Veteran Member
Join Date: Nov 2015
Location: Chocolate Factory
Old 05-09-2021 , 05:12   Re: [L4D] How accurately calculate tank damage with SDKHook?
Reply With Quote #10

Quote:
Originally Posted by Dragokas View Post
cravenge, sorry, I don't understand the relationship to my topic. I don't change damage, only measure.
Yes you aren't but what I suggested is merely for consistency and probably cosmetic too if I am to be honest.
cravenge is offline
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 02:16.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode