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 | nilReturns 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.
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
endSeveral at once
p:get_ability_values({ {slot, "Name"}, ... } [, rate_ms]) -> tableAsks 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").
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])
endYou 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 | nilget_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.
for s = 0, 3 do
local n = enemy:get_ability_name(s)
if n then print("ability " .. (s + 1) .. ": " .. n) end
endTo 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_nameuses 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:
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
endThe first pass returns nil for every key. The values arrive on a later pass.