Skip to content

Debugging Modifiers ​

If you want to write a script that reacts to a specific ability or status effect, the first thing you need to know is which modifier or flag the engine sets when that effect is active. The cheat ships with built-in logging that prints every state change in real time, which is the fastest way to figure this out.

Enabling modifier state logging ​

In the TSUKI menu, go to the Misc > Scripts > Dev Tools section and enable:

  • Modifier States: logs every flag bit that flips on or off
  • In-App Console (under Console): opens the script console window where logs print

Optional but useful:

  • Local Modifier Events / Enemy Modifier Events: log full modifier additions and removals (RTTI name + token) instead of just the bitmask flags
  • Modifier Details: pretty-prints the full modifier table when one is added

Example: finding the flag for Haze's Smoke Bomb ​

With Modifier States enabled, watch the console while the effect you care about happens. Here's what shows up when Haze casts Smoke Bomb:

Console output showing INVISIBLE_TO_ENEMY flag toggling on and off for Haze's Smoke Bomb. Click to enlarge.

Click to enlarge.

Three flags toggle on at the same time when Smoke Bomb starts:

[ModState] Haze bit 22 ON (TECH_UNTARGETABLE_BY_ENEMIES)
[ModState] Haze bit 31 ON (INVISIBLE_TO_ENEMY)
[ModState] Haze bit 32 ON (INVISIBLE_TO_ENEMY_CAST)

And then back off when it ends:

[ModState] Haze bit 22 OFF (TECH_UNTARGETABLE_BY_ENEMIES)
[ModState] Haze bit 31 OFF (INVISIBLE_TO_ENEMY)
[ModState] Haze bit 32 OFF (INVISIBLE_TO_ENEMY_CAST)

For our purposes, INVISIBLE_TO_ENEMY (bit 31) is the cleanest signal. It's set whenever an enemy is invisible to us, regardless of which ability or item caused it. Smoke Bomb, Shadow Weave, etc. all flip this bit.

Practical example: pause aimbot on invisible targets ​

If your aimbot is locking onto a Haze who just popped Smoke Bomb, you're announcing your cheat to the entire lobby. Here's a script that disables the aimbot while any visible enemy is invisible, and re-enables it when they come back:

lua
local aimbot_was_on = nil  -- nil = haven't toggled yet

function on_tick()
    local invisible_enemy = false
    for _, p in ipairs(get_players()) do
        if p:is_enemy() and p:is_alive()
           and p:has_modifier_flag(modifier_flag.INVISIBLE_TO_ENEMY) then
            invisible_enemy = true
            break
        end
    end

    if invisible_enemy and aimbot_was_on == nil then
        -- First tick we noticed an invisible enemy: remember the
        -- user's current setting and turn aimbot off.
        aimbot_was_on = tsuki.get_bool("aimbot_enabled", false)
        tsuki.set_bool("aimbot_enabled", false)
    elseif not invisible_enemy and aimbot_was_on ~= nil then
        -- Invisibility ended: restore whatever the user had before.
        tsuki.set_bool("aimbot_enabled", aimbot_was_on)
        aimbot_was_on = nil
    end
end

The state variable (aimbot_was_on) is what makes this safe. Without it, the script would force aimbot ON every tick the enemy is visible, overriding the user's own toggle. By recording the previous value, we only restore what was there before.

You can use the same pattern for any other flag-driven decision: pause auto-parry while the enemy is STUNNED (no point parrying a stunned target), pause ESP particles while you're in IN_FOUNTAIN to keep your screen clean, etc.

When the flag isn't reliable ​

Some effects don't set the flag you'd expect. SLOWED is the most common offender: many slow sources apply the effect via stat modifiers without ever tripping the flag. If your debugging shows nothing toggling for an effect that's clearly active, fall back to checking the modifier list directly:

lua
for _, m in ipairs(player:get_modifiers()) do
    print(m.name, m.token)
end

Then match by name or token. See Player > Modifiers for the full API.

Debugging bones ​

The bone system uses string names like "head", "arm_upper_l", "ankle_r". The available bones vary between heroes (Talon has weapon bones, Viscous has ball bones, etc.). To see what's actually on a hero's skeleton, enable the bone label overlay in Misc > Scripts > Dev Tools > Bone Tools > Skeleton Joint Labels.

In-game view of two heroes with bone names labeled at every joint. Click to enlarge.

Click to enlarge.

Every joint shows its bone name in real time. This is the fastest way to figure out which bone you actually want for a specific aim point, hitbox check, or 3D draw position. Bones are parsed from Deadlock's game files at startup; custom mods and Deadlock Mod Manager are supported and most custom-model bones will be parsed correctly.

To enumerate the bones on a hero from a script instead of looking at the labels, call player:bone_names():

lua
for _, name in ipairs(player:bone_names()) do
    print(name)
end

See Types & Constants > bone for the full list of named aliases and body-bone constants.

Discovering particle names ​

The particle event API (on_particle_create, on_particle_destroy) matches against full particle paths like "particles/abilities/melee/melee_heavy_activate_charge.vpcf". To find the path for a specific ability or action, enable Particle Scanner in the TSUKI menu under Misc > Scripts > Dev Tools.

The scanner logs every [Particle] Create and [Particle] Destroy event to both the in-app console and the attached Windows console. Useful toggles under Particle Scanner:

  • Show All Particles (Debug), shows every particle in the game, including towers, NPCs, and environment. Noisy; turn off when you have what you need.
  • Show Position, appends world position (x, y, z) to each log entry.
  • Dump Control Points, wide memory scan of the particle collection. Logs every float triplet that looks like world coordinates. Use this when researching which CP offset carries the data you need for a specific effect.
  • Scan Interval. How often to scan in milliseconds. Default 10ms (100Hz). Lower = faster detection, more IOCTLs.

Workflow ​

  1. Enable Particle Scanner in Dev Tools.
  2. Go into a sandbox or private lobby with a friend.
  3. Perform the action you want to detect (heavy melee, ability cast, etc.).
  4. Watch the console for [Particle] Create (enemy tN) 'particles/...' lines.
  5. Copy the relevant part of the path into your ev.name:find("...") filter.

For a curated list of commonly-used particles, see Events > Common particle names.

Not affiliated with Valve Corporation.