Unknown ❤ RESPAWN.ZAFEST.RO | VIP FREE | FREE FOR ALL ❤ 0/32
Romania XPlayZM.CSBlackDevil.COM # Zombie Plague UltimateX [ Respawn + FDL + VIP 22-12PM + POINTS] ® 12/32
Server bewerben
90 lines 6.3 KiB Markdown Source Rendered Raw Permalink History
title, excerpt, category, tags, image, read_time
title excerpt category tags image read_time
Hamsandwich Guide: RegisterHam and Ham_TakeDamage Hook the game DLL's virtual functions with RegisterHam, read and modify parameters, block calls with HAM_SUPERCEDE, and use pre versus post correctly. plugin-dev hamsandwich, amxmodx 7 min read

Ham Sandwich (module hamsandwich) hooks the virtual methods of Half-Life/CS entities — the C++ functions the game DLL calls internally to spawn a player, apply damage, or handle a kill. Unlike a network event, a Ham hook runs inside the call, so you can read the real arguments, change them, and cancel the whole thing. It works on both stock CS and ReGameDLL, which makes it the portable way to alter core gameplay. Ham_TakeDamage is the one you will use most, so this guide builds around it.

1. Registering a hook

RegisterHam takes the function to hook, the entity classname whose method you want, your callback, and a post flag (0 = pre, 1 = post). Register in plugin_init():

#include <amxmodx>
#include <hamsandwich>

public plugin_init() { register_plugin("Ham Demo", "1.0", "CSB")

RegisterHam(Ham_TakeDamage, "player", "fw_take_damage_pre", 0)
RegisterHam(Ham_Spawn,      "player", "fw_spawn_post", 1)
RegisterHam(Ham_Killed,     "player", "fw_killed_pre", 0)

}

The classname "player" hooks the method on every player entity. You can hook other entities the same way — "weapon_ak47", "func_breakable" — as long as the function exists on that class.

2. Ham_TakeDamage: reading the parameters

The TakeDamage forward hands you the victim, the inflictor entity, the attacker, the damage amount, and the damage-type bits:

public fw_take_damage_pre(victim, inflictor, attacker, Float:damage, damagebits)
{
    // ignore world/self damage
    if (!is_user_connected(attacker) || victim == attacker)
        return HAM_IGNORED
new vname[32], aname[32]
get_user_name(victim, vname, charsmax(vname))
get_user_name(attacker, aname, charsmax(aname))

server_print("%s is hitting %s for %.0f", aname, vname, damage)
return HAM_IGNORED

}

damagebits is a bitfield of DMG_* flags (bullet, blast, fall, etc.), useful for distinguishing a knife from a grenade from fall damage.

3. Modifying and blocking

To change a parameter, write it back with the SetHamParam* natives — the argument number matches the parameter position. Damage is parameter 4:

public fw_take_damage_pre(victim, inflictor, attacker, Float:damage, damagebits)
{
    if (!is_user_connected(attacker))
        return HAM_IGNORED
// double all player damage
SetHamParamFloat(4, damage * 2.0)
return HAM_HANDLED

}

To cancel the call outright — total damage immunity, spawn protection — return HAM_SUPERCEDE. That prevents the original function from running at all:

public fw_take_damage_pre(victim, inflictor, attacker, Float:damage, damagebits)
{
    if (is_spawn_protected(victim))
        return HAM_SUPERCEDE      // take no damage
return HAM_IGNORED

}

The return values: HAM_IGNORED (do nothing special), HAM_HANDLED (you changed a param, keep going), HAM_SUPERCEDE (block the original), and HAM_OVERRIDE (block and substitute your own return value, set with SetHamReturn*).

4. Pre versus post

A pre hook (flag 0) runs before the original function — the only place you can modify parameters or supersede the call. A post hook (flag 1) runs after, when the effect has already happened. Use post for Ham_Spawn when you want to hand out weapons or set health after the game has reset the player:

public fw_spawn_post(id)
{
    if (!is_user_alive(id))
        return HAM_IGNORED
set_pev(id, pev_health, 150.0)   // give bonus HP on spawn
return HAM_IGNORED

}

Setting health in a pre spawn hook would be pointless — the game overwrites it during the spawn. Match the hook direction to when the state you care about actually exists.

5. Calling the function yourself

ExecuteHamB lets you invoke a Ham function manually — for example, to kill a player through the real code path so death handling runs correctly:

// deal 1000 damage to slay a player properly
ExecuteHamB(Ham_TakeDamage, id, 0, id, 1000.0, DMG_GENERIC)

Common errors

  • Server crashes on load — wrong classname, or hooking a function the class does not have. Ham_TakeDamage on "player" is safe; a typo in the classname is not.
  • Damage change ignored — you set the param in a post hook. Parameters can only be modified in a pre hook, before the original runs.
  • Superceding TakeDamage breaks other plugins — if another plugin also hooks it and expects the call to proceed, your HAM_SUPERCEDE hides the event from it. Prefer setting damage to 0.0 and returning HAM_HANDLED when you only mean to null the damage, not the whole call.
  • run time error after the hook — you used an invalid entity index (attacker 0 is the world). Guard with is_user_connected before touching player data. See run-time error 4.

Verification

Load the plugin, take a hit in-game, and confirm the server_print reports the expected damage. For a modifier, check that the scoreboard/health reflects the change — double damage should drop a full-HP player in half the usual hits. For HAM_SUPERCEDE immunity, stand in fire and confirm health never drops. When you need named members and a cleaner API on a ReGameDLL server, ReAPI hooks the same functions with readable arguments; for lighter needs, compare all three hook types.