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
| Expression | Result | Notes |
|---|---|---|
v + other, v - other | vec3 | Component-wise |
v + scalar, v - scalar | vec3 | The scalar is broadcast to every component. Only this operand order works - scalar + v raises tsuki_vec3 expected, got number |
v * scalar, scalar * v | vec3 | Both orders work |
v * other | vec3 | Component-wise multiply, not a dot product. Use v:dot(other) for the dot product |
v / scalar | vec3 | Scalar only, and only on the right. A vector divisor raises number expected, got userdata. Dividing by 0 substitutes 1e-10 rather than producing inf |
There is no __unm, __eq, __lt or __len. -v and #v raise; write v * -1 for negation. a == b compares object identity, so two vectors with identical components are never equal - compare fields, or test (a - b):length() < eps.
vec2
2D vector. Same operators as vec3, including the component-wise v * other. It has no cross and no length_2d. 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 set in every situation. STUNNED fires for almost every hard stun (Knockdown, Cursed Relic, Dynamo ult) and INVISIBLE_TO_ENEMY for Smoke Bomb and Shadow Weave; others may not fire even when the player is clearly in that state. Examples:
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
All 303 flags are exposed. Some may be set by items or interactions not yet checked, so test before you ship: confirm the flag flips with the Debugging Modifiers workflow, and fall back to player:get_modifiers() by name or token if it does not.
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 |