Types & Constants ​
Vec2/vec3 math types and the named constant tables (modifier_flag, slot, bone, hero_id).
vec3 ​
3D vector. Returned by position queries and used as input to drawing functions.
local v = vec3(100, 200, 50)
v.x, v.y, v.z -- field access| Method | Returns | Description |
|---|---|---|
v:length() | number | Magnitude |
v:length_sqr() | number | Squared magnitude (cheaper than length()) |
v:length_2d() | number | XY magnitude (ignores Z) |
v:normalized() | vec3 | Unit vector |
v:dot(other) | number | Dot product |
v:cross(other) | vec3 | Cross product |
v:distance(other) | number | Distance to another point |
v:angle_to(other) | number | Angle in degrees |
v:empty() | boolean | True if all zero |
Operators: v + other, v - other, v * scalar, v / scalar.
vec2 ​
2D vector. Same operators as vec3 minus cross (+, -, *, /). Use vec2(x, y) to construct.
| Method | Returns | Description |
|---|---|---|
v:length() | number | Magnitude |
v:length_sqr() | number | Squared magnitude (cheaper than length()) |
v:normalized() | vec2 | Unit vector |
v:dot(other) | number | Dot product |
v:distance(other) | number | Distance to another point |
v:angle_to(other) | number | Angle in degrees (atan2) |
v:empty() | boolean | True if both components are zero |
modifier_flag ​
Status flags you can check via player:has_modifier_flag(...). There are 303 in total; below are the ones most scripts use. For the complete list see Modifier Flags Reference.
if player:has_modifier_flag(modifier_flag.STUNNED) then ... endThere is no string shorthand for modifier_flag checks. player:is_(flag) requires an integer (a player_flag bitmask such as player_flag.onground); passing a string throws a Lua error via luaL_checkinteger. To check a modifier by name string, use player:has_modifier("stunned") instead.
| Flag | Value |
|---|---|
IMMOBILIZED | 11 |
DISARMED | 12 |
MUTED | 13 |
ITEMS_DISABLED | 14 |
SILENCED | 15 |
SILENCE_MOVEMENT_ABILITES | 16 |
STUNNED | 18 |
INVULNERABLE | 19 |
STATUS_IMMUNE | 24 |
UNSTOPPABLE | 25 |
COMMAND_RESTRICTED | 28 |
CHARGING | 29 |
OBSCURED | 30 |
INVISIBLE_TO_ENEMY | 31 |
INVISIBLE_TO_ENEMY_CAST | 32 |
SPRINTING | 35 |
UNKILLABLE | 36 |
IN_SHOP | 45 |
IN_FOUNTAIN | 46 |
DASH_DISABLED | 52 |
BURNING | 54 |
SLOWED | 61 |
SHOOTING_DISABLED | 62 |
SLIDING | 65 |
VISIBLE_TO_ENEMY | 68 |
IS_ASLEEP | 75 |
USING_ZIPLINE | 84 |
BULLET_INVULNERABLE | 92 |
MELEE_DISABLED | 106 |
GLITCHED | 109 |
RELOAD_DISABLED | 112 |
FLYING | 119 |
SCOPED | 120 |
VISCOUS_CUBED | 122 |
IN_COMBAT | 163 |
YAMATO_SHADOW_FORM | 166 |
FROZEN | 193 |
PARRY_ACTIVE | 219 |
WEREWOLF | 260 |
Caveat ​
Not every flag is populated by the engine in every situation. Some flags are set reliably and broadly (e.g. STUNNED fires for almost every hard stun: Knockdown, Cursed Relic, Dynamo ult, etc., and INVISIBLE_TO_ENEMY fires for Smoke Bomb, Shadow Weave, etc.). Others may not fire at all even when the player is clearly in that state. Examples we've seen in testing:
SLIDINGmay not be set while a player is slidingUSING_ZIPLINEmay not be set while a player is on a ziplineIS_IN_CHARGE_MELEEmay not be set during a heavy charged meleeSLOWEDandBURNINGare inconsistent: some sources set them, others apply the effect via stat modifiers without ever tripping the flag
The full list of 303 flags is exposed for completeness. Some of them may turn out to be set by items or interactions we haven't tested, so they're available if you discover one that's useful. But test before you ship. Use the Debugging Modifiers workflow to confirm the flag actually flips during the effect you care about. If it doesn't, fall back to player:get_modifiers() and match by name or token directly.
slot ​
Ability, item, and action slot indexes.
| Constant | Value | Description |
|---|---|---|
slot.ability1 | 0 | Hero ability 1 |
slot.ability2 | 1 | Hero ability 2 |
slot.ability3 | 2 | Hero ability 3 |
slot.ability4 | 3 | Ultimate |
slot.item1 | 4 | Active item 1 |
slot.item2 | 5 | Active item 2 |
slot.item3 | 6 | Active item 3 |
slot.item4 | 7 | Active item 4 |
slot.held | 8 | Currently-held / channeled action |
slot.zipline | 9 | Zipline ride |
slot.mantle | 10 | Mantle (ledge grab) |
slot.climb_rope | 11 | Climb rope |
slot.jump | 12 | Jump |
slot.slide | 13 | Slide |
slot.teleport | 14 | Teleport |
slot.zipline_boost | 15 | Zipline boost |
slot.cosmetic1 | 16 | Cosmetic slot 1 |
slot.innate1 | 17 | Innate ability 1 |
slot.innate2 | 18 | Innate ability 2 |
slot.innate3 | 19 | Innate ability 3 |
slot.weapon_secondary | 20 | Secondary weapon |
slot.weapon_primary | 21 | Primary weapon |
slot.weapon_melee | 22 | Melee weapon |
Slots 0-3 are abilities, 4-7 are items, 8-22 are action/weapon slots. for i = slot.ability1, slot.ability4 do ... end iterates 0,1,2,3 and for i = slot.item1, slot.item4 do ... end iterates 4,5,6,7.
local key = slot_to_key(slot.ability3)
input.press_key(key)bone ​
String constants for player:bone_pos(...) and the targeting helpers. Bones are parsed from Deadlock's game files at startup; custom mods and Deadlock Mod Manager are supported and bones from custom models are parsed when the model ships standard VPK skeleton names.
local head_pos = player:bone_pos("head") -- string literal works
local head_pos = player:bone_pos(bone.head) -- bone.head == "head"
local head_pos = player:bone_pos(7) -- raw integer index, legacyNames are case-insensitive: "arm_upper_L" and "arm_upper_l" both resolve to the same bone.
Named aliases ​
These standard aliases map to specific VPK bones with fallback chains. If the primary bone isn't present on a hero's model, the alias falls back to the next one in the chain.
| Alias | Primary bone | Fallback chain |
|---|---|---|
bone.head | head | (exact only) |
bone.neck | neck | neck_0 (no further fallback) |
bone.chest | spine_3 | spine_2 → spine_1 → spine_0 |
bone.lower_chest | spine_2 | spine_1 → chest result |
bone.stomach | spine_0 | spine_1 |
bone.pelvis | pelvis | (exact only) |
Body bones ​
All standard humanoid body bones are available as bone.* constants. These don't have fallback chains; if the model doesn't have the bone, bone_pos returns nil.
| Constant | Value |
|---|---|
bone.clavicle_l, bone.clavicle_r | "clavicle_l", "clavicle_r" |
bone.arm_upper_l, bone.arm_upper_r | "arm_upper_l", "arm_upper_r" |
bone.arm_lower_l, bone.arm_lower_r | "arm_lower_l", "arm_lower_r" |
bone.hand_l, bone.hand_r | "hand_l", "hand_r" |
bone.leg_upper_l, bone.leg_upper_r | "leg_upper_l", "leg_upper_r" |
bone.leg_lower_l, bone.leg_lower_r | "leg_lower_l", "leg_lower_r" |
bone.ankle_l, bone.ankle_r | "ankle_l", "ankle_r" |
bone.ball_l, bone.ball_r | "ball_l", "ball_r" |
To discover all bones on a specific model at runtime, use player:bone_names(). The full body bone set varies between heroes (some have ears, tails, weapon bones, etc.).
Raw spine bones ​
The aliases above (bone.chest, bone.lower_chest, bone.stomach) map to spine bones with fallback chains. The raw bones are also exposed as constants if you want to target a specific vertebra without the fallback:
| Constant | Value |
|---|---|
bone.spine_0 | "spine_0" (stomach) |
bone.spine_1 | "spine_1" |
bone.spine_2 | "spine_2" (lower chest) |
bone.spine_3 | "spine_3" (chest) |
bone.neck_0 | "neck_0" (neck) |
Notes ​
- Bone probing only runs on enemies. Calling
bone_poson a teammate falls back to the player's origin position. - See Debugging Modifiers for the in-menu bone label overlay that shows every bone on a hero in real time.
hero_id ​
Hero identifier passed at script load and returned by player:get_hero_id().
id = hero_id.any -- script runs regardless of which hero is selected
-- Gate logic on a specific hero at runtime:
local lp = local_player()
if lp and lp:get_hero_id() == hero_id.haze then ... end| Constant | Value |
|---|---|
hero_id.any | -1 |
hero_id.none | 0 |
hero_id.infernus | 1 |
hero_id.seven | 2 |
hero_id.vindicta | 3 |
hero_id.ladygeist | 4 |
hero_id.abrams | 6 |
hero_id.wraith | 7 |
hero_id.mcginnis | 8 |
hero_id.paradox | 10 |
hero_id.dynamo | 11 |
hero_id.kelvin | 12 |
hero_id.haze | 13 |
hero_id.holliday | 14 |
hero_id.bebop | 15 |
hero_id.calico | 16 |
hero_id.greytalon | 17 |
hero_id.moandkrill | 18 |
hero_id.shiv | 19 |
hero_id.ivy | 20 |
hero_id.warden | 25 |
hero_id.yamato | 27 |
hero_id.lash | 31 |
hero_id.viscous | 35 |
hero_id.pocket | 50 |
hero_id.mirage | 52 |
hero_id.dummy | 55 |
hero_id.viper | 58 |
hero_id.vyper | 58 |
hero_id.sinclair | 60 |
hero_id.mina | 63 |
hero_id.drifter | 64 |
hero_id.venator | 65 |
hero_id.victor | 66 |
hero_id.paige | 67 |
hero_id.doorman | 69 |
hero_id.billy | 72 |
hero_id.graves | 76 |
hero_id.apollo | 77 |
hero_id.rem | 79 |
hero_id.silver | 80 |
hero_id.celeste | 81 |
hero_id.viper and hero_id.vyper are the same value (58). IDs are non-sequential; not all integers in the range are assigned. Use print(player:hero_name(), player:get_hero_id()) at runtime to discover values for heroes not yet listed.
bucket ​
Item upgrade bucket categories. Returned as ActiveItemInfo.bucket and accepted by any API that filters by upgrade tier.
| Constant | Value | Description |
|---|---|---|
bucket.innate | 0 | Innate / passive |
bucket.weapon | 1 | Weapon |
bucket.vitality | 2 | Vitality |
bucket.spirit | 3 | Spirit |
local items = player:get_active_items()
for _, item in ipairs(items) do
if item.bucket == bucket.weapon then
print("weapon item:", item.name)
end
endmodifier_token ​
Named subclass token IDs for well-known modifiers. Pass to player:has_modifier(token) or compare against ModifierInfo.token. Values are uint32 constants.
if player:has_modifier(modifier_token.knockdown) then
print("target is knocked down")
end| Constant | Value |
|---|---|
modifier_token.knockdown | 0x4ABFEA98 |
modifier_token.bebop_sticky_bomb | 0x96512C8E |
modifier_token.lash_death_slam | 0x17A9E77A |
modifier_token.warden_binding_word | 0x62C27FFE |
modifier_token.paige_captivating_read | 0xB6177F0A |
modifier_token.seven_static_charge | 0x400ED943 |
modifier_token.doorman_call_bell | 0x062B3CCC |
modifier_token.viktor_rebirth | 0xD04073B3 |
modifier_token.calico_cat | 0x3C249027 |
modifier_token.mo_burrow | 0x8F74398D |
modifier_token.rem_ability | 0x5D82ADA5 |
player_flag ​
Player entity flags (FL_* bitfield). Test with player:is_(flag). Values are bitmasks (1<<N), not raw bit indices - do not pass them to has_modifier_flag.
if player:is_(player_flag.onground) then
print("player is on the ground")
end| Constant | Value | Bit |
|---|---|---|
player_flag.onground | 1 | 1<<0 |
player_flag.ducking | 2 | 1<<1 |
player_flag.waterjump | 4 | 1<<2 |
player_flag.frozen | 32 | 1<<5 |
player_flag.atcontrols | 64 | 1<<6 |
player_flag.client | 128 | 1<<7 |
player_flag.fakeclient | 256 | 1<<8 |
player_flag.fly | 16384 | 1<<14 |
player_flag.godmode | 32768 | 1<<15 |
player_flag.notarget | 65536 | 1<<16 |
player_flag.aimtarget | 131072 | 1<<17 |
player_flag.staticprop | 262144 | 1<<18 |
player_flag.grenade | 524288 | 1<<19 |
player_flag.donttouch | 1048576 | 1<<20 |
player_flag.basevelocity | 2097152 | 1<<21 |
player_flag.worldbrush | 4194304 | 1<<22 |
player_flag.object | 8388608 | 1<<23 |
player_flag.onfire | 33554432 | 1<<25 |
player_flag.dissolving | 67108864 | 1<<26 |
player_flag.transragdoll | 134217728 | 1<<27 |
player_flag.unblockable_by_player | 268435456 | 1<<28 |
VK codes (common) ​
Windows virtual-key codes for input.*. Full list at Microsoft's docs.
The overlay exposes a VK table with named constants so you don't have to remember raw hex values:
-- Named constants
input.is_key_held(VK.LBUTTON) -- left mouse
input.is_key_held(VK.SHIFT) -- Shift
input.is_key_held(VK.F) -- F key
input.is_key_held(VK.LCONTROL) -- Left Ctrl
-- Raw hex works too
input.is_key_held(0x01)| Constant | Code | Key |
|---|---|---|
VK.LBUTTON | 0x01 | Left mouse |
VK.RBUTTON | 0x02 | Right mouse |
VK.MBUTTON | 0x04 | Middle mouse |
VK.XBUTTON1 | 0x05 | Mouse 4 |
VK.XBUTTON2 | 0x06 | Mouse 5 |
VK.RETURN | 0x0D | Enter / Return |
VK.SHIFT | 0x10 | Shift |
VK.CONTROL | 0x11 | Ctrl (either) |
VK.ESCAPE | 0x1B | Escape |
VK.SPACE | 0x20 | Space |
VK.KEY_0-VK.KEY_9 | 0x30-0x39 | Digit keys 0-9 |
VK.A-VK.Z | 0x41-0x5A | A-Z |
VK.F1-VK.F12 | 0x70-0x7B | F1-F12 |
VK.LCONTROL | 0xA2 | Left Ctrl |