Skip to content

Stats

Needs the internal running and needs_internal = true in script_info.

p:get_stats() -> table | nil

Returns the player's combat stats with every item and modifier applied. Works on any player object, not just the local player. Percent fields are percentages: 18.0 means 18 percent.

Keys on every player

KeyMeaningUnit
max_healthMax healthHP
bullet_resistBullet damage reductionpercent
spirit_resistSpirit damage reductionpercent
melee_resistMelee damage reductionpercent
debuff_resistDebuff resistpercent
bullet_shieldShield pool in front of healthHP
barrierPool that soaks every damage typeHP
crit_taken_scaleCrit damage receivedmultiplier, 1.0 baseline
slow_resistSlow resistancepercent
ability_levelAbility level statnumber
dmg_taken_incAll damage taken increasepercent
bullet_dmg_taken_incBullet damage taken increasepercent
spirit_dmg_taken_incSpirit damage taken increasepercent
dmg_taken_redAll damage taken reductionpercent
bullet_dmg_red_pctBullet damage reductionpercent
ability_dmg_red_pctAbility damage reductionpercent
seqChanges when any row in the feed was refreshedinteger
entry_seqChanges when this row was refreshedinteger

The six dmg_taken_inc and dmg_taken_red keys are rarely non zero.

Keys on the local player only

Only present on the local player. On anyone else they are absent, not zero, so test with if s.bullet_damage ~= nil.

weapon_power_bonus, spirit_power, bullet_damage, fire_rate_bonus, clip_size, health_regen, move_speed, light_melee, heavy_melee, bullet_lifesteal, spirit_lifesteal, falloff_min, falloff_max

  • weapon_power_bonus and fire_rate_bonus are bonuses over the hero base, so 0 is the baseline.
  • bullet_damage is damage per bullet before resists and falloff.
  • falloff_min and falloff_max are in game units. p:get_distance() is in metres; multiply by 39.37 to compare.

Returns nil when

  • the internal is not running
  • needs_internal = true is missing
  • nothing called p:get_stats() in the last 2 seconds. The feed idles, and the first call after a gap returns nil while it starts again
  • the player is not in the feed yet
  • the player is dead. The local player stays in the feed while dead

Notes

  • Rows refresh within 100 ms.
  • The same table is returned until entry_seq changes. Do not write into it; other scripts get the same table.
  • 16 players maximum.
  • No visibility requirement.

Example

Bullets to kill on the nearest enemy, from Shots to Kill:

lua
function on_tick()
    local x, y = 40, 460
    local function line(t, c, sc) draw.text(x, y, t, c or WHITE, sc or 1.15); y = y + 18 end

    if not internal.is_loaded() then line("shots_to_kill: internal not loaded", DIM); return end
    local me = local_player and local_player() or nil
    local ms = me and me:get_stats() or nil
    if not ms or not ms.bullet_damage then line("shots_to_kill: waiting for local stats", DIM); return end

    local e, d = nearest_enemy()
    local es = e and e:get_stats() or nil
    if not e or not es then line("shots_to_kill: no enemy stats yet", DIM); return end

    local B   = ms.bullet_damage
    local R   = (es.bullet_resist or 0) / 100
    local inc = ((es.dmg_taken_inc or 0) + (es.bullet_dmg_taken_inc or 0)) / 100
    local red = ((es.dmg_taken_red or 0) + (es.bullet_dmg_red_pct or 0)) / 100
    local per = B * (1 - R) * (1 + inc) * (1 - red)
    if per < 0.1 then line("shots_to_kill: per-hit damage ~0", DIM); return end

    local pool  = (e:get_health() or es.max_health or 0) + (es.bullet_shield or 0) + (es.barrier or 0)
    line(string.format("%d body", math.ceil(pool / per)), GREEN, 1.4)
end

bullet_damage is only on your own row and the resists are on the enemy's, so either read can be nil while the other answers. nearest_enemy is a helper defined in that script. For headshots, a multiplier of about 1.65 is an observed value, not something the API returns.