Scripting and trolling

ZimanDLC runs Lua 5.2 scripts inside the client. Write them in the Scripts tab of the menu, press Run, and they react to the game every tick. This page covers the whole API and the CS-style movement modules (Movement tab, plus AntiAim in Combat).

Your first script

  1. Open the client menu (Right Shift) and pick Scripts in the sidebar.
  2. Press + to make a script. It's saved as config/zimandlc/scripts/script1.lua in your game folder.
  3. Click into the editor, write something, press Run.
function on_load()
  print("hi " .. player.name())
end

function on_render()
  render.text("I'm alive", 20, 20)
end

A script is a plain Lua file that defines some of the callback functions. The client calls them when things happen. Everything you print shows up in the console under the editor, and so do errors.

Scripts that were running when you quit start again next time. On first launch you get hello.lua: a speed readout on the HUD, plus the K key toggles AntiAim.

The editor

Click a script in the list to open it. The green dot means it's running.

KeyWhat it does
Ctrl+SSave. A running script restarts with the new code.
Ctrl+EnterSave and run.
Ctrl+VPaste at the cursor. Tabs become two spaces.
Ctrl+CCopy the whole script. The editor has no selection.
Ctrl+DDuplicate the current line.
TabIndent by two spaces. Enter keeps the indent, and adds a level after then, do, function(…) and {.
Home / EndJump to the start of the code or the end of the line. Page Up and Page Down scroll a screen.
EscLeave the editor. Press it again to close the menu.

Cmd works instead of Ctrl on macOS. If you'd rather use a real editor, edit the file in config/zimandlc/scripts and press Reload. Delete asks you to press it twice, and then the file is gone.

Callbacks

Define any of these as global functions. Leave out the ones you don't need.

FunctionWhen it runs
on_load()Once, right after the script starts.
on_tick()Every game tick, 20 times a second, while you're in a world.
on_render()Every frame. Only here can you draw with render. It doesn't run while the client menu is open.
on_key(key)When a key is pressed in game, not in menus. key is a GLFW key code; compare it with keys.
on_chat(text)For every chat message you receive. Return true to hide it.
on_unload()When the script is stopped or restarted.
One error stops the script. If a callback throws, the error goes to the console with its line number and the script stops. Fix it and press Run again.

player

You. Every function is called with a dot: player.x(). Calling these outside a world raises not in a world, so guard with client.in_game() in on_load.

FunctionReturnsNotes
x() y() z()numberPosition in blocks.
pos()x, y, zAll three at once.
yaw() pitch()numberWhere the camera looks, in degrees. Pitch 90 is straight down.
set_yaw(deg) set_pitch(deg)Turn the camera. Pitch is clamped to ±90.
look(yaw, pitch)Server-only look for this tick. Others see it, your camera doesn't move. Call it from on_tick every tick you want it. Ignored while an aura is aiming.
vel()x, y, zVelocity in blocks per tick.
set_vel(x, y, z)Set the velocity.
speed()numberHorizontal speed in blocks per second.
jump()Jump, if you're on the ground.
health() max_health() food()numberHealth is in half-hearts, so 20 is full.
on_ground() sneaking() sprinting() in_water()boolean
set_sprint(on)
fall_distance()numberBlocks fallen since you last stood on something.
name()string
held()stringItem id in the main hand, like minecraft:diamond_sword.
slot() set_slot(n)1–9Hotbar slot.

world

FunctionReturnsNotes
block(x, y, z)stringBlock id at a position, like minecraft:air.
players()tableEvery other player you can see: a list of {name, x, y, z, health, distance}.
time()0–23999Time of day in ticks. 6000 is noon.

client

FunctionReturnsNotes
chat(text)Show a message in your chat only.
say(text)Send a chat message. Text starting with / runs as a command.
in_game()booleanWhether you're in a world.
menu_open()booleanWhether any screen is open: chat, inventory, pause menu.
server()string or nilServer address, or nil in singleplayer.
screen()w, hWindow size in pixels, the same units render uses.
fps()number
ms()numberMilliseconds since 1970. Use it for timers.
key_down(key)booleanWhether a key is held right now.

modules

Control any client module by the name shown in the menu, like "AttackAura" or "AntiAim". Setting names are also as shown, and the case doesn't matter.

FunctionReturnsNotes
list()tableAll module names.
is_on(name)boolean
set(name, on)Turn a module on or off.
toggle(name)booleanFlip it and get the new state.
settings(name)tableThe module's setting names.
get(name, setting)valueA boolean, number or string.
set_value(name, setting, value)Checkboxes take a boolean and sliders a number, clamped to their range. Mode lists take one of their mode names.
modules.set_value("AntiAim", "Yaw", "Jitter")
modules.set_value("AntiAim", "Jitter Range", 120)

render

Draw on the HUD from on_render. Coordinates are window pixels from the top-left. Colors are numbers made with render.rgba. All rectangles are drawn first and all text on top of them.

FunctionReturnsNotes
rgba(r, g, b, a)colorEach value is 0–255. Alpha defaults to 255.
rect(x, y, w, h, color, radius)A filled rectangle. Radius rounds the corners and defaults to 0.
text(str, x, y, color, size)Text with its top-left at x, y. Size defaults to 14, and color to white.
text_width(str, size)numberUse it to center or right-align text.
text_height(size)number

theme

The client's current theme colors, ready to pass to render. Every color function takes an optional alpha from 0 to 255 (default 255), so HUDs can match whatever theme the user picked.

FunctionReturns
accent(a) background(a) surface(a)color: main accent, base background, raised surface
text(a) text_secondary(a) muted(a) on_accent(a)color: text shades that stay readable on the theme; on_accent is for text drawn over the accent
name()string: theme name, like "Dark Mint"
is_light()boolean
function on_render()
  local w, h = client.screen()
  render.rect(w / 2 - 40, h / 2 + 20, 80, 20, theme.background(200), 6)
  render.text(string.format("%.1f", player.speed()), w / 2 - 14, h / 2 + 23, theme.accent())
end

keys

Key codes to compare with on_key and client.key_down: keys.A to keys.Z, keys.N0 to keys.N9, keys.F1 to keys.F12, plus SPACE, ENTER, TAB, BACKSPACE, ESCAPE, LEFT_SHIFT, LEFT_CONTROL, LEFT_ALT, UP, DOWN, LEFT and RIGHT. Any other key works by its GLFW code.

Limits

  • Each callback gets 50 ms. A loop that runs longer is stopped with took longer than 50 ms (endless loop?) so the game doesn't freeze.
  • Scripts can't touch files or Java: io, os, require, dofile, debug and luajava aren't there. string, table, math, bit32 and coroutine are.
  • Every script has its own globals. Two scripts can't see each other's variables.
  • Everything runs on the game thread, so slow scripts cost frames.
Only run scripts you've read. A script can't reach your files, but it can send chat messages and commands as you, and turn modules on and off.

Lua Unsafe

By default scripts cannot touch files or other scripts. The Lua Unsafe module (Misc tab, off by default) lifts that while it is on: scripts started in that state get require, dofile, loadfile, io and os. require("name") loads name.lua from the scripts folder, so scripts can share helper files. debug and luajava stay unavailable, and the 50 ms limit still applies.

Unsafe scripts can read and write any file you can and run programs, so only enable it for scripts you have read. Turning the module off stops every script that was started in unsafe mode. Clawd never starts a script that uses these functions on its own.

Examples

Coordinates in the corner

function on_render()
  local x, y, z = player.pos()
  local line = string.format("%d  %d  %d", math.floor(x), math.floor(y), math.floor(z))
  local w, h = client.screen()
  render.text(line, w - render.text_width(line) - 16, h - 30)
end

Hide chat spam

local banned = { "discord.gg", "cheap coins" }

function on_chat(text)
  for _, word in ipairs(banned) do
    if text:lower():find(word, 1, true) then return true end
  end
end

Your own anti-aim

-- a slow helicopter that nods up and down
local t = 0

function on_tick()
  t = t + 1
  player.look(t * 12, math.sin(t / 4) * 90)
end

Low health warning

local warned = false

function on_tick()
  local low = player.health() < 8
  if low and not warned then client.chat("low health, back off") end
  warned = low
end

function on_render()
  if warned then
    local w, h = client.screen()
    render.rect(0, 0, w, h, render.rgba(255, 0, 0, 40))
  end
end

CS movement modules

Source engine movement and CS anti-aim, rebuilt for Minecraft for the fun of it. Each one is a normal module: bind it, favorite it, script it.

AntiAim

Other players see you look somewhere silly while your own camera stays put. It pauses while an aura is aiming and, by default, while you click.

Yaw
Backwards, Spin, Jitter (flips left and right every tick), Sideways, Random, or Off.
Spin Speed
Degrees per tick for Spin.
Jitter Range
How far Jitter and Random swing.
Pitch
Down, Up, Zero, Jitter (straight up, straight down), Random, or Off.
Pause On Click
Look normal while attacking or using an item, so hits and block placing still go where you aim.

Pixelsurf

Fall against a wall and you stop falling. You glide along it and keep your speed, like surfing a pixel-wide ledge in CS.

Fall Speed
How fast you still sink while surfing. 0 holds you level.
Boost
Speed multiplier per tick while surfing.
Max Speed
Top speed Boost can reach, in blocks per tick.
Only While Sneaking
Surf only while you hold sneak.
Sound
A pling when a surf starts.

Edgebug

Land a long fall on the very edge of a block and the landing doesn't happen: no fall damage, and you slide off with your speed. Edge means the middle of your feet is over air while a corner would touch the block.

Min Fall
Fall height in blocks before an edgebug can trigger.
Any Landing
Trigger on every landing, not just edges.
Sound
A bell on each edgebug.
Chat Message
Count your edgebugs in chat.

Bhop

Land and jump on the same tick and you keep the speed you built in the air instead of losing it to ground friction.

Gain
Speed multiplier per hop.
Max Speed
Top speed Gain can reach, in blocks per tick.
Only When Moving
Skip the carry when you hold no movement key.

AutoStrafe

Air strafing like Source. Turn while holding a side key and you gain speed in the air.

Air Cap
How much speed one tick of strafing can add along your wish direction.
Max Speed
Top speed, in blocks per tick.
Auto (Follow Mouse)
Strafe toward wherever your mouse turns, no A or D needed.

StairSurf

Fall onto a stair or slab and you glide over it, keeping and boosting your speed.

Boost
Speed multiplier per tick while surfing.
Max Speed
Top speed Boost can reach, in blocks per tick.
Slabs
Surf slabs as well as stairs.

LongJump

Your jump launches you far along your view direction instead of straight up.

Speed
Horizontal launch speed.
Height
Vertical launch speed.
Only While Sprinting
Trigger only when you sprint.

JumpBug

Sneak as you land a long fall and the landing becomes a jump, with no fall damage.

Height
Jump speed after the bug.
Min Fall
Fall height in blocks before it can trigger.
Sound
A chime on each jumpbug.

TextureBug

Hold jump against a wall and you climb it, like squeezing up a bad texture seam.

Climb Speed
Upward speed while climbing.
Reset Fall Distance
Take no fall damage after climbing.
Anticheats notice this. Pixelsurf, Edgebug, Bhop, AutoStrafe, StairSurf, LongJump, JumpBug and TextureBug change your movement in ways vanilla can't, and AntiAim sends rotations no human makes. Expect kicks on servers with an anticheat.