Version 2.6.1

This commit is contained in:
OTCv8
2021-01-18 00:46:05 +01:00
parent 8fa45f387d
commit b938520faf
100 changed files with 1812 additions and 4267 deletions

View File

@@ -0,0 +1,315 @@
CaveBot.Actions = {}
-- it adds an action widget to list
CaveBot.addAction = function(action, value, focus)
action = action:lower()
local raction = CaveBot.Actions[action]
if not raction then
return error("Invalid cavebot action: " .. action)
end
if type(value) == 'number' then
value = tostring(value)
end
local widget = UI.createWidget("CaveBotAction", CaveBot.actionList)
widget:setText(action .. ":" .. value:split("\n")[1])
widget.action = action
widget.value = value
if raction.color then
widget:setColor(raction.color)
end
widget.onDoubleClick = function(cwidget) -- edit on double click
if CaveBot.Editor then
schedule(20, function() -- schedule to have correct focus
CaveBot.Editor.edit(cwidget.action, cwidget.value, function(action, value)
CaveBot.editAction(cwidget, action, value)
CaveBot.save()
end)
end)
end
end
if focus then
widget:focus()
CaveBot.actionList:ensureChildVisible(widget)
end
return widget
end
-- it updates existing widget, you should call CaveBot.save() later
CaveBot.editAction = function(widget, action, value)
action = action:lower()
local raction = CaveBot.Actions[action]
if not raction then
return error("Invalid cavebot action: " .. action)
end
if not widget.action or not widget.value then
return error("Invalid cavebot action widget, has missing action or value")
end
widget:setText(action .. ":" .. value:split("\n")[1])
widget.action = action
widget.value = value
if raction.color then
widget:setColor(raction.color)
end
return widget
end
--[[
registerAction:
action - string, color - string, callback = function(value, retries, prev)
value is a string value of action, retries is number which will grow by 1 if return is "retry"
prev is a true when previuos action was executed succesfully, false otherwise
it must return true if executed correctly, false otherwise
it can also return string "retry", then the function will be called again in 20 ms
]]--
CaveBot.registerAction = function(action, color, callback)
action = action:lower()
if CaveBot.Actions[action] then
return error("Duplicated acction: " .. action)
end
CaveBot.Actions[action] = {
color=color,
callback=callback
}
end
CaveBot.registerAction("label", "yellow", function(value, retries, prev)
return true
end)
CaveBot.registerAction("gotolabel", "#FFFF55", function(value, retries, prev)
return CaveBot.gotoLabel(value)
end)
CaveBot.registerAction("delay", "#AAAAAA", function(value, retries, prev)
if retries == 0 then
CaveBot.delay(tonumber(value))
return "retry"
end
return true
end)
CaveBot.registerAction("function", "red", function(value, retries, prev)
local prefix = "local retries = " .. retries .. "\nlocal prev = " .. tostring(prev) .. "\nlocal delay = CaveBot.delay\nlocal gotoLabel = CaveBot.gotoLabel\n"
prefix = prefix .. "local macro = function() error('Macros inside cavebot functions are not allowed') end\n"
for extension, callbacks in pairs(CaveBot.Extensions) do
prefix = prefix .. "local " .. extension .. " = CaveBot.Extensions." .. extension .. "\n"
end
local status, result = pcall(function()
return assert(load(prefix .. value, "cavebot_function"))()
end)
if not status then
error("Error in cavebot function:\n" .. result)
return false
end
return result
end)
CaveBot.registerAction("goto", "green", function(value, retries, prev)
local pos = regexMatch(value, "\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+),?\\s*([0-9]?)")
if not pos[1] then
error("Invalid cavebot goto action value. It should be position (x,y,z), is: " .. value)
return false
end
if CaveBot.Config.get("mapClick") then
if retries >= 5 then
return false -- tried 5 times, can't get there
end
else
if retries >= 100 then
return false -- tried 100 times, can't get there
end
end
local precision = tonumber(pos[1][5])
pos = {x=tonumber(pos[1][2]), y=tonumber(pos[1][3]), z=tonumber(pos[1][4])}
local playerPos = player:getPosition()
if pos.z ~= playerPos.z then
return false -- different floor
end
if math.abs(pos.x-playerPos.x) + math.abs(pos.y-playerPos.y) > 40 then
return false -- too far way
end
local minimapColor = g_map.getMinimapColor(pos)
local stairs = (minimapColor >= 210 and minimapColor <= 213)
if stairs then
if math.abs(pos.x-playerPos.x) == 0 and math.abs(pos.y-playerPos.y) <= 0 then
return true -- already at position
end
elseif math.abs(pos.x-playerPos.x) == 0 and math.abs(pos.y-playerPos.y) <= (precision or 1) then
return true -- already at position
end
-- check if there's a path to that place, ignore creatures and fields
local path = findPath(playerPos, pos, 40, { ignoreNonPathable = true, precision = 1, ignoreCreatures = true })
if not path then
return false -- there's no way
end
-- check if there's a path to destination but consider Creatures (attack only if trapped)
local path2 = findPath(playerPos, pos, 40, { ignoreNonPathable = true, precision = 1 })
if not path2 then
local monsters = {}
for i, spec in pairs(getSpectators()) do
if spec:isMonster() and spec:getType() ~= 3 and spec:canShoot() and findPath(playerPos, spec:getPosition(), 20, {ignoreNonPathable = true, precision = 1}) then
table.insert(monsters, {mob = spec, dist = getDistanceBetween(pos, spec:getPosition())})
end
end
table.sort(monsters, function(a,b) return a.dist < b.dist end)
if monsters[1] then
g_game.attack(monsters[1].mob)
storage.blockMonster = monsters[1].mob
autoWalk(storage.blockMonster, 10, {precision = 1})
storage.clearing = true
CaveBot.setOff()
g_game.setChaseMode(1)
schedule(10000, function() CaveBot.setOn() end) -- just in case callback trigger fails
return "retry"
else
return false -- there's no way
end
end
-- try to find path, don't ignore creatures, don't ignore fields
if not CaveBot.Config.get("ignoreFields") and CaveBot.walkTo(pos, 40) then
return "retry"
end
-- try to find path, don't ignore creatures, ignore fields
if CaveBot.walkTo(pos, 40, { ignoreNonPathable = true }) then
return "retry"
end
if retries >= 3 then
-- try to lower precision, find something close to final position
local precison = retries - 1
if stairs then
precison = 0
end
if CaveBot.walkTo(pos, 50, { ignoreNonPathable = true, precision = precison }) then
return "retry"
end
end
if not CaveBot.Config.get("mapClick") and retries >= 5 then
return false
end
if CaveBot.Config.get("skipBlocked") then
return false
end
-- everything else failed, try to walk ignoring creatures, maybe will work
CaveBot.walkTo(pos, 40, { ignoreNonPathable = true, precision = 1, ignoreCreatures = true })
return "retry"
end)
onCreatureDisappear(function(creature)
if creature ~= storage.blockMonster then return end
if storage.clearing then
CaveBot.setOn()
storage.blockMonster = nil
storage.clearing = false
end
end)
onCreaturePositionChange(function(creature, newPos, oldPos)
if creature ~= storage.blockMonster and creature ~= player then return end
if storage.clearing then
if creature == storage.blockMonster and not findPath(player:getPosition(), newPos, 20, {ignoreNonPathable = true, precision = 1}) then
CaveBot.setOn()
storage.blockMonster = nil
storage.clearing = false
end
if creature == player then
if oldPos.z ~= newPos.z then
CaveBot.setOn()
storage.blockMonster = nil
storage.clearing = false
end
end
end
end)
CaveBot.registerAction("use", "#FFB272", function(value, retries, prev)
local pos = regexMatch(value, "\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)")
if not pos[1] then
local itemid = tonumber(value)
if not itemid then
error("Invalid cavebot use action value. It should be (x,y,z) or item id, is: " .. value)
return false
end
use(itemid)
return true
end
pos = {x=tonumber(pos[1][2]), y=tonumber(pos[1][3]), z=tonumber(pos[1][4])}
local playerPos = player:getPosition()
if pos.z ~= playerPos.z then
return false -- different floor
end
if math.max(math.abs(pos.x-playerPos.x), math.abs(pos.y-playerPos.y)) > 7 then
return false -- too far way
end
local tile = g_map.getTile(pos)
if not tile then
return false
end
local topThing = tile:getTopUseThing()
if not topThing then
return false
end
use(topThing)
CaveBot.delay(CaveBot.Config.get("useDelay") + CaveBot.Config.get("ping"))
return true
end)
CaveBot.registerAction("usewith", "#EEB292", function(value, retries, prev)
local pos = regexMatch(value, "\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)")
if not pos[1] then
if not itemid then
error("Invalid cavebot usewith action value. It should be (itemid,x,y,z) or item id, is: " .. value)
return false
end
use(itemid)
return true
end
local itemid = tonumber(pos[1][2])
pos = {x=tonumber(pos[1][3]), y=tonumber(pos[1][4]), z=tonumber(pos[1][5])}
local playerPos = player:getPosition()
if pos.z ~= playerPos.z then
return false -- different floor
end
if math.max(math.abs(pos.x-playerPos.x), math.abs(pos.y-playerPos.y)) > 7 then
return false -- too far way
end
local tile = g_map.getTile(pos)
if not tile then
return false
end
local topThing = tile:getTopUseThing()
if not topThing then
return false
end
usewith(itemid, topThing)
CaveBot.delay(CaveBot.Config.get("useDelay") + CaveBot.Config.get("ping"))
return true
end)
CaveBot.registerAction("say", "#FF55FF", function(value, retries, prev)
say(value)
return true
end)

View File

