Skip to content

Player Object ​

Returned by local_player(), get_players(), event callbacks, and modifier.caster.

All methods are colon-style: p:method().

Identity ​

FunctionReturnsDescription
p:hero_name()stringDisplay name: "Ivy", "Vindicta", "Viscous", etc.
p:get_hero_id()integerNumeric hero ID (compare with hero_id enum)
p:get_team()integerTeam number (typically 2 or 3)
p:is_local()booleanTrue only for the local player
p:is_enemy()booleanTrue if on the opposing team
p:is_valid()booleanTrue if player data is currently readable
p:entity_ptr()integerRaw pawn pointer (advanced use)

State ​

FunctionReturnsDescription
p:is_alive()booleanHealth > 0
p:get_health()numberCurrent health
p:get_max_health()numberMaximum health
p:get_health_percentage()numberHealth as 0.0 to 1.0
p:is_visible()booleanVisible to local player (vischeck)
p:is_on_screen()booleanWithin screen bounds
p:is_scoped()booleanCurrently scoped or zoomed
p:is_in_reload()booleanCurrently reloading
p:get_reload_progress()numberReload progress 0.0 to 1.0
p:is_primary_weapon_active()booleanPrimary weapon is the active slot
p:is_in_melee_attack()booleanCurrently performing a melee attack
p:is_targetable()booleanCan be targeted (not invulnerable)
p:get_active_projectile_speed()numberEffective gun projectile speed (u/s), includes velocity item multiplier. Returns 0 until the gun resolves. Local player only
p:get_souls()integerTotal souls (net worth)
p:get_unsecured_souls()integerUnsecured souls (lost on death)

Position and Movement ​

FunctionReturnsDescription
p:get_position()vec3World position (feet)
p:get_head_world()vec3Head position in world space
p:get_velocity()vec3Movement velocity vector
p:get_view_angles()vec3Pitch, yaw, roll in degrees
p:bone_pos(name_or_index)vec3 | nilWorld position of a skeleton bone. Accepts a name string ("head", "arm_upper_l", etc.) or bone.* constant. Raw integer indexes work as legacy. Returns nil if the bone isn't found
p:get_bone_position(...)vec3 | nilLegacy alias for p:bone_pos. Identical behavior
p:bone_names()tableAll available bone names for this player's current model. Empty table if bones haven't been probed yet
p:get_distance([other])numberMeters to local player, or to other if provided

Stamina ​

Local player only

Stamina is not replicated to other clients. These functions return 0 when called on enemy or teammate handles.

FunctionReturnsDescription
p:get_stamina()numberCurrent stamina (e.g. 3.0)
p:get_max_stamina()numberMaximum stamina (e.g. 4.0)
lua
local me = local_player()
local pct = me:get_stamina() / me:get_max_stamina() * 100
print(string.format("Stamina: %.0f%%", pct))

Crouch ​

Local player only

Crouch state is not replicated to other clients. Returns 0 / false for non-local players.

FunctionReturnsDescription
p:get_crouch_fraction()number0.0 = standing, 1.0 = fully crouched. Values between indicate a transition
p:is_crouched()booleantrue when crouch fraction > 0.5
lua
local me = local_player()
if me:is_crouched() then
    print("Crouching: " .. string.format("%.0f%%", me:get_crouch_fraction() * 100))
end

Ground Normal / Slope ​

Local player only

Ground normal requires local movement data. Returns {0, 0, 0} / 0 for non-local players.

FunctionReturnsDescription
p:get_ground_normal()vec3Surface normal of the ground. {0, 0, 1} on flat ground
p:get_slope_angle()numberSlope angle in degrees. 0 = flat, 45 = steep, 90 = wall

The z component of the ground normal indicates steepness:

z valueMeaning
1.0Flat ground
0.87~30° slope
0.71~45° slope
0.0Vertical wall
lua
local me = local_player()
local slope = me:get_slope_angle()
if slope > 30 then
    print("Steep slope: " .. string.format("%.1f°", slope))
end

local gn = me:get_ground_normal()
print(string.format("Surface: (%.2f, %.2f, %.2f)", gn.x, gn.y, gn.z))

Screen Space ​

FunctionReturnsDescription
p:screen_box()table | nil{x, y, w, h} bounding box on screen
p:screen_head()table | nil{x, y} head position on screen
p:screen_origin()table | nil{x, y} feet position on screen

Returns nil if the player is off-screen or behind the camera.

Modifier Flags ​

Fast bitmask check for common status effects.

FunctionReturnsDescription
p:has_modifier_flag(flag)booleanCheck a single flag from modifier_flag enum
p:is_(name)booleanString shorthand: p:is_("stunned"), p:is_("silenced")
lua
if player:has_modifier_flag(modifier_flag.STUNNED) then
    -- stunned
end

See Types & Constants for the full flag list.

Modifiers (full data) ​

For modifiers that aren't covered by flags (channeling abilities, item effects, etc.), use the full modifier query.

