alliedmodders / amxmodx

AMX Mod X - Half-Life 1 Scripting and Administration
http://www.amxmodx.org/
499 stars 203 forks source link

Ham_Killed/DeathMsg getting called before Ham_TakeDamage? #713

Closed OciXCrom closed 5 years ago

OciXCrom commented 5 years ago

I don't think this is how it should work. Why is the damage dealt after the player has died?

#include <amxmodx>
#include <hamsandwich>

public plugin_init()
{
    register_plugin("Ham_Test", "1.0", "OciXCrom")
    RegisterHam(Ham_TakeDamage, "player", "OnTakeDamage", 1)
    RegisterHam(Ham_Killed, "player", "OnPlayerKilledHam", 1)
    register_event("DeathMsg", "OnPlayerKilled", "a")
}

public OnTakeDamage(iVictim, iInflictor, iAttacker, Float:fDamage, iDamageBits)
{
    client_print(iAttacker, print_chat, "You dealt %.0f damage to %n", fDamage, iVictim)
}

public OnPlayerKilled()
{
    new iAttacker = read_data(1), iVictim = read_data(2)
    client_print(iAttacker, print_chat, "You killed %n", iVictim)
}

public OnPlayerKilledHam(iVictim, iAttacker)
{
    client_print(iAttacker, print_chat, "[HAM] You killed %n", iVictim)
}

Result:

You killed a poor soul
[HAM] You killed a poor soul
You dealt 195 damage to a poor soul
fl0werD commented 5 years ago

Because player dies in takedamage

OciXCrom commented 5 years ago

@fl0werD that doesn't explain why death is called before damage.

Mistrick commented 5 years ago

pre takedamage pre killed post killed post takedamage

Th3-822 commented 5 years ago

First thing to notice, you are hooking Ham_TakeDamage as Post Your callback function will be called after TakeDamage is executed

If there is another function getting called is because it was called inside TakeDamage, so let's follow the function from the SDK:

It's TakeDamage from player, so let's find CBasePlayer::TakeDamage: https://github.com/ValveSoftware/halflife/blob/master/dlls/player.cpp#L443 Lines 443-673

There is a call in line 507 to CBaseMonster::TakeDamage, so let's go there and check: https://github.com/ValveSoftware/halflife/blob/master/dlls/combat.cpp#L838 Lines 838-968

Oh, what is in line 909? https://github.com/ValveSoftware/halflife/blob/master/dlls/combat.cpp#L909

    if ( pev->health <= 0 )
    {
        g_pevLastInflictor = pevInflictor;

        if ( bitsDamageType & DMG_ALWAYSGIB )
        {
            Killed( pevAttacker, GIB_ALWAYS );
        }
        else if ( bitsDamageType & DMG_NEVERGIB )
        {
            Killed( pevAttacker, GIB_NEVER );
        }
        else
        {
            Killed( pevAttacker, GIB_NORMAL );
        }

        g_pevLastInflictor = NULL;

        return 0;
    }

So CBasePlayer::Killed is called on TakeDamage...

So functions are called like this

CBasePlayer::TakeDamage() - Start || Pre hook gets called before running this
  CBaseMonster::TakeDamage()
    CBasePlayer::Killed() - Start || Pre hook of Ham_Killed on player before running this
      CHalfLifeMultiplay::PlayerKilled()
        CHalfLifeMultiplay::DeathNotice() || At here DeathMsg is sent, and your OnPlayerKilled() its called
    CBasePlayer::Killed() - End || Post hook gets called here, so your OnPlayerKilledHam() gets called at here
CBasePlayer::TakeDamage() - End || Post hook gets called here, OnTakeDamage() gets called

Thats why are you getting that result

OciXCrom commented 5 years ago

Thanks for the detailed explanation. If that's how the game works, I'm not going to judge it.