Skip to content

Haze Auto Dagger

Here's a Haze script that locks onto an enemy and throws a Sleep Dagger (ability 1) whenever mouse5 is pressed.

What this shows

  • Reading menu settings at runtime. config.get_float("fov") pulls the current value from TSUKI's settings UI every tick. Drag the slider in-game and the script responds immediately. No reload needed.
  • fire_and_hold keeps the aim locked for hold_time ms after the press. Haze has a throw windup; if the snap released on the keypress, the dagger would miss.
  • while true + coroutine.yield(). fire_and_hold yields during its hold, so on_tick has to run inside a coroutine. The yield() at the bottom of the loop hands control back to the engine each tick.
  • targeting.get_fov(target, bone) returns the angle in degrees from the camera forward to that bone.
  • snap_to_target() every tick, not once. The snap isn't sticky; each call moves the camera for that single frame. Calling it every tick while tracking is what creates the smooth follow before the dagger fires.

Script

lua
-- Haze Auto Dagger
-- Hold mouse5 -> track closest enemy -> fire when on target -> hold lock 200ms

name = "Haze Auto Dagger"
id = hero_id.haze

settings = {
    { key = "fov",        label = "FOV (degrees)",        type = "float", default = 15.0, min = 1.0, max = 30.0 },
    { key = "max_range",  label = "Max Range (m)",        type = "float", default = 30.0, min = 5.0, max = 100.0 },
    { key = "fire_angle", label = "Fire Threshold (deg)", type = "float", default = 1.5,  min = 0.3, max = 5.0 },
    { key = "hold_time",  label = "Lock After Fire (ms)", type = "float", default = 200,  min = 0, max = 2000 },
}

function on_tick()
    while true do
        local lp = local_player()
        if lp and lp:is_alive() and input.is_key_held(VK.XBUTTON2) then
            if lp:is_ability_ready(slot.ability1) then
                local target = targeting.find_closest_by_fov(
                    config.get_float("fov"),
                    config.get_float("max_range")
                )
                if target and target:is_targetable() then
                    snap_to_target(target, { bone = bone.chest })

                    local angle = targeting.get_fov(target, bone.chest)
                    if angle and angle < config.get_float("fire_angle") then
                        fire_and_hold(target, slot.ability1, {
                            bone = bone.chest,
                            hold_time = config.get_float("hold_time")
                        })
                        toast(string.format("Dagger → %s", target:hero_name() or "?"), 2, {
                            bg = {r=40, g=15, b=50, a=220},
                            text = {r=200, g=140, b=255},
                        })
                    end
                end
            end
        end
        coroutine.yield()
    end
end

Notes

id = hero_id.haze locks the script to Haze only. It goes idle automatically when you pick a different hero. Comment that line out (or delete it) if you want to try the same logic with another hero's ability 1.

bone.chest is a reasonable default for hero-sized targets at medium range. For long-range work where targets have more time to dodge, bone.pelvis gives a slightly higher hit rate because most strafing motion is horizontal at the upper body but the lower body lags. Try both.

If you want a more aggressive auto-throw, lower fire_angle won't help. It makes the script wait LONGER for a tight crosshair-to-target alignment. Going the other way (higher fire_angle, say 3-4 degrees) makes the script fire more eagerly, even when the snap hasn't fully caught up. That's a trade between fewer "perfect" shots and more "good-enough" ones.