Skip to content

Instantly share code, notes, and snippets.

@divinity76
Last active January 5, 2026 23:05
Show Gist options
  • Select an option

  • Save divinity76/17166b2fb2bd9f8967c042e4ceb75ae1 to your computer and use it in GitHub Desktop.

Select an option

Save divinity76/17166b2fb2bd9f8967c042e4ceb75ae1 to your computer and use it in GitHub Desktop.
otclient scripting cheat sheet
function getManaPercent()
return (player:getMana() / player:getMaxMana()) * 100
end
function getHealthPercent()
return (player:getHealth() / player:getMaxHealth()) * 100
end
function hasManashield()
-- return (player:getStates() & (1 << 4)) ~= 0
return player:hasState(16)
end
local function findAllItemsInContainers(itemId, subType, tier)
local found = {}
for _, container in pairs(g_game.getContainers()) do
for slot, item in ipairs(container:getItems()) do
if item:getId() == itemId and (subType == nil or item:getSubType() == subType) and
(tier == nil or (item.getTier and item:getTier() == tier)) then
table.insert(found, item)
end
end
end
return found
end
local function countItemsInContainers(itemId, subType, tier)
return #findAllItemsInContainers(itemId, subType, tier)
end
-- Finds the nearest tile around `position` (excluding the center) with no top creature.
-- Searches in concentric "circles" up to maxRadius (default 6) on the same z-level.
function findFreeTileNearPosition(position, maxRadius)
maxRadius = maxRadius or 6
local cx, cy, cz = position.x, position.y, position.z
local p = {
x = cx,
y = cy,
z = cz
}
local function try(dx, dy)
if dx == 0 and dy == 0 then
return nil
end -- skip center
p.x = cx + dx;
p.y = cy + dy
local tile = g_map.getTile(p)
if tile and not tile:getTopCreature() then
-- If you also need walkability, add: tile:isWalkable()
-- return { x = p.x, y = p.y, z = cz }
return tile
end
return nil
end
for r = 1, maxRadius do
local r2, prev2 = r * r, (r - 1) * (r - 1)
-- Helper to guard “circle” annulus without atan2.
local function in_annulus(dx, dy)
local d2 = dx * dx + dy * dy
return d2 > prev2 and d2 <= r2
end
-- Start at (r, 0) and sweep CCW around the square perimeter at Chebyshev radius r.
-- Right edge: ( r, 0 .. r ) -- up
do
local dx = r
for dy = 0, r do
if in_annulus(dx, dy) then
local hit = try(dx, dy)
if hit then
return hit
end
end
end
end
-- Top edge: ( r .. -r, r ) -- left
do
local dy = r
for dx = r, -r, -1 do
if in_annulus(dx, dy) then
local hit = try(dx, dy)
if hit then
return hit
end
end
end
end
-- Left edge: ( -r, r .. -r ) -- down
do
local dx = -r
for dy = r, -r, -1 do
if in_annulus(dx, dy) then
local hit = try(dx, dy)
if hit then
return hit
end
end
end
end
-- Bottom edge: ( -r .. r, -r ) -- right, stopping before (r,0) to avoid duplicate
do
local dy = -r
for dx = -r, r - 1 do
if in_annulus(dx, dy) then
local hit = try(dx, dy)
if hit then
return hit
end
end
end
end
end
return nil
end
macro(10000, "auto manashield", function()
if player:getMana() < 50 then
return
end
-- if hasManashield() then
-- return
-- end
say("utamo vita")
end)
macro(100, "auto exura vita", function()
if getHealthPercent() > 80 then
return
end
if player:getMana() < 100 then
return
end
if not hasManashield() then
return
end
say "exura vita"
end)
macro(200, "manarune heal", function()
if not hasManashield() and player:getMana() > 50 then
-- we need utamo vita asap
say("utamo vita")
return
end
if getManaPercent() >= 70 then
return
end
local idManaRune = 3201
local idManaruneBp = 2868
local manaruneList = findAllItemsInContainers(idManaRune, 1)
local manaruneCount = #manaruneList
local manaruneItem = manaruneList[1] or nil
if manaruneCount == 0 then
local manaruneBpItem = g_game.findPlayerItem(idManaruneBp, 1)
if manaruneBpItem then
g_game.open(manaruneBpItem, manaruneBpItem:getParentContainer())
end
return
end
local nearbyFreePos = findFreeTileNearPosition(player:getPosition(), 6)
if not nearbyFreePos then
-- need to find a nearby tile with no creature..
return
end
local targetThing = nearbyFreePos:getTopUseThing();
if not targetThing then
targetThing = nearbyFreePos:getTopThing();
if not targetThing then
return
end
end
g_game.useWith(manaruneItem, targetThing, 1)
if manaruneCount < 2 then
local manaruneBpItem = g_game.findPlayerItem(idManaruneBp, 1)
if manaruneBpItem then
g_game.open(manaruneBpItem, manaruneBpItem:getParentContainer())
end
end
end)
-- function g_game.getAttackingCreature() end
macro(500, "SD rune attack", function()
if not hasManashield() then
return
end
if getManaPercent() < 50 then
return
end
local target = g_game.getAttackingCreature()
if not target then
return
end
local idSDRune = 3155
local sdruneItem = g_game.findPlayerItem(idSDRune, 1)
if not sdruneItem then
return
end
g_game.useWith(sdruneItem, target, 1)
end)
macro(1000, "Auto UE", function()
if not hasManashield() then
say("utamo vita")
return
end
if getManaPercent() < 30 then
return
end
local target = g_game.getAttackingCreature()
if not target then
return
end
say("exevo gran mas mort")
end)
local function stackOnce()
local containers = g_game.getContainers()
local toStack = {}
for _, container in pairs(containers) do
for slot, item in ipairs(container:getItems()) do
if item:isStackable() and item:getCount() ~= 100 then
local targetPos = toStack[item:getId()]
if targetPos then
g_game.move(item, targetPos, item:getCount())
return true -- moved something
end
toStack[item:getId()] = container:getSlotPosition(slot - 1)
end
end
end
return false -- nothing to stack
end
macro(5000, "Auto stacking items", function(m)
if stackOnce() then
m.timeout = 1000
else
m.timeout = 5000 -- idle when done
end
end)
local NORMAL_DELAY = 5000
local FAST_DELAY = 800
local VERY_FAST_DELAY = 250
macro(VERY_FAST_DELAY, "Sell", function(m)
-- First pass: stack everything
if stackOnce() then
return
end
-- Nothing left to stack: say the sell lines
say('exura "hi')
say('exura "sell all golden boots')
say('exura "sell all golden legs')
say('exura "sell all magic longsword')
say('exura "sell all demon shield')
say('exura "sell all great shield')
say('exura "sell all mpa')
say('exura "sell all dsm')
say('exura "sell all royal helmet')
m.setOff()
end)
macro(3600000, "Auto task maxpoints", function()
say("!task maxpoints")
end)
macro(500, "turn itself off", function(m)
m.setOff()
end)