FunctionReturnsDescription
p:has_modifier(name_or_token)booleanTrue if any modifier matches. String arg = substring match on RTTI name; integer arg = exact token match
p:get_modifier(name_or_token)table | nilFirst matching modifier, or nil. Same matching rules as has_modifier
p:get_modifier_count()integerNumber of active modifiers
p:get_modifier_names()tableArray of RTTI class name strings
p:get_modifiers()tableArray of all modifier tables
lua
-- Substring match: catches modifier_stunned, modifier_delayed_stun, etc.
if player:has_modifier("stun") then ... end

-- Exact token match
if player:has_modifier(0x9C02E614) then ... end

Each modifier table (returned by get_modifier and as entries in get_modifiers) has these fields:

FieldTypeDescription
namestringRTTI class name, e.g. "modifier_glitch"
tokenintegerAbility subclass ID, e.g. 0x9C02E614
durationnumber-1 if permanent, > 0 if temporary
remainingnumberSeconds left (0 if permanent or expired)
expires_atnumbergame_time() when effect ends
is_activebooleanHas duration and hasn't expired
ability_namestringLinked ability class name
ability_cdnumberAbility cooldown remaining
ability_coolingbooleanAbility is on cooldown
serialintegerUnique instance ID (distinguishes duplicate tokens)
casterplayer | nilWho applied the modifier (nil if unknown)
lua
local m = player:get_modifier("stunned")
if m and m.is_active then
    print(m.remaining, "seconds left, applied by", m.caster and m.caster:hero_name())
end

for _, m in ipairs(player:get_modifiers()) do
    if m.is_active and m.caster and m.caster:is_enemy() then
        print(m.name, m.remaining)
    end
end

Ultimate ​

FunctionReturnsDescription
p:is_ult_trained()booleanUltimate has been skilled
p:is_ult_ready()booleanTrained AND off cooldown
p:get_ult_cooldown()numberSeconds remaining (-1 = not trained, 0 = ready)

Abilities (slots 0-3) & Weapon Slots ​

Hero abilities, active items, and weapon slots.

FunctionReturnsDescription
p:has_abilities()booleanPlayer has any abilities loaded
p:is_ability_ready(slot)booleanSlot is ready to cast
p:get_ability(slot)table | nilSingle ability data (see below)
p:get_abilities()tableArray of all four ability tables

Slot Constants ​

slot.*ValueMeaning
slot.ability1 … slot.ability40–3Hero abilities (signature 1–4)
slot.item1 … slot.item44–7Active items
slot.weapon_secondary20Secondary weapon / alt-fire
slot.weapon_primary21Primary gun
slot.weapon_melee22Melee

Local player only

Weapon slots (20–22) are local player only. Items (4–7) return as items, not abilities. They don't populate projectile_speed.

Each ability table has:

FieldTypeDescription
namestringRTTI name, e.g. "citadel_ability_tengu_airlift"
slotintegerSlot number
pointsintegerUpgrade points spent
learnedbooleanHas been skilled
cooldownnumberSeconds remaining
is_readybooleanLearned, not on cd, not casting
is_cooling_downbooleanOn cooldown
is_castingbooleanMid-cast
is_channelingbooleanCurrently channeling
is_in_cast_delaybooleanIn pre-cast windup
remaining_chargesintegerRemaining charges (-1 = not charge-based)
projectile_speednumberBase projectile speed in u/s (VData, not item-boosted). 0 = no projectile
rangenumberCast range (currently always 0, unimplemented)

Projectile Speed ​

get_ability(slot).projectile_speed returns the base (VData) speed. For the gun's effective speed including velocity items, use get_active_projectile_speed() instead.

lua
local me = local_player()

-- Ability projectile speed (base)
local dagger = me:get_ability(slot.ability1)
if dagger then print(dagger.name, dagger.projectile_speed) end

-- Gun base vs effective
local gun_base = me:get_ability(slot.weapon_primary)
local effective = me:get_active_projectile_speed()
-- effective = base × (1 + 0.6 × velocity_item_count)

Owned Items ​

All purchased items (m_vecUpgrades). Match by case-insensitive display name OR hex token.

FunctionReturnsDescription
p:get_item_count()integerNumber of owned items
p:has_item(name_or_token)boolean"Cursed Relic", "cursed relic", or 0x9C02E614 all work
p:get_item(name_or_token)table | nilItem table or nil if not owned
p:get_items()tableAll owned items

Each item table has:

FieldTypeDescription
tokenintegere.g. 0x5230D219
namestringDisplay name, e.g. "Metal Skin"
lua
if player:has_item("Cursed Relic") then
    -- ...
end

for _, it in ipairs(player:get_items()) do
    print(string.format("0x%08X  %s", it.token, it.name))
end

Active Items (slots 4-7) ​

Items in ability slots with cooldown tracking. Matched by RTTI substring (lowercase, snake_case).

FunctionReturnsDescription
p:get_active_item_count()integerNumber of active items equipped
p:has_active_item(substring)booleanRTTI substring match
p:get_active_item(substring)table | nilSingle active item data
p:get_active_items()tableArray of all active items

Each active item table has:

FieldTypeDescription
namestringRTTI class name
subclassstringSubclass name
slotinteger4-7
bucketintegerItem bucket
cooldownnumberSeconds remaining
lua
if player:has_active_item("metal_skin") then
    local mskin = player:get_active_item("metal_skin")
    print("cd:", mskin.cooldown)
end

Not affiliated with Valve Corporation.