mirror of
https://github.com/OTCv8/otclientv8.git
synced 2025-05-02 20:19:21 +02:00
340 lines
10 KiB
Lua
340 lines
10 KiB
Lua
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 warn("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 warn("Invalid cavebot action: " .. action)
|
|
end
|
|
|
|
if not widget.action or not widget.value then
|
|
return warn("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 warn("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("follow", "#FF8400", function(value, retries, prev)
|
|
local c = getCreatureByName(value)
|
|
if not c then
|
|
print("CaveBot[follow]: can't find creature to follow")
|
|
return false
|
|
end
|
|
local cpos = c:getPosition()
|
|
local pos = pos()
|
|
if getDistanceBetween(cpos, pos) < 2 then
|
|
g_game.cancelFollow()
|
|
return true
|
|
else
|
|
follow(c)
|
|
delay(200)
|
|
return "retry"
|
|
end
|
|
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() warn('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
|
|
warn("warn 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
|
|
warn("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 then
|
|
if 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
|
|
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(3000, 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
|
|
warn("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
|
|
warn("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)
|
|
CaveBot.registerAction("npcsay", "#FF55FF", function(value, retries, prev)
|
|
NPC.say(value)
|
|
return true
|
|
end)
|