Scripts

Scripts: teach the bot new tricks in JavaScript

Like the Lua scripts of the classic Tibia bots, but in JavaScript. Write a few lines in the Scripts tab and the bot runs them every few seconds: it reads your character and the screen, casts, uses items, attacks, walks, talks to NPCs and buys, or decides who the Target attacks and what the Loot takes.

How it works

  1. Open the bot, go to Scripts and press + New script, or start from one of the examples below.
  2. Each script runs again at the interval you choose (from 0.1 s). Turn it on with its switch, and turn the Scripts module on. While a script is on, its code is read-only: turn it off to edit it. What log() writes shows in the Console under the code (Edit).
  3. Scripts are saved in your profile: when you share, send or sell a profile, its scripts go with it, and whoever gets it can read and edit them. Scripts that come in a profile from someone else arrive off and blocked: they don’t run in any way (not on their own, not with Run now, not from a Script waypoint of the Cavebot) until you press Allow… in the Scripts module. Be careful: a malicious script can sell or drop your items, walk your character into monsters, log you out or talk for you. Read the code (Edit) and allow only scripts you understand, from people you trust.
  4. An action returns true when the bot does it and false when it can't; why() tells you why. Each script does one game action per tick: put await wait(ms) between the steps of a sequence.

Safe by design

Scripts run in a closed box inside the bot and can only use the functions on this page. They can't see the game page, your passwords or the internet, and a script stuck in a loop is stopped on its own. Every action goes through the same paths as the rest of the bot.

Your first script

Heal under 60% life, put the magic shield on when a player shows up, and write what is happening in the script's console:

if (player.hpPercent < 60) cast("exura vita")
if (players().length > 0 && !player.magicShield) cast("utamo vita")
log("HP", player.hp, "monsters", monsters().length)

Ready examples

They are in the bot too: Scripts → + From an example.

Train magic level (utevo lux)

runs every 2 s

if (player.manaPercent >= 95 && !player.inPz && monsters().length === 0) {
  cast("utevo lux")
}

Magic shield when a PK shows up

runs every 0.5 s

const pk = players().find((p) => p.skull === "white" || p.skull === "red" || p.skull === "black")
if (pk && !player.magicShield) {
  cast("utamo vita")
}

Heal a friend with exura sio

runs every 0.5 s

const friend = findCreature("Friend Name")
if (friend && friend.hpPercent < 60 && distance(friend) <= 7) {
  cast('exura sio "' + friend.name + '"')
}

Alarm on low capacity

runs every 5 s

if (player.cap !== null && player.cap < 50) {
  alarm()
  log("Capacity:", player.cap)
}

Hit the weakest monster first

runs every 0.5 s

const weakest = monsters()
  .filter((m) => m.distance <= 6 && m.hpPercent !== null)
  .sort((a, b) => a.hpPercent - b.hpPercent)[0]
if (weakest && (!target || target.id !== weakest.id)) {
  attack(weakest)
}

Haste when no monster is around

runs every 1 s

if (!player.hasted && !player.inPz && monsters().length === 0) {
  cast("utani hur")
}

Pause the Cavebot on few mana fluids

runs every 2 s

const VIAL = 2874
const MANA = 7
if (itemCount(VIAL, MANA) < 20) {
  pause("cavebot")
  warn("Few mana fluids:", itemCount(VIAL, MANA))
} else {
  resume("cavebot")
}

Talk to an NPC (step by step)

runs every 60 s

say("hi")
await wait(2000)
say("trade")
await wait(1500)
log("Trade window should be open now")

Target: skip some, weak ones first

runs every 60 s

const NEVER = ["Rabbit", "Deer"]
onAttack((monster) => {
  if (NEVER.includes(monster.name)) return false
  if (monster.hpPercent !== null && monster.hpPercent < 30) return 10
  if (monster.attackingMe) return 5
})

Loot: skip cheap items, always take some

runs every 60 s

const ALWAYS = ["dragon ham", "platinum coin"]
onLoot((item) => {
  if (ALWAYS.includes(item.name)) return true
  if (item.value !== null && item.value < 50) return false
})

Go refill on low supplies

runs every 60 s

const MANA_FLUIDS = itemCount(2874, 7)
if (player.cap < 100 || MANA_FLUIDS < 50) {
  log("Going to refill. Cap:", player.cap, "mana fluids:", MANA_FLUIDS)
  gotoLabel("Refill")
}

Buy mana fluids up to 100

runs every 60 s

const WANT = 100
const have = itemCount(2874, 7)
if (have >= WANT) return
say("hi")
await wait(1500)
say("trade")
if (!(await waitUntil(() => trade, 3000))) {
  warn("The shop did not open")
  return
}
if (!(await buy(2874, WANT - have, 7))) warn("Could not buy:", why())
closeTrade()

Sell loot to the NPC

runs every 60 s

const SELL = ["plate armor", "battle shield", "dwarven shield"]
say("hi")
await wait(1500)
say("trade")
if (!(await waitUntil(() => trade, 3000))) {
  warn("The shop did not open")
  return
}
for (const name of SELL) {
  const item = findItem(name)
  if (!item) continue
  if (!(await sell(item.id, itemCount(item.id)))) warn("Could not sell", name + ":", why())
}
closeTrade()

Stop hunting, log out after 2 h

runs every 10 s

const HOURS = 2
storage.start = storage.start || now
if (now - storage.start >= HOURS * 3600000) {
  pause("cavebot")
  pause("target")
  if (!storage.warned) {
    warn("Hunt time is over")
    alarm()
    storage.warned = true
  }
  if (!player.inBattle && !player.pzLocked) logout()
}

Alarm on a private message

runs every 1 s

for (const m of messages()) {
  if (m.type === "private") {
    alarm()
    warn("Private message from", m.from)
  }
}

Pause the Cavebot near players

runs every 1 s

const near = players().filter((p) => p.distance <= 4 && !p.party)
if (near.length > 0) {
  pause("cavebot")
} else {
  resume("cavebot")
}

Kills per hour

runs every 60 s

storage.start = storage.start || now
storage.kills = storage.kills || 0
for (const m of messages()) {
  if (m.type === "loot") storage.kills += 1
}
const hours = (now - storage.start) / 3600000
log("Kills:", storage.kills, "per hour:", hours > 0 ? Math.round(storage.kills / hours) : 0)

Area spell on 3 monsters around

runs every 0.5 s

const SPELL = "exori"
const close = monsters().filter((m) => m.distance <= 1)
if (close.length >= 3 && canCast(SPELL)) {
  cast(SPELL)
}