Skip to content

Ability Values ​

Needs the internal running and needs_internal = true in script_info. Works on every player.

p:get_ability_value(slot, "PropertyName" [, rate_ms]) -> number | nil

Returns the resolved value of one ability property, with that player's bought upgrade tiers and spirit power applied. This is the number the in-game tooltip shows. p:get_ability_properties(slot) (external, on the Player page) returns the base values before upgrades.

slot is an integer: 0 to 3 for abilities, 4 to 7 for active items, the same numbering as p:get_ability(slot). Active items only work on yourself, so on other players use 0 to 3. On another Silver, her HUD abilities are slots 0, 2, 4 and 6 (see Ability upgrades). A string raises an error. Weapon slots 20 to 22 always return nil.

rate_ms is optional. See Refresh rates.

input.cast counts from 1

input.cast(1) is the ability that is slot 0 here.

Property names are the game's own. Call p:get_ability_properties(slot) on yourself to list the ones an ability has. Common names: AbilityCooldown, AbilityCharges, AbilityCastRange, AbilityRadius, Damage, HeadshotBonus, TimeToFullCharge.

Units are the property's own: seconds for AbilityCooldown and TimeToFullCharge, raw damage for Damage, a count for AbilityCharges (0 means no charge system), percent for names ending in Pct or Percent and for HeadshotBonus.

lua
for _, e in ipairs(get_players()) do
    if e:is_enemy() then
        local cd = e:get_ability_value(0, "AbilityCooldown")
        if cd then print(e:hero_name() .. " ability 1 cooldown: " .. cd .. " s") end
    end
end

Several at once ​

p:get_ability_values({ {slot, "Name"}, ... } [, rate_ms]) -> table

Asks for a whole list in one call. result[i] is the value for list[i], or nil. Without needs_internal = true, or for a player that can no longer be read, the whole call returns nil instead of a table. Loop over 1..#list, not #result, because a nil in the middle is a real answer ("not ready yet").

lua
local want = { { 1, "AbilityCooldown" }, { 1, "AbilityCharges" }, { 2, "AbilityCooldown" } }
local got  = me:get_ability_values(want)
for i = 1, #want do
    print(want[i][2], got[i])
end

You get the same answers as calling get_ability_value for each pair, but they all arrive together.

By ability name ​

p:get_ability_value_by_name(ability, "PropertyName" [, rate_ms]) -> number | nil
p:get_ability_name(slot) -> string | nil

get_ability_value_by_name is the same, but you pick the ability by its exact designer name instead of its slot, for example "ability_vampirebat_steallife". Names from get_ability_name and p:get_ability_upgrades() work here. It works on every player.

It also gives a value for an ability the player doesn't have, using no upgrades and just their spirit power. So getting a number doesn't prove they have it.

get_ability_name(slot) returns the designer name of a player's ability in slot 0 to 3, for example "viscous_goo_grenade". It works for every hero, even ones newer than your TSUKI build. The first call returns nil, and the name arrives a few ticks later.

lua
for s = 0, 3 do
    local n = enemy:get_ability_name(s)
    if n then print("ability " .. (s + 1) .. ": " .. n) end
end

To see how much damage your ability does to a player, see Damage preview.

Returns nil when ​

  • the internal is not running, or the flag is missing
  • the slot is empty
  • the property does not exist on that ability
  • on another player: the slot is past the end of their ability list (4 and up for most heroes)
  • by name: the ability does not exist
  • it is the first call for that (ability, property). The value usually arrives within a quarter of a second
  • the property name or the ability name is 48 characters or longer
  • all 32 pairs are in use and none can be replaced (see Limits)

In these cases the answer is never 0, so you can tell a real zero from a failed read.

Limits ​

  • 32 (ability, property) pairs, shared by all scripts. Each player counts separately, so one property on four abilities of six enemies uses 24. When all 32 are in use, a new pair takes the spot of the one unused the longest, but only if nobody asked for it in the last 1.5 seconds. Otherwise the new pair returns nil. A pair you ask for every tick is never replaced.
  • get_ability_name uses one pair for each player and slot you ask about.
  • Values refresh within 250 ms.
  • A pair nobody asked for in 10 seconds is dropped. Asking again re-registers it.

To check whether you hit the limit, call internal.ability_values_diag(). requests is the number of pairs in use, and overflow counts the ones turned away.

Example ​

Read a fixed set of properties for the ult slot once a second:

lua
script_info = { name = "vindicta_ult_values", needs_internal = true }

local VINDICTA = { "AbilityCharges", "Damage", "HeadshotBonus",
                   "LowHealthEnemyDamageBonus", "LowHealthEnemyThresholdPct",
                   "MinChargeDamagePercent", "TimeToFullCharge" }
local props, next_props = {}, 0

local function refresh_props(me)
    for _, k in ipairs(VINDICTA) do props[k] = me:get_ability_value(3, k) end
end

function on_tick()
    local me = local_player()
    if not me or not internal.is_loaded() then return end
    local t = clock()
    if t >= next_props then next_props = t + 1.0; refresh_props(me) end
    if props.Damage then
        draw.text(40, 300, string.format("Damage %.0f  charges %.0f", props.Damage, props.AbilityCharges or 0), 0xFFFFFFFF)
    end
end

The first pass returns nil for every key. The values arrive on a later pass.