• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

OTClientV8 BOT

Status
Not open for further replies.

kondra

Excellent OT User
Joined
Apr 9, 2018
Messages
192
Solutions
3
Reaction score
692
Location
/dev/null
GitHub
OTCv8
Hey,
I'm creating the most powerful bot tibia community has even seen. Personally, I don't like bots, but many players and server owners asked me for it, so there it is.

OTClientV8 bot is included in OTClientV8 project, but has separate github repository with documentation and examples.
Github: OTCv8/otclientv8_bot (https://github.com/OTCv8/otclientv8_bot)
It should be possible to port this bot to classic otclient, but I don't have time for that.

This bot allows you to create whatever you want with lua and otclient otml language. It gives you access to all otclient lua functions and has a lot of functions and tools to make development easier. I don't plan to create an advanced UI for this bot, you can do it yourself by using setupUI function and then share it =)

If you want to contribure, add more functions, some scripts or even UI join otclientv8 discord channel and contact with me - Join the OTClientV8 Discord Server! (https://discord.gg/feySup6) . Or just make a github pull request.

Main bot functions:
Code:
-- better description will be added later
info(text)
warn(text)
error(text)

setupUI(text)
setupUI(text, parent)
addLabel(id, text)
addSwitch(id, text, onClickCallback)
addButton(id, text, onClickCallback)
addSeparator(id)

macro(timeout, callback)
macro(timeout, name, callback)
macro(timeout, name, hotkey, callback) -- hotkey is used to turn on/off macro

hotkey(keys, callback)
hotkey(keys, name, callback)

singlehotkey(keys, callback) -- works like hotkey, but will be executed only once after key press
singlehotkey(keys, name, callback)

schedule(timeout, callback)

onKeyDown(callback) -- callback = function(keys)
onKeyPress(callback) -- callback = function(keys)
onKeyUp(callback) -- callback = function(keys)
onTalk(callback) -- callback = function(name, level, mode, text, channelId, pos)
onAddThing(callback) -- callback = function(tile, thing)
onRemoveThing(callback) -- callback = function(tile, thing)

listen(name, callback) -- callback = function(text, channelId, pos)

delay(duration) -- can be only used inside callback function, blocks execution of current macro/hotkey/callback for x milliseconds
For more functions tools and shortcuts please visit bot github repo, don't want to make this post too long.

Example bot script:

Code:
--#Example config

--#main
local widget = setupUI([[
Panel
  id: redPanel
  background: red
  margin-top: 10
  margin-bottom: 10
  height: 100
 
  Label
    anchors.fill: parent
    text: custom ui, otml based
    text-align: center
]])

--#macros
macro(5000, "macro send link", "f5", function()
  g_game.talk("macro test - https://github.com/OTCv8/otclient_bot")
  g_game.talk("bot is hiding 50% of effects as example, say exevo gran mas vis")
end)

macro(1000, "flag tiles", function()
  tile:setText("Hello =)", "red")
end)

macro(25, "auto healing", function()
  if hppercent() < 80 then
    say("exura")
    delay(1000) -- not calling this macro for next 1s
  end
end)

addSeparator("spe0")

--#hotkeys
hotkey('y', 'test hotkey', function() g_game.talk('hotkey elo') end)
singlehotkey('x', 'single hotkey', function() g_game.talk('single hotkey') end)

singlehotkey('=', "Zoom in map", function () zoomIn() end)
singlehotkey('-', "Zoom out map", function () zoomOut() end)

--#callbacks
onAddThing(function(tile, thing)
  if thing:isItem() and thing:getId() == 2129 then
    local pos = tile:getPosition().x .. "," .. tile:getPosition().y .. "," .. tile:getPosition().z
    if not storage[pos] or storage[pos] < now then
      storage[pos] = now + 20000
    end
    tile:setTimer(storage[pos] - now)
  end
end)

-- hide 50% of effects
onAddThing(function(tile, thing)
  if thing:isEffect() and math.random(1, 2) == 1 then
    thing:hide()
  end
end)

listen(player:getName(), function(text)
  info("you said: " .. text)
end)

--#other
addLabel("label1", "Test label 1")
addSeparator("sep1")
addLabel("label2", "Test label 2")

storage.clicks = 0
addButton("button1", "Click me", function()
  storage.clicks = storage.clicks + 1
  ui.button1:setText("Clicks: " .. storage.clicks)
end)

HTTP.getJSON("https://api.ipify.org/?format=json", function(data, err)
    if err then
        warn("Whoops! Error occured: " .. err)
        return
    end
    info("HTTP: My IP is: " .. tostring(data['ip']))
end)

For more examples visit bot github repository.

An example, why this bot will be much more powerful than others is data synchronization between players. In this example, two players are able to share information when magic wall is going to disappear.

The script I used:
Code:
-- sync mwall
-- tested on 1099
local secondPlayer = "Player1"
if name() == "Player1" then
  secondPlayer = "Player2"
end
info("Syncing mwalls with player: " .. secondPlayer)

onAddThing(function(tile, thing)
  if thing:isItem() and thing:getId() == 2129 then
    local pos = tile:getPosition().x .. "," .. tile:getPosition().y .. "," .. tile:getPosition().z
    if not storage[pos] or storage[pos] < now then
      storage[pos] = now + 20000
      talkPrivate(5, secondPlayer, encode({type = "mwall", pos = pos, ping = ping()}))
    end
    tile:setTimer(storage[pos] - now)
  end
end)

listen(secondPlayer, function(text)
  local data = decode(text)
  if data and data.type == "mwall" then
    storage[data.pos] = now + 20000 - data.ping - ping()
  end
end)

If you want new functions or functionality - let me know in this thread ;)
 
Last edited:
I got some requestes to show more advanced UI example - so here it is.
1572204476002.png

You can replace item by dragging it from ground/your eq to item in bot window.
An example:

Script:
Code:
-- UI & healing
info("Tested on 10.99")

--#main
local healthPanel = setupUI([[
Panel
  id: healingPanel
  height: 150
  margin-top: 3

  Label
    anchors.top: parent.top
    anchors.left: parent.left
    anchors.right: parent.right
    text: Use item if
    text-align: center

  BotItem
    id: item1
    anchors.left: parent.left
    anchors.top: prev.bottom

  Label
    id: label1
    anchors.left: prev.right
    anchors.right: parent.right
    anchors.top: prev.top
    margin: 0 5 0 5
    text-align: center

  HorizontalScrollBar
    id: scroll1
    anchors.left: prev.left
    anchors.right: prev.right
    anchors.top: prev.bottom
    margin-top: 5
    minimum: 0
    maximum: 100
    step: 1

  BotItem
    id: item2
    anchors.left: parent.left
    anchors.top: item1.bottom
    margin-top: 3

  Label
    id: label2
    anchors.left: prev.right
    anchors.right: parent.right
    anchors.top: prev.top
    margin: 0 5 0 5
    text-align: center

  HorizontalScrollBar
    id: scroll2
    anchors.left: label2.left
    anchors.right: label2.horizontalCenter
    anchors.top: label2.bottom
    margin-top: 5
    minimum: 0
    maximum: 100
    step: 1

  HorizontalScrollBar
    id: scroll3
    anchors.left: label2.horizontalCenter
    anchors.right: label2.right
    anchors.top: label2.bottom
    margin-top: 5
    minimum: 0
    maximum: 100
    step: 1

  Label
    anchors.top: item2.bottom
    anchors.left: parent.left
    anchors.right: parent.right
    margin-top: 3
    text: Drag item to change it
    text-align: center

  HorizontalSeparator
    anchors.top: prev.bottom
    anchors.left: parent.left
    anchors.right: parent.right
    margin-top: 3
]])

healthPanel.item1:setItemId(storage.healItem1 or 266)
healthPanel.item1.onItemChange = function(widget, item)
  storage.healItem1 = item:getId()
  widget:setItemId(storage.healItem1)
end

healthPanel.item2:setItemId(storage.healItem2 or 268)
healthPanel.item2.onItemChange = function(widget, item)
  storage.healItem2 = item:getId()
  widget:setItemId(storage.healItem2)
end

healthPanel.scroll1.onValueChange = function(scroll, value)
  storage.healPercent1 = value
  healthPanel.label1:setText("0% <= hp <= " .. storage.healPercent1 .. "%")
end
healthPanel.scroll1:setValue(storage.healPercent1 or 50)

healthPanel.scroll2.onValueChange = function(scroll, value)
  storage.healPercent2 = value
  healthPanel.label2:setText("" .. storage.healPercent2 .. "% <= mana <= " .. storage.healPercent3 .. "%")
end
healthPanel.scroll3.onValueChange = function(scroll, value)
  storage.healPercent3 = value
  healthPanel.label2:setText("" .. storage.healPercent2 .. "% <= mana <= " .. storage.healPercent3 .. "%")
end
healthPanel.scroll2:setValue(storage.healPercent2 or 40)
healthPanel.scroll3:setValue(storage.healPercent3 or 60)

macro(25, function()
  if not storage.healItem1 then
    return
  end
  if healthPanel.scroll1:getValue() >= hppercent() then
    useWith(storage.healItem1, player)  
    delay(500)
  end
end)
macro(25, function()
  if not storage.healItem2 then
    return
  end
  if storage.healPercent2 <= manapercent() and manapercent() <= storage.healPercent3 then
    useWith(storage.healItem2, player)  
    delay(500)
  end
end)

--#macros

--#hotkeys

--#callbacks

--#other

To make it work you need to get last OTCv8 version because I added BotItem in last update.

@Syntax - not planned
 
I have one more good example for you, I entered karamy-war server for few hours and created something similar to magebomb. Was using 6 otclients at once and trying to kill some players. It wasn't very effective, but it took only ~2h to make this lua bot script and results are not bad. Hope it will inspire some of you :p


Code:
-- KaramyWar bot

local leaderName = "Kondra"
local isLeader = (name() == leaderName)
storage.wait = 0
storage.startattack = 0
storage.friends = {}
storage.friendIndex = 1
storage.target = ""

-- set same outfit, will be used to detect friends
if isLeader then
  -- randomize outfit for leader
  local outfit = player:getOutfit()
  outfit.head = math.random(0, 255)
  outfit.body = math.random(0, 255)
  changeOutfit(outfit)
else
  macro(1000, function()
    local leader = getPlayerByName(leaderName)
    if leader then
      local outfit = player:getOutfit()
      local leaderOutfit = leader:getOutfit()     
      if leaderOutfit.head ~= outfit.head or leaderOutfit.body ~= outfit.body then
        outfit.head = leaderOutfit.head
        outfit.body = leaderOutfit.body
        changeOutfit(outfit)
      end
    end
  end)
end

-- update friends, based on same outfit colors
macro(1000, function()
  storage.friends = {}
  local outfit = player:getOutfit()
  for i, spec in ipairs(getSpectators()) do
    if spec:isPlayer() then
      local specOutfit = spec:getOutfit()
      if specOutfit.head == outfit.head and specOutfit.body == outfit.body then
        table.insert(storage.friends, spec:getName())
      end
    end
  end
  table.sort(storage.friends)
  for i, friend in ipairs(storage.friends) do
    if friend == name() then
      storage.friendIndex = i
      break
    end
  end
end)


function magicWallAttack(target)
  local tpos = target:getPosition()
  local offsets = {{-1,0},{0,-1},{0,1},{1,0},{-1,1},{-1,-1},{1,-1},{1,1}}   
  for i=1,10 do
    local offset = offsets[math.random(1,#offsets)]
    if i == 1 then
      offset = offsets[storage.friendIndex]
    end
    local pos = {x=tpos.x - offset[1], y=tpos.y - offset[2], z=tpos.z}
    local tile = g_map.getTile(pos)   
    if tile and tile:isWalkable(false) then -- if can throw magic wall
      info(storage.friendIndex .. " " .. pos.x .. " " .. pos.y)
      usewith(3156, tile:getGround()) -- use wild growth, magic wall is 3180
      return true
    end
  end 
  info("no tiles")
  return false
end

listen(leaderName, function(text)
  local data = decode(text)
  if data and data.say then
    say(data.say)
  end
  if data and data.t ~= nil then   
    storage.target = data.t
    -- attack with paralyze first, ever character every 1s
    info("wait " .. storage.target)
    storage.wait = now + 100
    storage.startattack = now + 4000   
    --schedule(1 + (storage.friendIndex - 1) * 1000, function()
    --  local target = getPlayerByName(storage.target)
    --  if not target then
    --    return
    --  end
    --  usewith(3165, target) -- paralyze
    --end)
  end
end)

if isLeader then
    storage.attacking = ""
    macro(25, function()
        local target = g_game.getAttackingCreature()
        if not target then
          if #storage.attacking > 0 then
            say(encode({t=""}))
          end
          storage.attacking = ""
          return
        end
        if target:getName() ~= storage.attacking  then
          storage.attacking = target:getName()
          say(encode({t=target:getName(), info="I'm testing otclientv8 bot - https://otland.net/threads/otclientv8-bot.266958 - i will post there my current script, in 1-2h"}))
          storage.wait = now + 500
        end
    end)
end

macro(25, function()
  local target = getPlayerByName(storage.target)
  if not target then
    return
  end
  if storage.wait > now then
    return
  end
  if now > storage.startattack then
    usewith(3155, target) -- sd
    delay(1000)
    return
  end   
  if magicWallAttack(target) then
    delay(250)
    return
  end 
end)

if not isLeader then
  macro(300, "go to leader/target", function()
   local target = getPlayerByName(storage.target)
   local leader = getPlayerByName(leaderName)
   if not leader then
    storage.target = ""
   end
   if target then
     autoWalk(target:getPosition())
     return
   end
   if leader then
    autoWalk(leader:getPosition())
   end
  end) 
end

macro(25, function()
  if manapercent() < 50 then
      usewith(238, player)
      delay(500)
  end
end)

macro(25, function()
  if hppercent() < 80 then
      say("exura gran")
      delay(1000)
  end
end)

macro(20000, function()
  say("utamo vita")
end)

-- magic wall timer
onAddThing(function(tile, thing)
  if thing:isItem() and (thing:getId() == 2129 or thing:getId() == 2130) then
    local pos = tile:getPosition().x .. "," .. tile:getPosition().y .. "," .. tile:getPosition().z
    if not storage[pos] or storage[pos] < now then
      if thing:getId() == 2129 then
        storage[pos] = now + 20000
      else
        storage[pos] = now + 45000     
      end
    end
    tile:setTimer(storage[pos] - now)
  end
end)
 
Last edited:
finally...
honestly otclient isn't used cause tibia client have better bots
 
DASH and auto-equip things would be very usefull aswell.
 
Version 0.999 of otclientv8 with new bot has been released. It support a lot of new functions and new ui elements - like tabs, item selector, text editor.

1572497504505.png

List of all functions is available here - OTCv8/otclientv8 (https://github.com/OTCv8/otclientv8/tree/master/modules/game_bot/functions)
There are also some ready to use ui elements - OTCv8/otclientv8 (https://github.com/OTCv8/otclientv8/tree/master/modules/game_bot/panels)

Currently example script looks like this:
Code:
--Version 0.999

--#main

Panels.Haste()
Panels.ManaShield()
Panels.Health()
Panels.HealthItem()
Panels.ManaItem()
Panels.ManaItem()
Panels.AntiParalyze()

local tab2 = addTab("Another Tab")
addButton("button1", "test button on 2nd tab", nil, tab2)

local tab3 = addTab("3th tab")
addLabel("label1", "Label on 3th tab", tab3)
Panels.Turning(tab3)

--#macros

local helloLabel = addLabel("helloLabel", "", tab2)

macro(1000, "example macro (time)", nil, function()
  helloLabel:setText("Time from start: " .. now)
end, tab2)
--#hotkeys

hotkey("f5", "example hotkey", function()
  info("Wow, you clicked f5 hotkey")
end)

singlehotkey("f6", "example hotkey2", function()
  info("Wow, you clicked f6 singlehotkey")
end)
--#callbacks

local positionLabel = addLabel("positionLabel", "")
onPlayerPositionChange(function()
  positionLabel:setText("Pos: " .. posx() .. "," .. posy() .. "," .. posz())
end)
--#other
 
This bot doesn't have enough options/functions in compare to Elfbot | Magebot | Xenobot | Windbot and other bots like Blackd Proxy.
The fact is that there is not many players using this client is because it doesn't have a decent bot.
So if you wanna spread it faster and grow more users I would suggest starting with bot improvements, Everyone cheats no matter what they say about manual playing and hands only etc..
 
@M0ustafa otclient + this bot already provides better functions and features than any bot atleast in pvp, you just need to code stuff on your own till people start using it and start sharing scripts
i guess cavebot is only really major thing missing for pve
 
Finally something like that for my dear OTC
Would be possible to run OTCv8 + this BOT on Debian or Ubuntu | iOS or Android?
 
Finally something like that for my dear OTC
Would be possible to run OTCv8 + this BOT on Debian or Ubuntu | iOS or Android?

Yeah, everything is possible, but I don't have time for that, so currently - no.
 
Ok, waypoints are finished. There's one bug with function on this video, will be fixed in next update

Please test them and let me know if works fine. If you want login on my test server you can use this client: http://************/files/otclient.zip

My waypoints:
Code:
name:Example
goto:95,117,7
goto:101,114,7
use:102,114,6
goto:101,115,6
use:100,116,5
goto:101,115,5
goto:100,116,4
goto:102,114,5
goto:97,113,6
goto:88,111,6
goto:80,108,6
goto:80,97,6
goto:75,95,6
goto:73,95,7
say:lol
goto:75,95,7
goto:82,91,6
goto:89,92,6
goto:91,89,7
goto:91,80,7
goto:82,79,7
goto:73,82,7
goto:67,77,7
goto:65,77,7
goto:68,82,8
usewith:3003,68,82,9
goto:69,82,9
usewith:3003,65,77,8
goto:66,78,8
goto:71,82,7
goto:80,80,7
goto:89,78,7
goto:96,78,7
goto:104,81,7
goto:108,81,7
say:yeah
wait:1000
say:/town 1
 
Last edited:
Ok, waypoints are finished. There's one bug with function on this video, will be fixed in next update

Please test them and let me know if works fine. If you want login on my test server you can use this client: http://************/files/otclient.zip

My waypoints:
Code:
in your video u mistake a code in this part:
[CODE]setOutfit(outfit)
must be
Code:
player:setOutfit(outfit)

sensational, I never imagined that it would be possible to "cavebot" by otclient
 
Code:
in your video u mistake a code in this part:
[CODE]setOutfit(outfit)
must be
Code:
player:setOutfit(outfit)

sensational, I never imagined that it would be possible to "cavebot" by otclient

xd, no, it's not that kind of bug. It was bug in config parsing, didn't recognize : correctly.
 
Ok, waypoints are finished. There's one bug with function on this video, will be fixed in next update

Please test them and let me know if works fine. If you want login on my test server you can use this client: http://************/files/otclient.zip

My waypoints:
Code:
name:Example
goto:95,117,7
goto:101,114,7
use:102,114,6
goto:101,115,6
use:100,116,5
goto:101,115,5
goto:100,116,4
goto:102,114,5
goto:97,113,6
goto:88,111,6
goto:80,108,6
goto:80,97,6
goto:75,95,6
goto:73,95,7
say:lol
goto:75,95,7
goto:82,91,6
goto:89,92,6
goto:91,89,7
goto:91,80,7
goto:82,79,7
goto:73,82,7
goto:67,77,7
goto:65,77,7
goto:68,82,8
usewith:3003,68,82,9
goto:69,82,9
usewith:3003,65,77,8
goto:66,78,8
goto:71,82,7
goto:80,80,7
goto:89,78,7
goto:96,78,7
goto:104,81,7
goto:108,81,7
say:yeah
wait:1000
say:/town 1

It will be possible to use this functions to set ways to go on waypointer?
I mean, set a label, before a goto, and when get in this label, check if have supplys, or check any other thing
To check if is okey to still hunting, or go to other label to refill for example...
 
It will be possible to use this functions to set ways to go on waypointer?
I mean, set a label, before a goto, and when get in this label, check if have supplys, or check any other thing
To check if is okey to still hunting, or go to other label to refill for example...

Yeah, good idea. Will be available in next version
1572648410597.png

From function you just need to call waypoints.gotoLabel("label Name")
Code:
function(waypoints)
  -- your lua code, function is executed if previous goto was successful or is the first on the list
  waypoints.gotoLabel("CAVE")
  -- must return true to execute next command, otherwise will run in loop till correct return
  return true
end
 
Status
Not open for further replies.
Back
Top