@@ -0,0 +1,72 @@
CaveBot.Extensions.Bank = {}
CaveBot.Extensions.Bank.setup = function()
CaveBot.registerAction("bank", "#00FFFF", function(value, retries)
local data = string.split(value, ",")
local waitVal = 300
local amount = 0
local actionType
local npcName
if #data ~= 3 and #data ~= 2 then
warn("CaveBot[Bank]: incorrect value!")
return false
else
actionType = data[1]:trim():lower()
npcName = data[2]:trim()
if #data == 3 then
amount = tonumber(data[3]:trim())
end
end
if actionType ~= "withdraw" and actionType ~= "deposit" then
warn("CaveBot[Bank]: incorrect action type! should be withdraw/deposit, is: " .. actionType)
return false
elseif actionType == "withdraw" then
local value = tonumber(amount)
if not value then
warn("CaveBot[Bank]: incorrect amount value! should be number, is: " .. amount)
return false
end
end
if retries > 5 then
print("CaveBot[Bank]: too many tries, skipping")
return false
end
local npc = getCreatureByName(npcName)
if not npc then
print("CaveBot[Bank]: NPC not found, skipping")
return false
end
local pos = player:getPosition()
local npcPos = npc:getPosition()
if math.max(math.abs(pos.x - npcPos.x), math.abs(pos.y - npcPos.y)) > 3 then
CaveBot.walkTo(npcPos, 20, {ignoreNonPathable = true, precision=3})
delay(300)
return "retry"
end
if actionType == "deposit" then
NPC.say("hi")
schedule(waitVal, function() NPC.say("deposit all") end)
schedule(waitVal*2, function() NPC.say("yes") end)
CaveBot.delay(waitVal*3)
return true
else
NPC.say("hi")
schedule(waitVal, function() NPC.say("withdraw") end)
schedule(waitVal*2, function() NPC.say(value) end)
schedule(waitVal*3, function() NPC.say("yes") end)
CaveBot.delay(waitVal*4)
return true
end
end)
CaveBot.Editor.registerAction("bank", "bank", {
value="action, NPC name",
title="Banker",
description="action type(withdraw/deposit), NPC name, if withdraw: amount",
})
end

View File

@@ -0,0 +1,116 @@
CaveBot.Extensions.BuySupplies = {}
storage.buySuppliesCap = 0
CaveBot.Extensions.BuySupplies.setup = function()
CaveBot.registerAction("BuySupplies", "#00FFFF", function(value, retries)
local item1Count = 0
local item2Count = 0
local item3Count = 0
local item4Count = 0
local item5Count = 0
local val = string.split(value, ",")
local waitVal
if #val == 0 or #val > 2 then
warn("CaveBot[BuySupplies]: incorrect BuySupplies value")
return false
elseif #val == 2 then
waitVal = tonumber(val[2]:trim())
end
local npc = getCreatureByName(val[1]:trim())
if not npc then
print("CaveBot[BuySupplies]: NPC not found")
return false
end
if not waitVal and #val == 2 then
warn("CaveBot[BuySupplies]: incorrect delay values!")
elseif waitVal and #val == 2 then
delay(waitVal)
end
if retries > 40 then
print("CaveBot[BuySupplies]: Too many tries, can't buy")
return false
end
if freecap() == storage.buySuppliesCap then
storage.buySuppliesCap = 0
print("CaveBot[BuySupplies]: Bought Everything, proceeding")
return true
end
delay(800)
local pos = player:getPosition()
local npcPos = npc:getPosition()
if math.max(math.abs(pos.x - npcPos.x), math.abs(pos.y - npcPos.y)) > 3 then
CaveBot.walkTo(npcPos, 20, {ignoreNonPathable = true, precision=3})
delay(300)
return "retry"
end
for _, container in pairs(getContainers()) do
for _, item in ipairs(container:getItems()) do
if (storage[suppliesPanelName].item1 > 100) and (item:getId() == storage[suppliesPanelName].item1) then
item1Count = item1Count + item:getCount()
end
if (storage[suppliesPanelName].item2 > 100) and (item:getId() == storage[suppliesPanelName].item2) then
item2Count = item2Count + item:getCount()
end
if (storage[suppliesPanelName].item3 > 100) and (item:getId() == storage[suppliesPanelName].item3) then
item3Count = item3Count + item:getCount()
end
if (storage[suppliesPanelName].item4 > 100) and (item:getId() == storage[suppliesPanelName].item4) then
item4Count = item4Count + item:getCount()
end
if (storage[suppliesPanelName].item5 > 100) and (item:getId() == storage[suppliesPanelName].item5) then
item5Count = item5Count + item:getCount()
end
end
end
local itemList = {
item1 = {ID = storage[suppliesPanelName].item1, maxAmount = storage[suppliesPanelName].item1Max, currentAmount = item1Count},
item2 = {ID = storage[suppliesPanelName].item2, maxAmount = storage[suppliesPanelName].item2Max, currentAmount = item2Count},
item3 = {ID = storage[suppliesPanelName].item3, maxAmount = storage[suppliesPanelName].item3Max, currentAmount = item3Count},
item4 = {ID = storage[suppliesPanelName].item4, maxAmount = storage[suppliesPanelName].item4Max, currentAmount = item4Count},
item5 = {ID = storage[suppliesPanelName].item5, maxAmount = storage[suppliesPanelName].item5Max, currentAmount = item5Count}
}
if not NPC.isTrading() then
NPC.say("hi")
schedule(500, function() NPC.say("trade") end)
else
storage.buySuppliesCap = freecap()
end
for i, item in pairs(itemList) do
if item["ID"] > 100 then
local amountToBuy = item["maxAmount"] - item["currentAmount"]
if amountToBuy > 100 then
for i=1, math.ceil(amountToBuy/100), 1 do
NPC.buy(item["ID"], math.min(100, amountToBuy))
amountToBuy = amountToBuy - math.min(100, amountToBuy)
print("CaveBot[BuySupplies]: bought " .. amountToBuy .. "x " .. item["ID"])
return "retry"
end
else
if amountToBuy > 0 then
NPC.buy(item["ID"], amountToBuy)
print("CaveBot[BuySupplies]: bought " .. amountToBuy .. "x " .. item["ID"])
return "retry"
end
end
end
end
return "retry"
end)
CaveBot.Editor.registerAction("buysupplies", "buy supplies", {
value="NPC name",
title="Buy Supplies",
description="NPC Name, delay(in ms, optional)",
})
end

View File

@@ -0,0 +1,224 @@
local cavebotMacro = nil
local config = nil
-- ui
local configWidget = UI.Config()
local ui = UI.createWidget("CaveBotPanel")
ui.list = ui.listPanel.list -- shortcut
CaveBot.actionList = ui.list
if CaveBot.Editor then
CaveBot.Editor.setup()
end
if CaveBot.Config then
CaveBot.Config.setup()
end
for extension, callbacks in pairs(CaveBot.Extensions) do
if callbacks.setup then
callbacks.setup()
end
end
-- main loop, controlled by config
local actionRetries = 0
local prevActionResult = true
cavebotMacro = macro(20, function()
if TargetBot and TargetBot.isActive() and not TargetBot.isCaveBotActionAllowed() then
CaveBot.resetWalking()
return -- target bot or looting is working, wait
end
if CaveBot.doWalking() then
return -- executing walking
end
local actions = ui.list:getChildCount()
if actions == 0 then return end
local currentAction = ui.list:getFocusedChild()
if not currentAction then
currentAction = ui.list:getFirstChild()
end
local action = CaveBot.Actions[currentAction.action]
local value = currentAction.value
local retry = false
if action then
local status, result = pcall(function()
CaveBot.resetWalking()
return action.callback(value, actionRetries, prevActionResult)
end)
if status then
if result == "retry" then
actionRetries = actionRetries + 1
retry = true
elseif type(result) == 'boolean' then
actionRetries = 0
prevActionResult = result
else
error("Invalid return from cavebot action (" .. currentAction.action .. "), should be \"retry\", false or true, is: " .. tostring(result))
end
else
error("Error while executing cavebot action (" .. currentAction.action .. "):\n" .. result)
end
else
error("Invalid cavebot action: " .. currentAction.action)
end
if retry then
return
end
if currentAction ~= ui.list:getFocusedChild() then
-- focused child can change durring action, get it again and reset state
currentAction = ui.list:getFocusedChild() or ui.list:getFirstChild()
actionRetries = 0
prevActionResult = true
end
local nextAction = ui.list:getChildIndex(currentAction) + 1
if nextAction > actions then
nextAction = 1
end
ui.list:focusChild(ui.list:getChildByIndex(nextAction))
end)
-- config, its callback is called immediately, data can be nil
local lastConfig = ""
config = Config.setup("cavebot_configs", configWidget, "cfg", function(name, enabled, data)
if enabled and CaveBot.Recorder.isOn() then
CaveBot.Recorder.disable()
CaveBot.setOff()
return
end
local currentActionIndex = ui.list:getChildIndex(ui.list:getFocusedChild())
ui.list:destroyChildren()
if not data then return cavebotMacro.setOff() end
local cavebotConfig = nil
for k,v in ipairs(data) do
if type(v) == "table" and #v == 2 then
if v[1] == "config" then
local status, result = pcall(function()
return json.decode(v[2])
end)
if not status then
error("Error while parsing CaveBot extensions from config:\n" .. result)
else
cavebotConfig = result
end
elseif v[1] == "extensions" then
local status, result = pcall(function()
return json.decode(v[2])
end)
if not status then
error("Error while parsing CaveBot extensions from config:\n" .. result)
else
for extension, callbacks in pairs(CaveBot.Extensions) do
if callbacks.onConfigChange then
callbacks.onConfigChange(name, enabled, result[extension])
end
end
end
else
CaveBot.addAction(v[1], v[2])
end
end
end
CaveBot.Config.onConfigChange(name, enabled, cavebotConfig)
actionRetries = 0
CaveBot.resetWalking()
prevActionResult = true
cavebotMacro.setOn(enabled)
cavebotMacro.delay = nil
if lastConfig == name then
-- restore focused child on the action list
ui.list:focusChild(ui.list:getChildByIndex(currentActionIndex))
end
lastConfig = name
end)
-- ui callbacks
ui.showEditor.onClick = function()
if not CaveBot.Editor then return end
if ui.showEditor:isOn() then
CaveBot.Editor.hide()
ui.showEditor:setOn(false)
else
CaveBot.Editor.show()
ui.showEditor:setOn(true)
end
end
ui.showConfig.onClick = function()
if not CaveBot.Config then return end
if ui.showConfig:isOn() then
CaveBot.Config.hide()
ui.showConfig:setOn(false)
else
CaveBot.Config.show()
ui.showConfig:setOn(true)
end
end
-- public function, you can use them in your scripts
CaveBot.isOn = function()
return config.isOn()
end
CaveBot.isOff = function()
return config.isOff()
end
CaveBot.setOn = function(val)
if val == false then
return CaveBot.setOff(true)
end
config.setOn()
end
CaveBot.setOff = function(val)
if val == false then
return CaveBot.setOn(true)
end
config.setOff()
end
CaveBot.delay = function(value)
cavebotMacro.delay = math.max(cavebotMacro.delay or 0, now + value)
end
CaveBot.gotoLabel = function(label)
label = label:lower()
for index, child in ipairs(ui.list:getChildren()) do
if child.action == "label" and child.value:lower() == label then
ui.list:focusChild(child)
return true
end
end
return false
end
CaveBot.save = function()
local data = {}
for index, child in ipairs(ui.list:getChildren()) do
table.insert(data, {child.action, child.value})
end
if CaveBot.Config then
table.insert(data, {"config", json.encode(CaveBot.Config.save())})
end
local extension_data = {}
for extension, callbacks in pairs(CaveBot.Extensions) do
if callbacks.onSave then
local ext_data = callbacks.onSave()
if type(ext_data) == "table" then
extension_data[extension] = ext_data
end
end
end
table.insert(data, {"extensions", json.encode(extension_data, 2)})
config.save(data)
end

View File

@@ -0,0 +1,58 @@
CaveBotAction < Label
background-color: alpha
text-offset: 2 0
focusable: true
$focus:
background-color: #00000055
CaveBotPanel < Panel
layout:
type: verticalBox
fit-children: true
HorizontalSeparator
margin-top: 2
margin-bottom: 5
Panel
id: listPanel
height: 100
margin-top: 2
TextList
id: list
anchors.fill: parent
vertical-scrollbar: listScrollbar
margin-right: 15
focusable: false
auto-focus: first
VerticalScrollBar
id: listScrollbar
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
pixels-scroll: true
step: 10
BotSwitch
id: showEditor
margin-top: 2
$on:
text: Hide waypoints editor
$!on:
text: Show waypoints editor
BotSwitch
id: showConfig
margin-top: 2
$on:
text: Hide config
$!on:
text: Show config

View File

@@ -0,0 +1,94 @@
-- config for bot
CaveBot.Config = {}
CaveBot.Config.values = {}
CaveBot.Config.default_values = {}
CaveBot.Config.value_setters = {}
CaveBot.Config.setup = function()
CaveBot.Config.ui = UI.createWidget("CaveBotConfigPanel")
local ui = CaveBot.Config.ui
local add = CaveBot.Config.add
add("ping", "Server ping", 100)
add("walkDelay", "Walk delay", 10)
add("mapClick", "Use map click", false)
add("mapClickDelay", "Map click delay", 100)
add("ignoreFields", "Ignore fields", false)
add("skipBlocked", "Skip blocked path", false)
add("useDelay", "Delay after use", 400)
end
CaveBot.Config.show = function()
CaveBot.Config.ui:show()
end
CaveBot.Config.hide = function()
CaveBot.Config.ui:hide()
end
CaveBot.Config.onConfigChange = function(configName, isEnabled, configData)
for k, v in pairs(CaveBot.Config.default_values) do
CaveBot.Config.value_setters[k](v)
end
if not configData then return end
for k, v in pairs(configData) do
if CaveBot.Config.value_setters[k] then
CaveBot.Config.value_setters[k](v)
end
end
end
CaveBot.Config.save = function()
return CaveBot.Config.values
end
CaveBot.Config.add = function(id, title, defaultValue)
if CaveBot.Config.values[id] then
return error("Duplicated config key: " .. id)
end
local panel
local setter -- sets value
if type(defaultValue) == "number" then
panel = UI.createWidget("CaveBotConfigNumberValuePanel", CaveBot.Config.ui)
setter = function(value)
CaveBot.Config.values[id] = value
panel.value:setText(value, true)
end
setter(defaultValue)
panel.value.onTextChange = function(widget, newValue)
newValue = tonumber(newValue)
if newValue then
CaveBot.Config.values[id] = newValue
CaveBot.save()
end
end
elseif type(defaultValue) == "boolean" then
panel = UI.createWidget("CaveBotConfigBooleanValuePanel", CaveBot.Config.ui)
setter = function(value)
CaveBot.Config.values[id] = value
panel.value:setOn(value, true)
end
setter(defaultValue)
panel.value.onClick = function(widget)
widget:setOn(not widget:isOn())
CaveBot.Config.values[id] = widget:isOn()
CaveBot.save()
end
else
return error("Invalid default value of config for key " .. id .. ", should be number or boolean")
end
panel.title:setText(tr(title) .. ":")
CaveBot.Config.value_setters[id] = setter
CaveBot.Config.values[id] = defaultValue
CaveBot.Config.default_values[id] = defaultValue
end
CaveBot.Config.get = function(id)
if CaveBot.Config.values[id] == nil then
return error("Invalid CaveBot.Config.get, id: " .. id)
end
return CaveBot.Config.values[id]
end

View File

@@ -0,0 +1,57 @@
CaveBotConfigPanel < Panel
id: cavebotEditor
visible: false
layout:
type: verticalBox
fit-children: true
HorizontalSeparator
margin-top: 5
Label
text-align: center
text: CaveBot Config
margin-top: 5
CaveBotConfigNumberValuePanel < Panel
height: 20
margin-top: 5
BotTextEdit
id: value
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
margin-right: 5
width: 50
Label
id: title
anchors.left: parent.left
anchors.verticalCenter: prev.verticalCenter
margin-left: 5
CaveBotConfigBooleanValuePanel < Panel
height: 20
margin-top: 5
BotSwitch
id: value
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
margin-right: 5
width: 50
$on:
text: On
$!on:
text: Off
Label
id: title
anchors.left: parent.left
anchors.verticalCenter: prev.verticalCenter
margin-left: 5

View File

@@ -0,0 +1,188 @@
CaveBot.Extensions.DWithdraw = {}
comparePosition = function(pPos, tPos)
return (getDistanceBetween(pPos, tPos) <= 1)
end
local depotIDs = {3497, 3498, 3499, 3500}
local depotContainers = {22797, 22798, 22799, 22800, 22801, 22802, 22803, 22804, 22805, 22806, 22807, 22808, 22809, 22810, 22811, 22812, 22813}
storage.stopSearch = false
storage.lootContainerOpen = false
local i = 1
CaveBot.Extensions.DWithdraw.setup = function()
CaveBot.registerAction("dpwithdraw", "#00FFFF", function(value, retries)
local capLimit = nil
if retries > 600 then
print("CaveBot[DepotWithdraw]: actions limit reached, proceeding")
return true
end
delay(50)
if not value or #string.split(value, ",") ~= 3 and #string.split(value, ",") ~= 4 then
warn("CaveBot[DepotWithdraw]: incorrect value!")
return false
end
local indexDp = tonumber(string.split(value, ",")[1]:trim())
local destName = string.split(value, ",")[2]:trim()
local destId = tonumber(string.split(value, ",")[3]:trim())
if #string.split(value, ",") == 4 then
capLimit = tonumber(string.split(value, ",")[4]:trim())
end
if freecap() < (capLimit or 200) then
print("CaveBot[DepotWithdraw]: cap limit reached, proceeding")
return true
end
local destContainer
for i, container in pairs(getContainers()) do
if container:getName():lower() == destName:lower() then
destContainer = container
end
if string.find(container:getName():lower(), "depot box") then
if #container:getItems() == 0 then
print("CaveBot[DepotWithdraw]: all items withdrawn")
return true
end
end
end
if not destContainer then
print("CaveBot[DepotWithdraw]: container not found!")
return false
end
if destContainer:getCapacity() == destContainer:getSize() then
for j, item in pairs(destContainer:getItems()) do
if item:getId() == destId then
g_game.open(item, destContainer)
return "retry"
end
end
print("CaveBot[DepotWithdraw]: loot containers full!")
return true
end
local tileList = {}
local tPos
local depotClear = false
local depotOpen = false
local depotBoxOpen = false
for _,tile in pairs(g_map.getTiles(posz())) do
for i,thing in pairs(tile:getThings()) do
if table.find(depotIDs, thing:getId()) then
table.insert(tileList, {tileObj = tile, distance = getDistanceBetween(pos(), tile:getPosition()), depotID = thing:getId()})
end
end
end
table.sort(tileList, function(a,b) return a.distance < b.distance end)
::findEmptyDP::
if tileList[i] and not storage.stopSearch then
if tileList[i].depotID == 3498 then
tPos = {x = tileList[i].tileObj:getPosition().x + 1, y = tileList[i].tileObj:getPosition().y, z = tileList[i].tileObj:getPosition().z}
elseif tileList[i].depotID == 3499 then
tPos = {x = tileList[i].tileObj:getPosition().x, y = tileList[i].tileObj:getPosition().y + 1, z = tileList[i].tileObj:getPosition().z}
elseif tileList[i].depotID == 3500 then
tPos = {x = tileList[i].tileObj:getPosition().x - 1, y = tileList[i].tileObj:getPosition().y, z = tileList[i].tileObj:getPosition().z}
elseif tileList[i].depotID == 3497 then
tPos = {x = tileList[i].tileObj:getPosition().x, y = tileList[i].tileObj:getPosition().y - 1, z = tileList[i].tileObj:getPosition().z}
end
if tPos then
local dest = g_map.getTile(tPos)
if not comparePosition(pos(), dest:getPosition()) then
if not dest:getCreatures()[1] and dest:isWalkable() then
if CaveBot.walkTo(dest:getPosition(), {ignoreNonPathable=true}) then
storage.stopSearch = true
delay(100)
end
else
i = i + 1
goto findEmptyDP
end
end
end
end
if tileList[i].tileObj and not table.find(depotIDs, tileList[i].tileObj:getTopLookThing():getId()) and comparePosition(pos(), tileList[i].tileObj:getPosition()) then
for j=1,table.getn(tileList[i].tileObj:getThings()),1 do
if not tileList[i].tileObj:getThings()[j]:isNotMoveable() then
delay(500)
g_game.move(tileList[i].tileObj:getThings()[j], pos(), tileList[i].tileObj:getThings()[j]:getCount())
end
end
if table.find(depotIDs, tileList[i].tileObj:getTopLookThing():getId()) then
depotClear = true
end
else
depotClear = true
end
if depotClear then
for _, container in pairs(g_game.getContainers()) do
if container:getName():lower() == "locker" then
depotOpen = true
end
end
end
if tileList[i].tileObj and depotClear and not depotOpen and not storage.lootContainerOpen then
delay(500)
g_game.use(tileList[i].tileObj:getTopUseThing())
depotOpen = true
end
i = 1
--Version Check to know what to do with the depot--
if g_game.getClientVersion() > 910 then
if depotOpen then
for _, container in pairs(g_game.getContainers()) do
if container:getName():lower() == "depot chest" then
depotBoxOpen = true
end
end
if findItem(3502) and not depotBoxOpen then
delay(500)
g_game.use(findItem(3502))
depotBoxOpen = true
end
end
if depotBoxOpen and not storage.lootContainerOpen then
for _, container in pairs(g_game.getContainers()) do
if container:getName():lower() == "depot chest" then
for _, item in ipairs(container:getItems()) do
if item:isContainer() and table.find({22797, 22798}, item:getId()) then
g_game.open(findItem(depotContainers[indexDp]), container)
delay(500)
for _, cont in pairs(g_game.getContainers()) do
if string.find(cont:getName():lower(), "depot box") then
storage.lootContainerOpen = true
break
end
end
end
end
break
end
end
end
for i, container in pairs(g_game.getContainers()) do
if string.find(container:getName():lower(), "depot box") then
for j, item in ipairs(container:getItems()) do
g_game.move(item, destContainer:getSlotPosition(destContainer:getItemsCount()), item:getCount())
return "retry"
end
end
end
end
return "retry"
end)
CaveBot.Editor.registerAction("dpwithdraw", "dpwithdraw", {
value="1, shopping bag, 21411",
title="Loot Withdraw",
description="index Depot, destination container name and it's ID",
})
end
onPlayerPositionChange(function(newPos, oldPos)
storage.lootContainerOpen = false
storage.stopSearch = false
end)

