Documentation › Lua
Scripting
When the tabs are not enough, write a script. DrenoxBot runs Lua scripts with its own API: events, timers, HUDs on the game screen and windows of their own. Scripts written for ZeroBot run too, without changes.
Where scripts live#
Each script is a .lua file in the scripts/ folder, next to bot.json. Sounds used by scripts go in scripts/sounds/. Inside a script, Engine.getScriptsDirectory() returns the folder's path.
The Scripting tab manages everything:
| Control | What it does |
|---|---|
| Active | Turns the script on or off. Scripts left on come back by themselves when the bot starts |
| New | Creates scripts/<name>.lua and opens it in the editor |
| Edit (or double click) | Opens the editor, with Save and Save & enable |
| Import DrenoxBot / ZeroBot | Copies a .lua, or every .lua of a folder (subfolders kept), into scripts/. A different script with the same name is not overwritten |
| Reload all | Restarts every enabled script |
| Delete | Stops the script and deletes the file |
The Status column shows whether the script is running or the error that stopped it.
How a script runs#
- Each script runs on its own thread, without blocking the bot or the other scripts.
- The top-level code runs once. After that the script stays alive, receiving events and running timers.
wait(ms)pauses the script, but events and timers keep arriving while it waits. Scripts in thewhile true do ... wait(100) endstyle work.- An error inside an event or timer is reported and the script keeps running.
print()goes to the Console tab as[name] text. Errors show as[lua:name] ....
Other ways to run Lua#
- Console:
lua <code>runs a snippet right away, for examplelua print(Player.getHealth()). Thescriptcommand also manages files:script list,script on <name>,script off <name>,script reload [name],script delete <name>andscript import <.lua or folder>. - CaveBot Script waypoint: the waypoint's code runs and the route waits until it ends (no timers or events left registered). Inside it,
CaveBot.GoTo("label")jumps to the label and ends the script.
The API#
Full reference, module by module: Function reference. The most used ones are below.
Functions live in tables, one per module. Positions are passed as separate x, y, z and returned as a {x, y, z} table. Inventory slots start at 1 (Enums.InventorySlot); container slots start at 0.
| Function | Parameters | What it does |
|---|---|---|
Player.getHealth() / getMana() | Current HP and mana (also getMaxHealth, getMaxMana, getHealthPercent, getManaPercent) | |
Player.getPosition() | Your position {x, y, z} | |
Player.getLevel() / getCapacity() | Level and free cap | |
Player.getTargetId() | Id of the attacked creature (0 = none) | |
Player.getState(state) | Enums.States.X | true if you have the state (paralyze, haste...) |
Player.isInPz() / isInCombat() | In a protection zone / in combat | |
Player.getSkills() | Table with skills, magic level and percentages | |
Game.talk(text, mode) | text, optional mode | Speaks in Default (mode 1 = say) |
Game.talkPrivate(text, name) | Sends a PM | |
Game.walk(direction) | Enums.Directions.X | Takes one step |
Game.attack(id) / Game.follow(id) | creature id | Attacks (0 stops attacking) / follows |
Game.useItem(itemId) | Uses the item like a hotkey | |
Game.useItemWithCreature(itemId, id) | Uses the item (rune, potion) on the creature | |
Game.useItemOnGround(itemId, x, y, z) | Uses the item on a tile | |
Game.getItemCount(itemId) | How many you have (bag and equipment) | |
Game.equipItem(itemId) | Equips the item | |
Map.getCreatureIds(sameFloor, onlyPlayers) | booleans | Ids of the visible creatures |
Map.goTo(x, y, z) | Walks to the position | |
Map.isTileWalkable(x, y, z) | Whether you can step there | |
Creature.new(id) | Object with getName, getHealthPercent, getPosition, getDistance, isOnScreen, getType, getSkull... | |
Container.new(index) | An open container: getName, getItems, useItem, moveItemToContainer... | |
Spells.getIdByWords(words) | The spell's id (-1 if none) | |
Spells.isInCooldown(id) | Whether the spell is on cooldown | |
Npc.buy(id, amount) / Npc.sell(id, amount) | Buys and sells in the open trade window | |
Engine.enableHealing(bool) | Turns modules on/off: also enableTargeting, enableCaveBot, enableMagicShooter, enableEquipment, enableBot and the isXEnabled ones | |
Engine.healingSwitchProfile(n) | Switches the module's profile (also Targeting, Equipment, MagicShooter) | |
CaveBot.GoTo(label) | Jumps the route to the label | |
CaveBot.pause(ms) | Pauses the route (0 resumes) | |
CaveBot.getWaypoints() | List of waypoints {x, y, z, type, data} | |
Client.showMessage(text) | Text in the middle of the screen for 3 s | |
Client.isKeyPressed(key) | key code | Whether the key is held down |
HUD.new(x, y, text or itemId) | Text or icon on the game screen: setText, setColor(r, g, b), setPos, setCallback, destroy... | |
CustomModalWindow.new(title, text) | A window with buttons: addButton, setCallback(fn(button)) | |
Timer.new(name, fn, ms) | 4th parameter false = do not start | Runs fn every ms: start, stop, isActive. destroyTimer(name) removes it |
wait(ms) | Waits without missing events | |
JSON.encode(t) / JSON.decode(s) | Converts between table and JSON text | |
Sound.play(file, default) | true = look in scripts/sounds | Plays a .wav |
More functions available
- Player:
getName,getId,getSoulPoints,getStamina,getExperience,getLevelPercent,getSpeed,getVocation,getInventorySlot(slot),getContainers,getMagicShield,getBlessingState,isPremium,getUnjustifiedData,getDusts,getTotalGoldBalance,getHuntingPoints,getPreyWildcards, party functions (inviteParty,joinParty,leaveParty,enableSharedExpParty,passLeadershipParty). - Game:
turn,talkChannel,openChannel,getChannelsHistory,getInventoryItems,useItemOnInventory,useItemFromGround,lootCorpse,autoLoot,modalWindowAnswer,requestQuestLog,requestQuestLines,writeTextWindow,stashRetrieve, hunting tasks and task board, store, daily reward, forge and imbuements. - Map:
getTiles,getThings,getThingsCount,getTopItemId,getTopCreatureId,getAllPositionsWithTopItemId,getPlayerOnScreen,moveItemToInventory,moveItemToContainer,moveItemToGround,moveCreatureToGround,useItemWithInventory,useItemWithContainer,lookAt,browseField,collectRewardChest,canWalk. - Inventory:
useItem,lookAt,moveItemToGround,moveItemToContainer,stowContainer. - CaveBot: add, insert, replace and delete waypoints,
selectWaypoint,saveFile,loadFile, sell and refill lists, lure settings, special areas and walk mode. - Client:
isConnected,logout,login,XLog,focus,flashWindow,setWindowTitle,sendHotkey,getFightMode/setFightMode,getChaseMode/setChaseMode,getVersion,getAllItems,getAllMonsters,getLootBlackWhitelist/setLootBlackWhitelist. - Engine:
loadScript,unloadScript,reloadScript,isScriptLoaded,loadConfig, alarms (setAlarm,isAlarmEnabled,allAlarmsEnable),holdTargetEnable,antiPushEnable,autoSSAEnable,autoMightRingEnable,runeMaxEnable,reconnectEnable. - Enums and
HotkeyManager.parseKeyCombination("Ctrl+F5").
Events#
Register with Game.registerEvent(Game.Events.X, function) and remove with Game.unregisterEvent. Each event, with its parameters and an example, is in Game events.
| Event | Arguments |
|---|---|
TALK | name, level, mode, x, y, z, text, channel |
TEXT_MESSAGE | table {messageType, text, channelId, position, value, ...} |
MAGIC_EFFECT | id, x, y, z |
DISTANCE_SHOOT_EFFECT | id, from x, y, z, to x, y, z |
HOTKEY_SHORTCUT_PRESS | key, modifiers (only while the client has focus) |
HUD_CLICK / HUD_DRAG | HUD id (and x, y when dragging) |
MODAL_WINDOW | table with id, title, message, buttons, choices |
CUSTOM_MODAL_WINDOW_BUTTON_CLICK | window id, button |
LABEL | index and text of the label waypoint (the CaveBot pauses until you call CaveBot.pause(0)) |
ALARM | type (Enums.AlarmType) |
QUEST_LOG / QUEST_LINES | quest list / id and mission list |
OPEN_STASH | table with the stash |
CREATURE_HEALTH | creature id, HP % (DrenoxBot extra) |
PLAYER_DATA | HP, max HP, mana, max mana (DrenoxBot extra) |
Examples#
-- Target HP in a HUD on the screen
local hud = HUD.new(20, 60, "Target: -")
hud:setColor(35, 213, 255)
Game.registerEvent(Game.Events.CREATURE_HEALTH, function(id, hp)
if id ~= Player.getTargetId() then return end
local target = Creature.new(id)
if target:isOnScreen() then
hud:setText(target:getName() .. " " .. hp .. "%")
end
end)-- Every 5 s: low cap shows a warning and plays scripts/sounds/alarm.wav
Timer.new("cap", function()
local cap = Player.getCapacity()
if cap < 100 then
Client.showMessage("Low cap: " .. cap)
Sound.play("alarm.wav", true)
end
end, 5000)-- Ctrl+F5 turns the CaveBot on and off
local ok, mods, key = HotkeyManager.parseKeyCombination("Ctrl+F5")
Game.registerEvent(Game.Events.HOTKEY_SHORTCUT_PRESS, function(k, m)
-- bit 8 = Num Lock on: ignore it
if k == key and bit.band(m, 7) == mods then
local on = not Engine.isCaveBotEnabled()
Engine.enableCaveBot(on)
Client.showMessage("CaveBot " .. (on and "on" or "off"))
end
end)-- At label "check": under 50 mana potions, go to label "refill"
Game.registerEvent(Game.Events.LABEL, function(index, label)
if label == "check" and Game.getItemCount(268) < 50 then -- 268 = mana potion
CaveBot.GoTo("refill")
end
CaveBot.pause(0) -- the route waits until here
end)-- Logs to the Console who said your name
Game.registerEvent(Game.Events.TALK, function(name, level, mode, x, y, z, text)
if text:lower():find(Player.getName():lower(), 1, true) then
print(name .. " (" .. level .. "): " .. text)
Client.flashWindow()
end
end)Sharing and downloading scripts#
The community Downloads area has Lua scripts, cavebots and presets shared by players. From the DrenoxCommunity tab inside the game, each download has Install and Install + run, and you share your own scripts with one click. Before turning on someone else's script, read the code: it runs with your character.
Questions about a script? Post in the support forum with the code and the Console error message.
Comments
to comment.