how to open main container:

local containers = getContainers()
if not containers[0] and getBack() then
  g_game.open(getBack())
end

how to get the target bot's "Danger" count in Lua:

TargetBot.Danger() -- returns int

how to move an item to under my feet:

interestingItem=findItem(1337);
g_game.move(interestingItem, player:getPosition(), 1)

how to move an item to a container:

bp0=getContainer(0);
interestingItem=findItem(1337);
g_game.move(interestingItem, bp0:getSlotPosition(0), 1)

how to open container in current window, rather than a new window:

g_game.open(container, container:getParentContainer())

how to send a custom packet, like "\x01\x00\x65":

  local protocol = g_game.getProtocolGame()
  local msg = OutputMessage.create()
  msg:addU8(1)
  msg:addU8(0)
  msg:addU8(113)
  protocol:send(msg)

how to schedule something in the future:

schedule(1000, function()
-- this will execute in 1000 milliseconds
end)

misc functions:

function getManaPercent()
  return (player:getMana() / player:getMaxMana()) *100
end

function getHealthPercent()
  return (player:getHealth() / player:getMaxHealth()) *100
end

function hasManashield()
    -- return (player:getStates() & (1 << 4)) ~= 0
    return player:hasState(PlayerStates.ManaShield)
end
macro(3000, "manarune heal", function()
  if getManaPercent() >= 70 then
    say("more than 70%")
    return
  end
    local idManaRune = 3201
    local manaruneItem = g_game.findPlayerItem(idManaRune, 1)
    if not manaruneItem then
      say("no manarune")
      return
    end
    say("using manarune")
    g_game.useWith(manaruneItem, g_game.getLocalPlayer(), 1)
end)



macro(100, "manarune heal in front of you", function()
  if getManaPercent() >= 70 then
    return
  end
    local idManaRune = 3201
    local manaruneItem = g_game.findPlayerItem(idManaRune, 1)
    if not manaruneItem then
      return
    end
    local pos = player:getPosition()
    pos.x = pos.x + 2
    local tile = g_map.getTile(pos)
    if not tile then
      return
    end
    local targetThing = tile:getTopUseThing()
    if not targetThing then
        targething = tile:getTopThing()
        if not targetThing then
            return
        end
    end
    g_game.useWith(manaruneItem, targetThing, 1)
end)

converting 100gp to 1plat, 100plat to 1 cc, 100 cc to something:

for i, container in pairs(getContainers()) do
    for j, item in ipairs(container:getItems()) do
      if item:getCount() == 100 and (item:getId() == 3031 or item:getId() == 3035 or item:getId() == 3043) then
        g_game.use(item)
        delay(100)
        return "retry"
      end
    end
  end

turn off cavebot:

CaveBot.setOn(false)

Stacking itmes:

macro(5000, "Auto stacking items", function()
    local containers = g_game.getContainers()
    for i, container in pairs(containers) do
        local toStack = {}
        for j, item in ipairs(container:getItems()) do
            if item:isStackable() and item:getCount() ~= 100 then
                local otherItem = toStack[item:getId()]
                if otherItem then
                    g_game.move(item, otherItem, item:getCount())
                end
                toStack[item:getId()] = container:getSlotPosition(j - 1)
            end
        end
    end
end)
@divinity76
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment