Skip to content

Silent Aim on Your Shots

While an enemy head is within fov_deg of your crosshair and visible, every shot you fire is corrected onto it. The script only arms the angle; your own trigger fires. With test_mode on it also taps attack every 700 ms so a run can count its own hits.

What this shows

  • cmds = 1 covers one game tick. aim.silent has to be called again every tick the target stays in the cone.
  • Pass target =. With a target the aimed point is that player's led bone. With a bare angle the point sits distance units down the camera ray, and the default misses.
  • false means refused. The aimbot owns the shot, the game is unfocused, the cursor is up, or another script holds the window. aim.diag().last_reason says which.
  • Hits come from p:get_hit_events. The sequence cursor keeps an event from being counted twice.

Script

lua
-- gun_psilent.lua
-- While an enemy head is inside fov_deg of the crosshair and visible, every shot you fire is
-- corrected onto it. Your own trigger is what fires: the script only arms the angle, unless
-- test_mode is on. Settings (scripts/config/gun_psilent.json): fov_deg=6, bone="head", range_m=60.

script_info = {
    name        = "gun_psilent",
    author      = "tsuki",
    version     = "1.0",
    description = "Silent aim for the gun on your own shots (aim.silent example)",
    needs_internal = true,
}

local last_status, last_tap, taps, hits, hit_seq = -100, 0, 0, 0, 0

local function angle_between(a, b)
    local dot = a.x * b.x + a.y * b.y + a.z * b.z
    if dot > 1 then dot = 1 elseif dot < -1 then dot = -1 end
    return math.deg(math.acos(dot))
end

local function best_in_fov(fov_deg, range_m, bone)
    local cam, fwd = camera.get_position(), camera.get_forward()
    local best, ba = nil, fov_deg
    for _, p in ipairs(get_players() or {}) do
        if p:is_alive() and p:is_visible() then
            local d = p:get_distance()
            if d and d <= range_m then
                local h = p:get_bone_position(bone) or p:get_head_world()
                if h then
                    local v = vec3(h.x - cam.x, h.y - cam.y, h.z - cam.z):normalized()
                    local ang = angle_between(v, fwd)
                    if ang < ba then best, ba = p, ang end
                end
            end
        end
    end
    return best
end

function on_tick()
    local me = local_player()
    if not me or not me:is_alive() or not internal.is_loaded() then return end
    local fov_deg   = config.get_float("fov_deg", 6)
    local bone      = config.get_string("bone", "head")
    local range_m   = config.get_float("range_m", 60)
    local test_mode = config.get_bool("test_mode", false)
    local t = clock()

    -- count our hits on heroes
    local ev, latest = me:get_hit_events(hit_seq)
    if ev then
        for _, e in ipairs(ev) do if e.is_dealt and e.victim_class and e.victim_class ~= 0 then hits = hits + 1 end end
        if latest then hit_seq = latest end
    end
    if t - last_status >= 5 then
        last_status = t
        local d = aim.diag()
        print(string.format("[ex-gun] armed=%d taps=%d hero_hits=%d refused aimbot=%d input=%d last='%s'", d.silent, taps, hits, d.refused_aimbot, d.refused_input, d.last_reason or ""))
    end

    local target = best_in_fov(fov_deg, range_m, bone)
    if not target then return end
    -- re-arm every tick while the target stays in the cone
    local va = camera.get_view_angles()
    local armed = aim.silent(va.x, va.y, { cmds = 1, target = target, bone = bone, button = "attack" })
    if test_mode and armed and t - last_tap >= 0.7 then
        local ammo = me:get_ammo()
        if ammo and ammo < 2 then input.tap("reload"); last_tap = t + 1.5; return end
        if input.tap("attack") then taps = taps + 1; last_tap = t end
    end
end

Notes

  • needs_internal = true is declared because the script uses the internal API. internal.is_loaded() at the top of on_tick checks the internal is running.
  • Turn the built in aimbot off before testing. While it holds a lock, aim.silent returns false every tick and refused_aimbot climbs.
  • The status line prints every five seconds from aim.diag(). If armed climbs and hero_hits does not, the correction is being staged and the problem is elsewhere.
  • Only hero hits are counted (victim_class ~= 0).
  • The reload branch only runs under test_mode; a tap on an empty gun would count as a tap without firing.
  • Settings live in C:\TSUKI\Deadlock\scripts\config\gun_psilent.json: fov_deg = 6, bone = "head", range_m = 60, test_mode = false. The script runs with its defaults if the file is missing.

See Aim for every option and refusal reason, Hit Events for the cursor, and Camera and Input for the external calls.