View File

@@ -0,0 +1,27 @@
CaveBot.Extensions.Depositer = {}
local ui
-- first function called, here you should setup your UI
CaveBot.Extensions.Depositer.setup = function()
--ui = UI.createWidget('Label')
--ui:setText("Depositer UI")
end
-- called when cavebot config changes, configData is a table but it can be nil
CaveBot.Extensions.Depositer.onConfigChange = function(configName, isEnabled, configData)
if not configData then return end
end
-- called when cavebot is saving config, should return table or nil
CaveBot.Extensions.Depositer.onSave = function()
return {}
end
-- bellow add you custom functions
-- this function can be used in cavebot function waypoint as: return Depositer.run(retries, prev)
-- there are 2 useful parameters - retries (number) and prev (true/false), check actions.lua to learn more
CaveBot.Extensions.Depositer.run = function(retries, prev)
return true
end

View File

@@ -0,0 +1,376 @@
CaveBot.Extensions.Depositor = {}
local depotIDs = {3497, 3498, 3499, 3500}
local reset = function()
storage.stopSearch = false
storage.lootContainerOpen = false
storage.containersClosed = false
storage.containersReset = false
storage.currentStack = 0
storage.currentNonStack = nonStackMin
storage.lastTry = nil
storage.lootItemsCount = 0
storage.depositDone = false
end
local i = 1
CaveBot.Extensions.Depositor.setup = function()
CaveBot.registerAction("depositor", "#00FFFF", function(value, retries)
if retries > 400 then
print("CaveBot[Depositor]: Depositor actions limit reached, proceeding")
reset()
return true
end
local name = storage["_configs"]["targetbot_configs"]["selected"]
local file = configDir .. "/targetbot_configs/" .. name .. ".json"
local data = g_resources.readFileContents(file)
local lootList = Config.parse(data)['looting']['items']
local lootContainers = Config.parse(data)['looting']['containers']
local mainBp
local stackBp
local nonStackBp
local valueString = string.split(value, ",") -- if 3 then it's old tibia
-- if old tibia then setup backpacks
if #valueString == 3 then
mainBp = tonumber(valueString[1]:trim())
stackBp = tonumber(valueString[2]:trim()) -- non-stack bp count
nonStackBp = tonumber(valueString[3]:trim()) -- stack bp count
if not mainBp or not stackBp or not nonStackBp then
warn("CaveBot[Depositor]: incorrect values! should be 3x ID of containers!")
reset()
return false
end
end
-- start with checking the containers
local lootDestination = {}
for _, container in pairs(lootContainers) do
if not table.find(lootDestination, container['id']) then
table.insert(lootDestination, container['id'])
end
end
-- pretty much every container action is needed only if you want to work with containers
if (value:lower() == "yes" or #valueString == 3) and not storage.containersReset then
-- what is open and what's not
local currentContainers = {}
for i, container in pairs(getContainers()) do
if not table.find(currentContainers, container:getContainerItem():getId()) then
table.insert(currentContainers, container:getContainerItem():getId())
end
end
delay(500) -- slow down this function until containers reset
if #lootDestination > 0 then
-- first closing all that are opened
if not storage.containersClosed then
for i, container in pairs(getContainers()) do
if table.find(lootDestination, container:getContainerItem():getId()) then
g_game.close(container)
return "retry"
end
end
storage.containersClosed = true
end
-- now reopen them
if not storage.containersReset and storage.containersClosed then
for i, container in pairs(getContainers()) do
for j, item in pairs(container:getItems()) do
if table.find(lootDestination, item:getId()) and not table.find(currentContainers, item:getId()) then
g_game.open(item)
return "retry"
end
end
end
storage.containersReset = true
end
end
end
if storage.depositDone then
reset()
print("CaveBot[Depositor]: Deposit finished, proceeding")
return true
end
local tileList = {}
local tPos
local depotClear = false
local depotOpen = false
local depotBoxOpen = false
for _,tile in pairs(g_map.getTiles(posz())) do
for i,thing in pairs(tile:getThings()) do
if table.find(depotIDs, thing:getId()) then
table.insert(tileList, {tileObj = tile, distance = getDistanceBetween(pos(), tile:getPosition()), depotID = thing:getId()})
end
end
end
table.sort(tileList, function(a,b) return a.distance < b.distance end)
::findEmptyDP::
if tileList[i] and not storage.stopSearch then
if tileList[i].depotID == 3498 then
tPos = {x = tileList[i].tileObj:getPosition().x + 1, y = tileList[i].tileObj:getPosition().y, z = tileList[i].tileObj:getPosition().z}
elseif tileList[i].depotID == 3499 then
tPos = {x = tileList[i].tileObj:getPosition().x, y = tileList[i].tileObj:getPosition().y + 1, z = tileList[i].tileObj:getPosition().z}
elseif tileList[i].depotID == 3500 then
tPos = {x = tileList[i].tileObj:getPosition().x - 1, y = tileList[i].tileObj:getPosition().y, z = tileList[i].tileObj:getPosition().z}
elseif tileList[i].depotID == 3497 then
tPos = {x = tileList[i].tileObj:getPosition().x, y = tileList[i].tileObj:getPosition().y - 1, z = tileList[i].tileObj:getPosition().z}
end
if tPos then
local dest = g_map.getTile(tPos)
if not (getDistanceBetween(pos(), dest:getPosition()) <= 1) then
if not dest:getCreatures()[1] and dest:isWalkable() then
if CaveBot.walkTo(dest:getPosition(), {ignoreNonPathable=true}) then
storage.stopSearch = true
delay(100)
end
else
i = i + 1
goto findEmptyDP
end
end
end
end
if tileList[i] and not table.find(depotIDs, tileList[i].tileObj:getTopLookThing():getId()) and (getDistanceBetween(pos(), tileList[i].tileObj:getPosition()) <= 1) then
for j=1,table.getn(tileList[i].tileObj:getThings()),1 do
if not tileList[i].tileObj:getThings()[j]:isNotMoveable() then
delay(500)
g_game.move(tileList[i].tileObj:getThings()[j], pos(), tileList[i].tileObj:getThings()[j]:getCount())
end
end
if table.find(depotIDs, tileList[i].tileObj:getTopLookThing():getId()) then
depotClear = true
end
else
depotClear = true
end
if depotClear then
for _, container in pairs(getContainers()) do
if container:getName():lower() == "locker" then
depotOpen = true
end
end
end
if tileList[i] and depotClear and not depotOpen and not storage.lootContainerOpen then
delay(500)
g_game.use(tileList[i].tileObj:getTopUseThing())
depotOpen = true
end
i = 1
-- finding depot
if depotOpen then
for _, container in pairs(getContainers()) do
if container:getName():lower() == "depot chest" then
depotBoxOpen = true
end
end
if findItem(3502) and not depotBoxOpen then
delay(500)
g_game.use(findItem(3502))
depotBoxOpen = true
end
end
if depotBoxOpen and not storage.lootContainerOpen then
for _, container in pairs(getContainers()) do
if container:getName():lower() == "depot chest" then
for _, item in ipairs(container:getItems()) do
if #valueString ~= 3 then -- new depot
if item:isContainer() and table.find({22797, 22798}, item:getId()) then
delay(500)
storage.lootContainerOpen = true
break
end
else
if item:isContainer() and item:getId() == mainBp then
delay(500)
g_game.use(item, container)
storage.lootContainerOpen = true
break
end
end
end
break
end
end
end
if #valueString == 3 then
delay(150)
for _, container in pairs(getContainers()) do
if container:getContainerItem():getId() == mainBp then
storage.lootContainerOpen = true
storage.isDepositing = true
break
end
end
end
local looting = {}
for _, lootItem in pairs(lootList) do
if not table.find(looting, lootItem['id']) and not table.find({3031, 3035, 3043}, lootItem['id']) then
table.insert(looting, lootItem['id'])
end
end
delay(200)
local currentItems = 0
for _, container in pairs(getContainers()) do
for _, item in ipairs(container:getItems()) do
if table.find(looting, item:getId()) then
currentItems = currentItems + item:getCount()
end
end
end
if currentItems == 0 then
if value:lower() ~= "yes" and #valueString ~= 3 then
storage.containersClosed = false
storage.containersReset = false
storage.depositDone = true
return "retry"
end
for i, container in pairs(getContainers()) do
for j, item in pairs(container:getItems()) do
if table.find(lootDestination, container:getContainerItem():getId()) and table.find(lootDestination, item:getId()) then
g_game.open(item, container)
return "retry"
end
end
end
storage.containersClosed = false
storage.containersReset = false
storage.depositDone = true
return "retry"
end
-- only if old depot
local stackMin
local stackMax
local nonStackMin
local nonStackMax
if #valueString == 3 then
-- backpacks setup
local stack = 0
local nonStack = 0
for i, container in pairs(getContainers()) do
if container:getContainerItem():getId() == mainBp then
for i, item in pairs(container:getItems()) do
if item:getId() == stackBp then
stack = stack + 1
elseif item:getId() == nonStackBp then
nonStack = nonStack + 1
end
end
end
end
stackMax = stack - 1
nonStackMin = stack
nonStackMax = (stack + nonStack) - 1
storage.currentStack = 0
storage.currentNonStack = nonStackMin
if storage.lootItemsCount == currentItems then
if storage.lastTry == 1 then
if storage.currentStack < stackMax then
storage.currentStack = storage.currentStack + 1
else
warn("CaveBot[Depositer]: Stack Backpack full! Proceeding.")
reset()
return true
end
elseif storage.lastTry == 2 then
if storage.currentNonStack < nonStackMax then
storage.currentNonStack = storage.currentNonStack + 1
else
warn("CaveBot[Depositer]: Non-Stack Backpack full! Proceeding.")
reset()
return true
end
end
end
storage.lootItemsCount = currentItems
end
if #looting > 0 then
if #valueString ~= 3 then -- version check, if value is set of 3 i
for i, depotcontainer in pairs(getContainers()) do
containerItemId = depotcontainer:getContainerItem():getId()
--check if open depot
if containerItemId == 3502 then
-- check all containers and items
for l, lootcontainer in pairs(getContainers()) do
for j, item in ipairs(lootcontainer:getItems()) do
-- now the criteria
if table.find(looting, item:getId()) then
-- move the item
if item:isStackable() then
g_game.move(item, depotcontainer:getSlotPosition(1), item:getCount())
return "retry"
else
g_game.move(item, depotcontainer:getSlotPosition(0), item:getCount())
return "retry"
end
end
end
end
end
end
else -- to be written, last part missing is stashing items for old depots
for i, depotcontainer in pairs(getContainers()) do
containerItemId = depotcontainer:getContainerItem():getId()
--check if open depot
if containerItemId == mainBp then
-- check all containers and items
for l, lootcontainer in pairs(getContainers()) do
for j, item in ipairs(lootcontainer:getItems()) do
-- now the criteria
if table.find(looting, item:getId()) then
-- move the item
if item:isStackable() then
g_game.move(item, depotcontainer:getSlotPosition(storage.currentStack), item:getCount())
storage.lastTry = 1
return "retry"
else
g_game.move(item, depotcontainer:getSlotPosition(storage.currentNonStack), item:getCount())
storage.lastTry = 2
return "retry"
end
end
end
end
end
end
end
else
warn("no items in looting list!")
reset()
return false
end
return "retry"
end)
CaveBot.Editor.registerAction("depositor", "depositor", {
value="no",
title="Depositor",
description="No - just deposit \n Yes - also reopen loot containers \n mainID, stackId, nonStackId - for older tibia",
})
end
onPlayerPositionChange(function(newPos, oldPos)
if CaveBot.isOn() then
reset()
end
end)

View File

@@ -0,0 +1,47 @@
CaveBot.Extensions.OpenDoors = {}
CaveBot.Extensions.OpenDoors.setup = function()
CaveBot.registerAction("OpenDoors", "#00FFFF", function(value, retries)
local pos = regexMatch(value, "\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)")
if not pos[1] then
error("CaveBot[OpenDoors]: invalid value. It should be position (x,y,z), is: " .. value)
return false
end
if retries >= 5 then
print("CaveBot[OpenDoors]: too many tries, can't open doors")
return false -- tried 5 times, can't open
end
pos = {x=tonumber(pos[1][2]), y=tonumber(pos[1][3]), z=tonumber(pos[1][4])}
local doorTile
if not doorTile then
for i, tile in ipairs(g_map.getTiles(posz())) do
if tile:getPosition().x == pos.x and tile:getPosition().y == pos.y and tile:getPosition().z == pos.z then
doorTile = tile
end
end
end
if not doorTile then
return false
end
if not doorTile:isWalkable() then
use(doorTile:getTopUseThing())
return "retry"
else
print("CaveBot[OpenDoors]: possible to cross, proceeding")
return true
end
end)
CaveBot.Editor.registerAction("opendoors", "open doors", {
value=function() return posx() .. "," .. posy() .. "," .. posz() end,
title="Door position",
description="doors position (x,y,z)",
multiline=false,
validation="^\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)$"
})
end

View File

@@ -0,0 +1,174 @@
CaveBot.Editor = {}
CaveBot.Editor.Actions = {}
-- also works as registerAction(action, params), then text == action
-- params are options for text editor or function to be executed when clicked
-- you have many examples how to use it bellow
CaveBot.Editor.registerAction = function(action, text, params)
if type(text) ~= 'string' then
params = text
text = action
end
local color = nil
if type(params) ~= 'function' then
local raction = CaveBot.Actions[action]
if not raction then
return error("CaveBot editor error: action " .. action .. " doesn't exist")
end
CaveBot.Editor.Actions[action] = params
color = raction.color
end
local button = UI.createWidget('CaveBotEditorButton', CaveBot.Editor.ui.buttons)
button:setText(text)
if color then
button:setColor(color)
end
button.onClick = function()
if type(params) == 'function' then
params()
return
end
CaveBot.Editor.edit(action, nil, function(action, value)
local focusedAction = CaveBot.actionList:getFocusedChild()
local index = CaveBot.actionList:getChildCount()
if focusedAction then
index = CaveBot.actionList:getChildIndex(focusedAction)
end
local widget = CaveBot.addAction(action, value)
CaveBot.actionList:moveChildToIndex(widget, index + 1)
CaveBot.actionList:focusChild(widget)
CaveBot.save()
end)
end
return button
end
CaveBot.Editor.setup = function()
CaveBot.Editor.ui = UI.createWidget("CaveBotEditorPanel")
local ui = CaveBot.Editor.ui
local registerAction = CaveBot.Editor.registerAction
registerAction("move up", function()
local action = CaveBot.actionList:getFocusedChild()
if not action then return end
local index = CaveBot.actionList:getChildIndex(action)
if index < 2 then return end
CaveBot.actionList:moveChildToIndex(action, index - 1)
CaveBot.actionList:ensureChildVisible(action)
CaveBot.save()
end)
registerAction("edit", function()
local action = CaveBot.actionList:getFocusedChild()
if not action or not action.onDoubleClick then return end
action.onDoubleClick(action)
end)
registerAction("move down", function()
local action = CaveBot.actionList:getFocusedChild()
if not action then return end
local index = CaveBot.actionList:getChildIndex(action)
if index >= CaveBot.actionList:getChildCount() then return end
CaveBot.actionList:moveChildToIndex(action, index + 1)
CaveBot.actionList:ensureChildVisible(action)
CaveBot.save()
end)
registerAction("remove", function()
local action = CaveBot.actionList:getFocusedChild()
if not action then return end
action:destroy()
CaveBot.save()
end)
registerAction("label", {
value="labelName",
title="Label",
description="Add label",
multiline=false
})
registerAction("delay", {
value="500",
title="Delay",
description="Delay next action (in milliseconds)",
multiline=false,
validation="^\\s*[0-9]{1,10}\\s*$"
})
registerAction("gotolabel", "go to label", {
value="labelName",
title="Go to label",
description="Go to label",
multiline=false
})
registerAction("goto", "go to", {
value=function() return posx() .. "," .. posy() .. "," .. posz() end,
title="Go to position",
description="Go to position (x,y,z)",
multiline=false,
validation="^\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+),?\\s*([0-9]?)$"
})
registerAction("use", {
value=function() return posx() .. "," .. posy() .. "," .. posz() end,
title="Use",
description="Use item from position (x,y,z) or from inventory (itemId)",
multiline=false
})
registerAction("usewith", "use with", {
value=function() return "itemId," .. posx() .. "," .. posy() .. "," .. posz() end,
title="Use with",
description="Use item at position (itemid,x,y,z)",
multiline=false,
validation="^\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)$"
})
registerAction("say", {
value="text",
title="Say",
description="Enter text to say",
multiline=false
})
registerAction("function", {
title="Edit bot function",
multiline=true,
value=CaveBot.Editor.ExampleFunctions[1][2],
examples=CaveBot.Editor.ExampleFunctions,
width=650
})
ui.autoRecording.onClick = function()
if ui.autoRecording:isOn() then
CaveBot.Recorder.disable()
else
CaveBot.Recorder.enable()
end
end
-- callbacks
onPlayerPositionChange(function(pos)
ui.pos:setText("Position: " .. pos.x .. ", " .. pos.y .. ", " .. pos.z)
end)
ui.pos:setText("Position: " .. posx() .. ", " .. posy() .. ", " .. posz())
end
CaveBot.Editor.show = function()
CaveBot.Editor.ui:show()
end
CaveBot.Editor.hide = function()
CaveBot.Editor.ui:hide()
end
CaveBot.Editor.edit = function(action, value, callback) -- callback = function(action, value)
local params = CaveBot.Editor.Actions[action]
if not params then return end
if not value then
if type(params.value) == 'function' then
value = params.value()
elseif type(params.value) == 'string' then
value = params.value
end
end
UI.EditorWindow(value, params, function(newText)
callback(action, newText)
end)
end

View File

@@ -0,0 +1,44 @@
CaveBotEditorButton < Button
CaveBotEditorPanel < Panel
id: cavebotEditor
visible: false
layout:
type: verticalBox
fit-children: true
Label
id: pos
text-align: center
text: -
Panel
id: buttons
margin-top: 2
layout:
type: grid
cell-size: 86 20
cell-spacing: 1
flow: true
fit-children: true
Label
text: Double click on action from action list to edit it
text-align: center
text-auto-resize: true
text-wrap: true
margin-top: 3
margin-left: 2
margin-right: 2
BotSwitch
id: autoRecording
text: Auto Recording
margin-top: 3
BotButton
margin-top: 3
margin-bottom: 3
text: Documentation
@onClick: g_platform.openUrl("http://bot.otclient.ovh/")

View File

@@ -0,0 +1,94 @@
CaveBot.Editor.ExampleFunctions = {}
local function addExampleFunction(title, text)
return table.insert(CaveBot.Editor.ExampleFunctions, {title, text:trim()})
end
addExampleFunction("Click to browse example functions", [[
-- available functions/variables:
-- prev - result of previous action (true or false)
-- retries - number of retries of current function, goes up by one when you return "retry"
-- delay(number) - delays bot next action, value in milliseconds
-- gotoLabel(string) - goes to specific label, return true if label exists
-- you can easily access bot extensions, Depositer.run() instead of CaveBot.Extensions.Depositer.run()
-- also you can access bot global variables, like CaveBot, TargetBot
-- use storage variable to store date between calls
-- function should return false, true or "retry"
-- if "retry" is returned, function will be executed again in 20 ms (so better call delay before)
return true
]])
addExampleFunction("Check for stamina and imbues", [[
if stamina() < 900 or player:getSkillLevel(11) ~= 100 then CaveBot.setOff() return false else return true end
]])
addExampleFunction("buy 200 mana potion from npc Eryn", [[
--buy 200 mana potions
local npc = getCreatureByName("Eryn")
if not npc then
return false
end
if retries > 10 then
return false
end
local pos = player:getPosition()
local npcPos = npc:getPosition()
if math.max(math.abs(pos.x - npcPos.x), math.abs(pos.y - npcPos.y)) > 3 then
autoWalk(npcPos, {precision=3})
delay(300)
return "retry"
end
if not NPC.isTrading() then
NPC.say("hi")
NPC.say("trade")
delay(200)
return "retry"
end
NPC.buy(268, 100)
schedule(1000, function()
-- buy again in 1s
NPC.buy(268, 100)
NPC.closeTrade()
NPC.say("bye")
end)
delay(1200)
return true
]])
addExampleFunction("Say hello 5 times with some delay", [[
--say hello
if retries > 5 then
return true -- finish
end
say("hello")
delay(100 + retries * 100)
return "retry"
]])
addExampleFunction("Disable TargetBot", [[
TargetBot.setOff()
return true
]])
addExampleFunction("Enable TargetBot", [[
TargetBot.setOn()
return true
]])
addExampleFunction("Enable TargetBot luring", [[
TargetBot.enableLuring()
return true
]])
addExampleFunction("Disable TargetBot luring", [[
TargetBot.disableLuring()
return true
]])
addExampleFunction("Logout", [[
g_game.safeLogout()
delay(1000)
return "retry"
]])

View File

@@ -0,0 +1,58 @@
-- example cavebot extension (remember to add this file to ../cavebot.lua)
CaveBot.Extensions.Example = {}
local ui
-- setup is called automaticly when cavebot is ready
CaveBot.Extensions.Example.setup = function()
ui = UI.createWidget('BotTextEdit')
ui:setText("Hello")
ui.onTextChange = function()
CaveBot.save() -- save new config when you change something
end
-- add custom cavebot action (check out actions.lua)
CaveBot.registerAction("sayhello", "orange", function(value, retries, prev)
local how_many_times = tonumber(value)
if retries >= how_many_times then
return true
end
say("hello " .. (retries + 1))
delay(250)
return "retry"
end)
-- add this custom action to editor (check out editor.lua)
CaveBot.Editor.registerAction("sayhello", "say hello", {
value="5",
title="Say hello",
description="Says hello x times",
validation="[0-9]{1,5}" -- regex, optional
})
end
-- called when cavebot config changes, configData is a table but it can also be nil
CaveBot.Extensions.Example.onConfigChange = function(configName, isEnabled, configData)
if not configData then return end
if configData["text"] then
ui:setText(configData["text"])
end
end
-- called when cavebot is saving config (so when CaveBot.save() is called), should return table or nil
CaveBot.Extensions.Example.onSave = function()
return {text=ui:getText()}
end
-- bellow add you custom functions to be used in cavebot function action
-- an example: return Example.run(retries, prev)
-- there are 2 useful parameters - retries (number) and prev (true/false), check actions.lua and example_functions.lua to learn more
CaveBot.Extensions.Example.run = function(retries, prev)
-- it will say text 10 times with some delay and then continue
if retries > 10 then
return true
end
say(ui:getText() .. " x" .. retries)
delay(100 + retries * 100)
return "retry"
end

View File

@@ -0,0 +1,184 @@
CaveBot.Extensions.InWithdraw = {}
comparePosition = function(pPos, tPos)
return (getDistanceBetween(pPos, tPos) <= 1)
end
local depotIDs = {3497, 3498, 3499, 3500}
storage.stopSearch = false
storage.inboxContainerOpen = false
local i = 1
CaveBot.Extensions.InWithdraw.setup = function()
CaveBot.registerAction("inwithdraw", "#00FFFF", function(value, retries)
local data = string.split(value, ",")
local withdrawId
local count
local itemCount = 0
local depotAmount = 0
if #data ~= 2 then
error("CaveBot[InboxWithdraw]: incorrect withdraw value")
return false
else
withdrawId = tonumber(data[1])
count = tonumber(data[2])
end
for i, container in pairs(getContainers()) do
if not string.find(container:getName():lower(), "inbox") then
for j, item in pairs(container:getItems()) do
if item:getId() == withdrawId then
itemCount = itemCount + item:getCount()
end
end
end
end
if itemCount >= count then
for i, container in pairs(getContainers()) do
if string.find(container:getName():lower(), "your inbox") then
g_game.close(container)
end
end
print("CaveBot[InboxWithdraw]: enough items, proceeding")
return true
end
if retries > 400 then
print("CaveBot[InboxWithdraw]: actions limit reached, proceeding")
return true
end
delay(200)
local tileList = {}
local tPos
local depotClear = false
local depotOpen = false
local depotBoxOpen = false
for _,tile in pairs(g_map.getTiles(posz())) do
for i,thing in pairs(tile:getThings()) do
if table.find(depotIDs, thing:getId()) then
table.insert(tileList, {tileObj = tile, distance = getDistanceBetween(pos(), tile:getPosition()), depotID = thing:getId()})
end
end
end
table.sort(tileList, function(a,b) return a.distance < b.distance end)
::findEmptyDP::
if tileList[i] and not storage.stopSearch then
if tileList[i].depotID == 3498 then
tPos = {x = tileList[i].tileObj:getPosition().x + 1, y = tileList[i].tileObj:getPosition().y, z = tileList[i].tileObj:getPosition().z}
elseif tileList[i].depotID == 3499 then
tPos = {x = tileList[i].tileObj:getPosition().x, y = tileList[i].tileObj:getPosition().y + 1, z = tileList[i].tileObj:getPosition().z}
elseif tileList[i].depotID == 3500 then
tPos = {x = tileList[i].tileObj:getPosition().x - 1, y = tileList[i].tileObj:getPosition().y, z = tileList[i].tileObj:getPosition().z}
elseif tileList[i].depotID == 3497 then
tPos = {x = tileList[i].tileObj:getPosition().x, y = tileList[i].tileObj:getPosition().y - 1, z = tileList[i].tileObj:getPosition().z}
end
if tPos then
local dest = g_map.getTile(tPos)
if not comparePosition(pos(), dest:getPosition()) then
if not dest:getCreatures()[1] and dest:isWalkable() then
if CaveBot.walkTo(dest:getPosition(), {ignoreNonPathable=true}) then
storage.stopSearch = true
delay(100)
end
else
i = i + 1
goto findEmptyDP
end
end
end
end
if tileList[i].tileObj and not table.find(depotIDs, tileList[i].tileObj:getTopLookThing():getId()) and comparePosition(pos(), tileList[i].tileObj:getPosition()) then
for j=1,table.getn(tileList[i].tileObj:getThings()),1 do
if not tileList[i].tileObj:getThings()[j]:isNotMoveable() then
delay(500)
g_game.move(tileList[i].tileObj:getThings()[j], pos(), tileList[i].tileObj:getThings()[j]:getCount())
end
end
if table.find(depotIDs, tileList[i].tileObj:getTopLookThing():getId()) then
depotClear = true
end
else
depotClear = true
end
if depotClear then
for _, container in pairs(g_game.getContainers()) do
if container:getName():lower() == "locker" then
depotOpen = true
end
end
end
if tileList[i].tileObj and depotClear and not depotOpen and not storage.inboxContainerOpen then
delay(500)
g_game.use(tileList[i].tileObj:getTopUseThing())
depotOpen = true
end
i = 1
for _, container in pairs(g_game.getContainers()) do
if container:getName():lower() == "your inbox" then
depotBoxOpen = true
end
end
if depotOpen and not depotBoxOpen then
if findItem(12902) then
delay(500)
g_game.use(findItem(12902))
depotBoxOpen = true
end
end
if depotBoxOpen and not storage.inboxContainerOpen then
for _, container in pairs(g_game.getContainers()) do
if container:getName():lower() == "your" then
storage.inboxContainerOpen = true
end
end
end
delay(500)
for i, container in pairs(getContainers()) do
if string.find(container:getName():lower(), "your") then
for j, item in pairs(container:getItems()) do
if item:getId() == withdrawId then
depotAmount = depotAmount + item:getCount()
end
end
break
end
end
local destination
for i, container in pairs(getContainers()) do
if container:getCapacity() > #container:getItems() and not string.find(container:getName():lower(), "depot") and not string.find(container:getName():lower(), "loot") and not string.find(container:getName():lower(), "inbox") then
destination = container
end
end
if itemCount < count and destination then
for i, container in pairs(getContainers()) do
if string.find(container:getName():lower(), "your inbox") then
for j, item in pairs(container:getItems()) do
if item:getId() == withdrawId then
if item:isStackable() then
g_game.move(item, destination:getSlotPosition(destination:getItemsCount()), math.min(item:getCount(), (count - itemCount)))
return "retry"
else
g_game.move(item, destination:getSlotPosition(destination:getItemsCount()), 1)
return "retry"
end
return "retry"
end
end
end
end
end
return "retry"
end)
CaveBot.Editor.registerAction("inwithdraw", "in withdraw", {
value="id,amount",
title="Withdraw Items",
description="insert item id and amount",
})
end

View File

@@ -0,0 +1,23 @@
CaveBot.Extensions.Lure = {}
CaveBot.Extensions.Lure.setup = function()
CaveBot.registerAction("lure", "#00FFFF", function(value, retries)
if value == "start" then
TargetBot.setOff()
return true
elseif value == "stop" then
TargetBot.setOn()
return true
else
warn("incorrect lure value!")
return false
end
end)
CaveBot.Editor.registerAction("lure", "lure", {
value="start",
title="Lure",
description="start/stop",
multiline=false,
})
end

View File

@@ -0,0 +1,44 @@
CaveBot.Extensions.PosCheck = {}
storage.posCheckRetries = 0
CaveBot.Extensions.PosCheck.setup = function()
CaveBot.registerAction("PosCheck", "#00FFFF", function(value, retries)
local tilePos
local data = string.split(value, ",")
if #data ~= 5 then
error("wrong travel format, should be: label, distance, x, y, z")
return false
end
local tilePos = player:getPosition()
tilePos.x = tonumber(data[3])
tilePos.y = tonumber(data[4])
tilePos.z = tonumber(data[5])
if storage.posCheckRetries > 10 then
storage.posCheckRetries = 0
print("CaveBot[CheckPos]: waypoints locked, too many tries, unclogging cavebot and proceeding")
return false
elseif (tilePos.z == player:getPosition().z) and (getDistanceBetween(player:getPosition(), tilePos) <= tonumber(data[2])) then
storage.posCheckRetries = 0
print("CaveBot[CheckPos]: position reached, proceeding")
return true
else
storage.posCheckRetries = storage.posCheckRetries + 1
CaveBot.gotoLabel(data[1])
print("CaveBot[CheckPos]: position not-reached, going back to label: " .. data[1])
return false
end
end)
CaveBot.Editor.registerAction("poscheck", "pos check", {
value=function() return "label" .. "," .. "distance" .. "," .. posx() .. "," .. posy() .. "," .. posz() end,
title="Location Check",
description="label name, accepted dist from coordinates, x, y, z",
multiline=false,
})
end

View File

@@ -0,0 +1,65 @@
-- auto recording for cavebot
CaveBot.Recorder = {}
local isEnabled = nil
local lastPos = nil
local function setup()
local function addPosition(pos)
CaveBot.addAction("goto", pos.x .. "," .. pos.y .. "," .. pos.z, true)
lastPos = pos
end
onPlayerPositionChange(function(newPos, oldPos)
if CaveBot.isOn() or not isEnabled then return end
if not lastPos then
-- first step
addPosition(oldPos)
elseif newPos.z ~= oldPos.z or math.abs(oldPos.x - newPos.x) > 1 or math.abs(oldPos.y - newPos.y) > 1 then
-- stairs/teleport
addPosition(oldPos)
elseif math.max(math.abs(lastPos.x - newPos.x), math.abs(lastPos.y - newPos.y)) > 5 then
-- 5 steps from last pos
addPosition(newPos)
end
end)
onUse(function(pos, itemId, stackPos, subType)
if CaveBot.isOn() or not isEnabled then return end
if pos.x ~= 0xFFFF then
lastPos = pos
CaveBot.addAction("use", pos.x .. "," .. pos.y .. "," .. pos.z, true)
end
end)
onUseWith(function(pos, itemId, target, subType)
if CaveBot.isOn() or not isEnabled then return end
if not target:isItem() then return end
local targetPos = target:getPosition()
if targetPos.x == 0xFFFF then return end
lastPos = pos
CaveBot.addAction("usewith", itemId .. "," .. targetPos.x .. "," .. targetPos.y .. "," .. targetPos.z, true)
end)
end
CaveBot.Recorder.isOn = function()
return isEnabled
end
CaveBot.Recorder.enable = function()
CaveBot.setOff()
if isEnabled == nil then
setup()
end
CaveBot.Editor.ui.autoRecording:setOn(true)
isEnabled = true
lastPos = nil
end
CaveBot.Recorder.disable = function()
if isEnabled == true then
isEnabled = false
end
CaveBot.Editor.ui.autoRecording:setOn(false)
CaveBot.save()
end

View File

@@ -0,0 +1,68 @@
CaveBot.Extensions.SellAll = {}
storage.sellAllCap = 0
CaveBot.Extensions.SellAll.setup = function()
CaveBot.registerAction("SellAll", "#00FFFF", function(value, retries)
local val = string.split(value, ",")
local wait
if #val > 2 then
warn("CaveBot[SellAll]: incorrect sell all value!")
return false
end
if #val == 2 then
wait = true
else
wait = false
end
local npc = getCreatureByName(value)
if not npc then
print("CaveBot[SellAll]: NPC not found! skipping")
return false
end
if retries > 10 then
print("CaveBot[SellAll]: can't sell, skipping")
return false
end
if freecap() == storage.sellAllCap then
storage.sellAllCap = 0
print("CaveBot[SellAll]: Sold everything, proceeding")
return true
end
delay(800)
local pos = player:getPosition()
local npcPos = npc:getPosition()
if math.max(math.abs(pos.x - npcPos.x), math.abs(pos.y - npcPos.y)) > 3 then
CaveBot.walkTo(npcPos, 20, {ignoreNonPathable = true, precision=3})
delay(300)
return "retry"
end
if not NPC.isTrading() then
NPC.say("hi")
schedule(500, function() NPC.say("trade") end)
else
storage.sellAllCap = freecap()
end
NPC.sellAll(wait)
if #val == 2 then
print("CaveBot[SellAll]: Sold All with delay")
else
print("CaveBot[SellAll]: Sold All without delay")
end
return "retry"
end)
CaveBot.Editor.registerAction("sellall", "sell all", {
value="NPC",
title="Sell All",
description="Insert NPC name, and 'yes' if sell with delay ",
})
end

View File

@@ -0,0 +1,30 @@
CaveBot.Extensions.Supply = {}
local ui
-- first function called, here you should setup your UI
CaveBot.Extensions.Supply.setup = function()
--ui = UI.createWidget('SupplyItemList')
--local widget = UI.createWidget('SupplyItem', ui.list)
--widget.item.onItemChange = function(newItem)
--widget.fields.min.onTextChange = function(newText)
-- make it similar to UI.Container, so if there are no free slots, add another one, keep min 4 slots, check if value min/max is number after edit
end
-- called when cavebot config changes, configData is a table but it can be nil
CaveBot.Extensions.Supply.onConfigChange = function(configName, isEnabled, configData)
if not configData then return end
end
-- called when cavebot is saving config, should return table or nil
CaveBot.Extensions.Supply.onSave = function()
return {}
end
-- bellow add you custom functions
-- this function can be used in cavebot function waypoint as: return Supply.run(retries, prev)
-- there are 2 useful parameters - retries (number) and prev (true/false), check actions.lua to learn more
CaveBot.Extensions.Supply.run = function(retries, prev)
return true
end

View File

@@ -0,0 +1,72 @@
SupplyItem < Panel
height: 34
BotItem
id: item
size: 32 32
anchors.left: parent.left
anchors.top: parent.top
margin-top: 1
Panel
id: fields
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: prev.right
anchors.right: parent.right
margin-left: 2
margin-right: 2
Label
id: minLabel
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.horizontalCenter
margin-right: 2
text-align: center
text: "Min"
Label
id: maxLabel
anchors.top: parent.top
anchors.left: parent.horizontalCenter
anchors.right: parent.right
margin-left: 2
text-align: center
text: "Max"
BotTextEdit
id: min
anchors.top: minLabel.bottom
anchors.left: minLabel.left
anchors.right: minLabel.right
text-align: center
text: 1
BotTextEdit
id: max
anchors.top: maxLabel.bottom
anchors.left: maxLabel.left
anchors.right: maxLabel.right
text-align: center
text: 100
SupplyItemList < Panel
height: 102
ScrollablePanel
id: list
anchors.fill: parent
vertical-scrollbar: scroll
margin-right: 7
layout:
type: verticalBox
cell-height: 34
BotSmallScrollBar
id: scroll
anchors.top: prev.top
anchors.bottom: prev.bottom
anchors.right: parent.right
step: 10
pixels-scroll: true

View File

@@ -0,0 +1,70 @@
CaveBot.Extensions.SupplyCheck = {}
storage.supplyRetries = 0
CaveBot.Extensions.SupplyCheck.setup = function()
CaveBot.registerAction("supplyCheck", "#00FFFF", function(value)
local softCount = itemAmount(6529) + itemAmount(3549)
local totalItem1 = itemAmount(storage[suppliesPanelName].item1)
local totalItem2 = itemAmount(storage[suppliesPanelName].item2)
local totalItem3 = itemAmount(storage[suppliesPanelName].item3)
local totalItem4 = itemAmount(storage[suppliesPanelName].item4)
local totalItem5 = itemAmount(storage[suppliesPanelName].item5)
local totalItem6 = itemAmount(storage[suppliesPanelName].item6)
if storage.supplyRetries > 50 then
print("CaveBot[SupplyCheck]: Round limit reached, going back on refill.")
storage.supplyRetries = 0
return false
elseif (storage[suppliesPanelName].imbues and player:getSkillLevel(11) ~= 100) then
print("CaveBot[SupplyCheck]: Imbues ran out. Going on refill.")
storage.supplyRetries = 0
return false
elseif (storage[suppliesPanelName].staminaSwitch and stamina() < tonumber(storage[suppliesPanelName].staminaValue)) then
print("CaveBot[SupplyCheck]: Stamina ran out. Going on refill.")
storage.supplyRetries = 0
return false
elseif (softCount < 1 and storage[suppliesPanelName].SoftBoots) then
print("CaveBot[SupplyCheck]: No soft boots left. Going on refill.")
storage.supplyRetries = 0
return false
elseif (totalItem1 < tonumber(storage[suppliesPanelName].item1Min) and storage[suppliesPanelName].item1 > 100) then
print("CaveBot[SupplyCheck]: Not enough item: " .. storage[suppliesPanelName].item1 .. "(only " .. totalItem1 .. " left). Going on refill.")
storage.supplyRetries = 0
return false
elseif (totalItem2 < tonumber(storage[suppliesPanelName].item2Min) and storage[suppliesPanelName].item2 > 100) then
print("CaveBot[SupplyCheck]: Not enough item: " .. storage[suppliesPanelName].item2 .. "(only " .. totalItem2 .. " left). Going on refill.")
storage.supplyRetries = 0
return false
elseif (totalItem3 < tonumber(storage[suppliesPanelName].item3Min) and storage[suppliesPanelName].item3 > 100) then
print("CaveBot[SupplyCheck]: Not enough item: " .. storage[suppliesPanelName].item3 .. "(only " .. totalItem3 .. " left). Going on refill.")
storage.supplyRetries = 0
return false
elseif (totalItem4 < tonumber(storage[suppliesPanelName].item4Min) and storage[suppliesPanelName].item4 > 100) then
print("CaveBot[SupplyCheck]: Not enough item: " .. storage[suppliesPanelName].item4 .. "(only " .. totalItem4 .. " left). Going on refill.")
storage.supplyRetries = 0
return false
elseif (totalItem5 < tonumber(storage[suppliesPanelName].item5Min) and storage[suppliesPanelName].item5 > 100) then
print("CaveBot[SupplyCheck]: Not enough item: " .. storage[suppliesPanelName].item5 .. "(only " .. totalItem5 .. " left). Going on refill.")
storage.supplyRetries = 0
return false
elseif (totalItem6 < tonumber(storage[suppliesPanelName].item6Min) and storage[suppliesPanelName].item6 > 100) then
print("CaveBot[SupplyCheck]: Not enough item: " .. storage[suppliesPanelName].item6 .. "(only " .. totalItem6 .. " left). Going on refill.")
storage.supplyRetries = 0
return false
elseif (freecap() < tonumber(storage[suppliesPanelName].capValue) and storage[suppliesPanelName].capSwitch) then
print("CaveBot[SupplyCheck]: Not enough capacity. Going on refill.")
storage.supplyRetries = 0
return false
else
print("CaveBot[SupplyCheck]: Enough supplies. Hunting. Round (" .. storage.supplyRetries .. "/50)")
storage.supplyRetries = storage.supplyRetries + 1
return CaveBot.gotoLabel(value)
end
end)
CaveBot.Editor.registerAction("supplycheck", "supply check", {
value="startHunt",
title="Supply check label",
description="Insert here hunting start label",
})
end

View File

@@ -0,0 +1,52 @@
CaveBot.Extensions.Travel = {}
CaveBot.Extensions.Travel.setup = function()
CaveBot.registerAction("Travel", "#00FFFF", function(value, retries)
local data = string.split(value, ",")
local waitVal = 0
if #data < 2 or #data > 3 then
warn("CaveBot[Travel]: incorrect travel value!")
return false
elseif #data == 3 then
waitVal = tonumber(data[3]:trim())
end
if not waitVal then
warn("CaveBot[Travel]: incorrect travel delay value!")
return false
end
if retries > 5 then
print("CaveBot[Travel]: too many tries, can't travel")
return false
end
local npc = getCreatureByName(data[1]:trim())
if not npc then
print("CaveBot[Travel]: NPC not found, can't travel")
return false
end
local pos = player:getPosition()
local npcPos = npc:getPosition()
if math.max(math.abs(pos.x - npcPos.x), math.abs(pos.y - npcPos.y)) > 3 then
CaveBot.walkTo(npcPos, 20, {ignoreNonPathable = true, precision=3})
delay(300)
return "retry"
end
NPC.say("hi")
schedule(waitVal, function() NPC.say(data[2]:trim()) end)
schedule(2*waitVal, function() NPC.say("yes") end)
delay(3*waitVal)
print("CaveBot[Travel]: travel action finished")
return true
end)
CaveBot.Editor.registerAction("travel", "travel", {
value="NPC name, city",
title="Travel",
description="NPC name, City name, delay in ms(optional)",
})
end

View File

@@ -0,0 +1,93 @@
-- walking
local expectedDirs = {}
local isWalking = {}
local walkPath = {}
local walkPathIter = 0
CaveBot.resetWalking = function()
expectedDirs = {}
walkPath = {}
isWalking = false
end
CaveBot.doWalking = function()
if CaveBot.Config.get("mapClick") then
return false
end
if #expectedDirs == 0 then
return false
end
if #expectedDirs >= 3 then
CaveBot.resetWalking()
end
local dir = walkPath[walkPathIter]
if dir then
g_game.walk(dir, false)
table.insert(expectedDirs, dir)
walkPathIter = walkPathIter + 1
CaveBot.delay(CaveBot.Config.get("walkDelay") + player:getStepDuration(false, dir))
return true
end
return false
end
-- called when player position has been changed (step has been confirmed by server)
onPlayerPositionChange(function(newPos, oldPos)
if not oldPos or not newPos then return end
local dirs = {{NorthWest, North, NorthEast}, {West, 8, East}, {SouthWest, South, SouthEast}}
local dir = dirs[newPos.y - oldPos.y + 2]
if dir then
dir = dir[newPos.x - oldPos.x + 2]
end
if not dir then
dir = 8 -- 8 is invalid dir, it's fine
end
if not isWalking or not expectedDirs[1] then
-- some other walk action is taking place (for example use on ladder), wait
walkPath = {}
CaveBot.delay(CaveBot.Config.get("ping") + player:getStepDuration(false, dir) + 150)
return
end
if expectedDirs[1] ~= dir then
if CaveBot.Config.get("mapClick") then
CaveBot.delay(CaveBot.Config.get("walkDelay") + player:getStepDuration(false, dir))
else
CaveBot.delay(CaveBot.Config.get("mapClickDelay") + player:getStepDuration(false, dir))
end
return
end
table.remove(expectedDirs, 1)
if CaveBot.Config.get("mapClick") and #expectedDirs > 0 then
CaveBot.delay(CaveBot.Config.get("mapClickDelay") + player:getStepDuration(false, dir))
end
end)
CaveBot.walkTo = function(dest, maxDist, params)
local path = getPath(player:getPosition(), dest, maxDist, params)
if not path or not path[1] then
return false
end
local dir = path[1]
if CaveBot.Config.get("mapClick") then
local ret = autoWalk(path)
if ret then
isWalking = true
expectedDirs = path
CaveBot.delay(CaveBot.Config.get("mapClickDelay") + math.max(CaveBot.Config.get("ping") + player:getStepDuration(false, dir), player:getStepDuration(false, dir) * 2))
end
return ret
end
g_game.walk(dir, false)
isWalking = true
walkPath = path
walkPathIter = 2
expectedDirs = { dir }
CaveBot.delay(CaveBot.Config.get("walkDelay") + player:getStepDuration(false, dir))
return true
end

View File

@@ -0,0 +1,221 @@
CaveBot.Extensions.Withdraw = {}
comparePosition = function(pPos, tPos)
return (getDistanceBetween(pPos, tPos) <= 1)
end
local depotContainers = {22797, 22798, 22799, 22800, 22801, 22802, 22803, 22804, 22805, 22806, 22807, 22808, 22809, 22810, 22811, 22812, 22813}
local depotIDs = {3497, 3498, 3499, 3500}
storage.stopSearch = false
storage.lootContainerOpen = false
local i = 1
CaveBot.Extensions.Withdraw.setup = function()
CaveBot.registerAction("withdraw", "#00FFFF", function(value, retries)
local data = string.split(value, ",")
local stashIndex
local withdrawId
local count
local itemCount = 0
local depotAmount
if #data ~= 3 then
warn("incorrect withdraw value")
return false
else
stashIndex = tonumber(data[1])
withdrawId = tonumber(data[2])
count = tonumber(data[3])
end
local withdrawSource = depotContainers[stashIndex]
for i, container in pairs(getContainers()) do
if not string.find(container:getName():lower(), "depot") then
for j, item in pairs(container:getItems()) do
if item:getId() == withdrawId then
itemCount = itemCount + item:getCount()
end
end
end
end
if itemCount >= count then
for i, container in pairs(getContainers()) do
if string.find(container:getName():lower(), "depot box") then
g_game.close(container)
end
end
print("enough items")
return true
end
if retries > 400 then
return true
end
delay(200)
local tileList = {}
local tPos
local depotClear = false
local depotOpen = false
local depotBoxOpen = false
for _,tile in pairs(g_map.getTiles(posz())) do
for i,thing in pairs(tile:getThings()) do
if table.find(depotIDs, thing:getId()) then
table.insert(tileList, {tileObj = tile, distance = getDistanceBetween(pos(), tile:getPosition()), depotID = thing:getId()})
end
end
end
table.sort(tileList, function(a,b) return a.distance < b.distance end)
::findEmptyDP::
if tileList[i] and not storage.stopSearch then
if tileList[i].depotID == 3498 then
tPos = {x = tileList[i].tileObj:getPosition().x + 1, y = tileList[i].tileObj:getPosition().y, z = tileList[i].tileObj:getPosition().z}
elseif tileList[i].depotID == 3499 then
tPos = {x = tileList[i].tileObj:getPosition().x, y = tileList[i].tileObj:getPosition().y + 1, z = tileList[i].tileObj:getPosition().z}
elseif tileList[i].depotID == 3500 then
tPos = {x = tileList[i].tileObj:getPosition().x - 1, y = tileList[i].tileObj:getPosition().y, z = tileList[i].tileObj:getPosition().z}
elseif tileList[i].depotID == 3497 then
tPos = {x = tileList[i].tileObj:getPosition().x, y = tileList[i].tileObj:getPosition().y - 1, z = tileList[i].tileObj:getPosition().z}
end
if tPos then
local dest = g_map.getTile(tPos)
if not comparePosition(pos(), dest:getPosition()) then
if not dest:getCreatures()[1] and dest:isWalkable() then
if CaveBot.walkTo(dest:getPosition(), {ignoreNonPathable=true}) then
storage.stopSearch = true
delay(100)
end
else
i = i + 1
goto findEmptyDP
end
end
end
end
if tileList[i].tileObj and not table.find(depotIDs, tileList[i].tileObj:getTopLookThing():getId()) and comparePosition(pos(), tileList[i].tileObj:getPosition()) then
for j=1,table.getn(tileList[i].tileObj:getThings()),1 do
if not tileList[i].tileObj:getThings()[j]:isNotMoveable() then
delay(500)
g_game.move(tileList[i].tileObj:getThings()[j], pos(), tileList[i].tileObj:getThings()[j]:getCount())
end
end
if table.find(depotIDs, tileList[i].tileObj:getTopLookThing():getId()) then
depotClear = true
end
else
depotClear = true
end
if depotClear then
for _, container in pairs(g_game.getContainers()) do
if container:getName():lower() == "locker" then
depotOpen = true
end
end
end
if tileList[i].tileObj and depotClear and not depotOpen and not storage.lootContainerOpen then
delay(500)
g_game.use(tileList[i].tileObj:getTopUseThing())
depotOpen = true
end
i = 1
--Version Check to know what to do with the depot--
if g_game.getClientVersion() > 910 then
if depotOpen then
for _, container in pairs(g_game.getContainers()) do
if container:getName():lower() == "depot chest" then
depotBoxOpen = true
end
end
if findItem(3502) and not depotBoxOpen then
delay(500)
g_game.use(findItem(3502))
depotBoxOpen = true
end
end
if depotBoxOpen and not storage.lootContainerOpen then
for _, container in pairs(g_game.getContainers()) do
if container:getName():lower() == "depot chest" then
for _, item in ipairs(container:getItems()) do
if item:isContainer() and table.find({22797, 22798}, item:getId()) then
delay(500)
storage.lootContainerOpen = true
break
end
end
break
end
end
end
local boxOpened = false
for _, container in pairs(getContainers()) do
if string.find(container:getName():lower(), "depot box") then
boxOpened = true
end
end
if not boxOpened then
for _, container in pairs(getContainers()) do
if container:getName():lower() == "depot chest" then
for _, item in pairs(container:getItems()) do
if item:getId() == withdrawSource then
g_game.open(item)
break
end
end
end
end
end
for i, container in pairs(getContainers()) do
if string.find(container:getName():lower(), "depot") then
for j, item in pairs(container:getItems()) do
if item:getId() == withdrawId then
depotAmount = depotAmount + item:getCount()
end
end
break
end
end
if depotAmount == 0 then
print("lack of withdraw items!")
return false
end
local destination
for i, container in pairs(getContainers()) do
if container:getCapacity() > #container:getItems() and not string.find(container:getName():lower(), "depot") and not string.find(container:getName():lower(), "loot") and not string.find(container:getName():lower(), "inbox") then
destination = container
end
end
if itemCount < count and destination then
for i, container in pairs(getContainers()) do
if string.find(container:getName():lower(), "depot box") then
for j, item in pairs(container:getItems()) do
if item:getId() == withdrawId then
if item:isStackable() then
g_game.move(item, destination:getSlotPosition(destination:getItemsCount()), math.min(item:getCount(), (count - itemCount)))
return "retry"
else
g_game.move(item, destination:getSlotPosition(destination:getItemsCount()), 1)
return "retry"
end
return "retry"
end
end
end
end
end
return "retry"
end
end)
CaveBot.Editor.registerAction("withdraw", "withdraw", {
value="index,id,amount",
title="Withdraw Items",
description="insert source index, item id and amount",
})
end