Skip to content

Abrams Auto Charge ​

Hold mouse-5 to snap to the closest enemy in your FOV and charge them with ability 2. The script keeps tracking the target during the charge until the charge connects, the target dies, or the target becomes untargetable.

What this shows ​

  • Hero-locked script. Setting id = hero_id.abrams means the script only runs when you're playing Abrams. If you switch heroes, it goes idle on its own.
  • Modifier-driven state. The script watches the local player's bullcharging modifier, which is active while Abrams is mid-charge. When it ends (hit, miss or cancel), the script stops tracking.
  • Hit detection via modifier. The enemy gets a chargedragenemy modifier the moment the charge connects. If the target has it, the hit landed.
  • Identity guard. A stored player object can point at a different player on a later tick. The script saves the hero name when it locks on and checks it every tick.
  • Bone guard. bone_pos returns nil when the bone can't be read, so the script only snaps on ticks where it gets a position.

Script ​

lua
-- Abrams Auto Charge
-- Press mouse5 -> snap to closest enemy -> charge -> track until hit
--
-- API reference:
--   hero_id.abrams               hero filter, script only runs on Abrams
--   slot.ability2                ability slot (0-3 abilities, 4-7 items)
--   bone.head                    named bone (head, neck, chest, spine_1, pelvis, etc.)
--   VK.XBUTTON2                  mouse5 virtual key code
--
--   local_player()               returns local player
--   targeting.find_closest_by_fov(fov_deg, range_m)  best target in FOV cone
--   snap_to_target(player, {bone = bone.X})          smoothed aim toward a bone
--   press_ability(slot.X)        press ability keybind
--
--   player:has_modifier(name)    substring match on active modifiers
--   player:is_alive()            alive check
--   player:is_targetable()       alive + not immune
--   player:hero_name()           hero name string
--   player:get_distance()        distance in meters
--   player:bone_pos(bone)        bone world position
--
--   toast(text, dur, {bg, text, outline, scale})  styled notification
--   clock()                      high-res timer (seconds)
--   input.is_key_held(vk)        true while key held

name = "Abrams Auto Charge"
id   = hero_id.abrams

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 },
}

local locked_target = nil
local locked_hero = nil
local lock_time = 0

function on_tick()
    local lp = local_player()
    if not lp or not lp:is_alive() then
        locked_target = nil
        locked_hero = nil
        return
    end

    local charging = lp:has_modifier("bullcharging")
    local now = clock()

    -- Phase 2: mid-charge tracking
    if locked_target then
        local in_grace = (now - lock_time) < 0.3

        if charging or in_grace then
            -- index shift guard: check we're still aimed at the right hero
            if locked_target:hero_name() ~= locked_hero then
                locked_target = nil
                locked_hero = nil
                return
            end

            -- hit: enemy received charge drag modifier
            if locked_target:has_modifier("chargedragenemy") then
                toast(string.format("Charged %s!", locked_hero), 3, {
                    bg = {r=20, g=60, b=20, a=220},
                    text = {r=100, g=255, b=100},
                })
                locked_target = nil
                locked_hero = nil
                return
            end

            -- target lost
            if not locked_target:is_alive() or not locked_target:is_targetable() then
                toast("Target lost", 2, {
                    bg = {r=80, g=10, b=10, a=220},
                    text = {r=255, g=80, b=80},
                })
                locked_target = nil
                locked_hero = nil
                return
            end

            -- zero bone guard + track
            local bp = locked_target:bone_pos(bone.head)
            if bp and (bp.x ~= 0 or bp.y ~= 0 or bp.z ~= 0) then
                snap_to_target(locked_target, { bone = bone.head })
            end
            return
        end

        -- charge ended
        locked_target = nil
        locked_hero = nil
    end

    -- Phase 1: initiate
    if not input.is_key_held(VK.XBUTTON2) then return end
    if not lp:is_ability_ready(slot.ability2) then return end

    local target = targeting.find_closest_by_fov(
        config.get_float("fov"),
        config.get_float("max_range")
    )
    if not target or not target:is_targetable() then return end

    -- lock + snap + fire
    locked_target = target
    locked_hero = target:hero_name()
    lock_time = now
    snap_to_target(target, { bone = bone.head })
    press_ability(slot.ability2)

    toast(string.format("Charging %s!", locked_hero), 2, {
        bg = {r=15, g=25, b=60, a=220},
        text = {r=120, g=180, b=255},
    })
end

Adapting this to other heroes ​

The script locks on when you press the key, snaps to the target, fires the ability, tracks the charge through the modifier, and lets go on a hit or miss. This works for most charge abilities that have travel time. For a different hero, change these:

  • id = hero_id.X sets which hero the script runs on. Remove the line to make it run on any hero.
  • slot.abilityN sets which ability slot the script presses and checks for readiness.
  • The two modifier names. One is on the local player while you use the ability, and the other is on the target when the ability hits. The easiest way to find both is the Debugging Modifiers workflow. Turn on the live modifier dump, use the ability in-game, and see what shows up.
  • bone.head is the snap target. The head works for upper-body abilities. For AOE drops, use bone.pelvis or the player position instead.

The grace period (0.3 seconds) keeps tracking through the short windup before the modifier appears on you. For an ability with a longer windup, increase that number.