mirror of
https://github.com/OTCv8/otclientv8.git
synced 2025-10-18 21:53:26 +02:00
Added waypoints for bot
This commit is contained in:
@@ -108,6 +108,12 @@ function UIComboBox:removeOption(text)
|
||||
end
|
||||
end
|
||||
|
||||
function UIComboBox:clear()
|
||||
self.options = {}
|
||||
self.currentIndex = -1
|
||||
self:setText("")
|
||||
end
|
||||
|
||||
function UIComboBox:onMousePress(mousePos, mouseButton)
|
||||
local menu
|
||||
if self.menuScroll then
|
||||
|
@@ -26,7 +26,13 @@ function init()
|
||||
dofile("defaultconfig")
|
||||
dofile("executor")
|
||||
|
||||
connect(g_game, { onGameStart = online, onGameEnd = offline, onTalk = botOnTalk})
|
||||
connect(g_game, {
|
||||
onGameStart = online,
|
||||
onGameEnd = offline,
|
||||
onTalk = botOnTalk,
|
||||
onUse = botOnUse,
|
||||
onUseWith = botOnUseWith
|
||||
})
|
||||
|
||||
connect(rootWidget, { onKeyDown = botKeyDown,
|
||||
onKeyUp = botKeyUp,
|
||||
@@ -56,6 +62,9 @@ function init()
|
||||
else
|
||||
botConfig = botDefaultConfig
|
||||
end
|
||||
|
||||
botConfig.configs[1].name = botDefaultConfig.configs[1].name
|
||||
botConfig.configs[1].script = botDefaultConfig.configs[1].script
|
||||
|
||||
botButton = modules.client_topmenu.addRightGameToggleButton('botButton',
|
||||
tr('Bot'), '/images/topbuttons/bot', toggle)
|
||||
@@ -136,7 +145,13 @@ function terminate()
|
||||
onKeyUp = botKeyUp,
|
||||
onKeyPress = botKeyPress })
|
||||
|
||||
disconnect(g_game, { onGameStart = online, onGameEnd = offline, onTalk = botOnTalk})
|
||||
disconnect(g_game, {
|
||||
onGameStart = online,
|
||||
onGameEnd = offline,
|
||||
onTalk = botOnTalk,
|
||||
onUse = botOnUse,
|
||||
onUseWith = botOnUseWith
|
||||
})
|
||||
|
||||
disconnect(Tile, { onAddThing = botAddThing, onRemoveThing = botRemoveThing })
|
||||
|
||||
@@ -177,7 +192,7 @@ function online()
|
||||
botButton:show()
|
||||
updateEnabled()
|
||||
if botConfig.enabled then
|
||||
scheduleEvent(refreshConfig, 1)
|
||||
scheduleEvent(refreshConfig, 20)
|
||||
else
|
||||
clearConfig()
|
||||
end
|
||||
@@ -337,7 +352,7 @@ function refreshConfig()
|
||||
end
|
||||
errorOccured = false
|
||||
g_game.enableTileThingLuaCallback(false)
|
||||
local status, result = pcall(function() return executeBot(config.script, config.storage, botTabs, botMsgCallback) end)
|
||||
local status, result = pcall(function() return executeBot(config.script, config.storage, botTabs, botMsgCallback, saveConfig) end)
|
||||
if not status then
|
||||
errorOccured = true
|
||||
statusLabel:setText("Error: " .. tostring(result))
|
||||
@@ -454,3 +469,13 @@ function botCraetureHealthPercentChange(creature, healthPercent)
|
||||
if compiledConfig == nil then return false end
|
||||
safeBotCall(function() compiledConfig.callbacks.onCreatureHealthPercentChange(creature, healthPercent) end)
|
||||
end
|
||||
|
||||
function botOnUse(pos, itemId, stackPos, subType)
|
||||
if compiledConfig == nil then return false end
|
||||
safeBotCall(function() compiledConfig.callbacks.onUse(pos, itemId, stackPos, subType) end)
|
||||
end
|
||||
|
||||
function botOnUseWith(pos, itemId, target, subType)
|
||||
if compiledConfig == nil then return false end
|
||||
safeBotCall(function() compiledConfig.callbacks.onUseWith(pos, itemId, target, subType) end)
|
||||
end
|
||||
|
@@ -33,7 +33,16 @@ BotSeparator < HorizontalSeparator
|
||||
BotPanel < Panel
|
||||
layout:
|
||||
type: verticalBox
|
||||
|
||||
CaveBotLabel < Label
|
||||
background-color: alpha
|
||||
text-offset: 2 0
|
||||
focusable: true
|
||||
|
||||
$focus:
|
||||
background-color: #00000033
|
||||
color: #ffffff
|
||||
|
||||
MiniWindow
|
||||
id: botWindow
|
||||
!text: tr('Bot')
|
||||
|
@@ -1,41 +1,49 @@
|
||||
botDefaultConfig = {
|
||||
configs = {
|
||||
{name = "Example", script = [=[
|
||||
--Example
|
||||
{name = "Default", script = [=[
|
||||
--Default
|
||||
--IMPORTANT
|
||||
--In this config editions are not saved
|
||||
|
||||
--#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 battleTab = addTab("Battle")
|
||||
local caveTab = addTab("Cave")
|
||||
local toolsTab = addTab("Tools")
|
||||
|
||||
local tab3 = addTab("3th tab")
|
||||
addLabel("label1", "Label on 3th tab", tab3)
|
||||
Panels.Turning(tab3)
|
||||
Panels.HealthItem(battleTab)
|
||||
Panels.ManaItem(battleTab)
|
||||
|
||||
local waypoints = Panels.Waypoints(caveTab)
|
||||
local attacking = Panels.Attacking(caveTab)
|
||||
local looting = Panels.Looting(caveTab)
|
||||
|
||||
--#macros
|
||||
|
||||
local helloLabel = addLabel("helloLabel", "", tab2)
|
||||
local helloLabel = addLabel("helloLabel", "")
|
||||
|
||||
macro(1000, "example macro (time)", nil, function()
|
||||
helloLabel:setText("Time from start: " .. now)
|
||||
end, tab2)
|
||||
end)
|
||||
|
||||
macro(1000, "this macro does nothing", nil, function()
|
||||
|
||||
end, toolsTab)
|
||||
|
||||
--#hotkeys
|
||||
|
||||
hotkey("f5", "example hotkey", function()
|
||||
info("Wow, you clicked f5 hotkey")
|
||||
end)
|
||||
|
||||
singlehotkey("f6", "example hotkey2", function()
|
||||
singlehotkey("ctrl+f6", "example hotkey2", function()
|
||||
info("Wow, you clicked f6 singlehotkey")
|
||||
end)
|
||||
|
||||
--#callbacks
|
||||
|
||||
local positionLabel = addLabel("positionLabel", "")
|
||||
@@ -43,9 +51,6 @@ onPlayerPositionChange(function()
|
||||
positionLabel:setText("Pos: " .. posx() .. "," .. posy() .. "," .. posz())
|
||||
end)
|
||||
|
||||
listen(player:getName(), function(text)
|
||||
info("you said: " .. text)
|
||||
end)
|
||||
--#other
|
||||
|
||||
HTTP.getJSON("https://api.ipify.org/?format=json", function(data, err)
|
||||
@@ -53,7 +58,7 @@ HTTP.getJSON("https://api.ipify.org/?format=json", function(data, err)
|
||||
warn("Whoops! Error occured: " .. err)
|
||||
return
|
||||
end
|
||||
info("HTTP: My IP is: " .. tostring(data['ip']))
|
||||
local myIp = data['ip']
|
||||
end)
|
||||
|
||||
|
||||
@@ -204,7 +209,7 @@ end)
|
||||
--#callbacks
|
||||
|
||||
--#other
|
||||
]=]},
|
||||
]=]},
|
||||
{}, {}, {}, {}
|
||||
},
|
||||
enabled = false,
|
||||
|
@@ -1,7 +1,8 @@
|
||||
function executeBot(config, storage, tabs, msgCallback)
|
||||
function executeBot(config, storage, tabs, msgCallback, saveConfigCallback)
|
||||
local context = {}
|
||||
context.tabs = tabs
|
||||
context.panel = context.tabs:addTab("Main", g_ui.createWidget('BotPanel')).tabPanel
|
||||
context.saveConfig = saveConfigCallback
|
||||
|
||||
context.storage = storage
|
||||
if context.storage._macros == nil then
|
||||
@@ -22,7 +23,9 @@ function executeBot(config, storage, tabs, msgCallback)
|
||||
onCreatureAppear = {},
|
||||
onCreatureDisappear = {},
|
||||
onCreaturePositionChange = {},
|
||||
onCreatureHealthPercentChange = {}
|
||||
onCreatureHealthPercentChange = {},
|
||||
onUse = {},
|
||||
onUseWith = {}
|
||||
}
|
||||
|
||||
-- basic functions & classes
|
||||
@@ -36,6 +39,9 @@ function executeBot(config, storage, tabs, msgCallback)
|
||||
context.tr = tr
|
||||
context.json = json
|
||||
context.regexMatch = regexMatch
|
||||
context.getDistanceBetween = function(p1, p2)
|
||||
return math.max(math.abs(p1.x - p2.x), math.abs(p1.y - p2.y))
|
||||
end
|
||||
|
||||
-- classes
|
||||
context.g_resources = g_resources
|
||||
@@ -166,7 +172,17 @@ function executeBot(config, storage, tabs, msgCallback)
|
||||
for i, callback in ipairs(context._callbacks.onCreatureHealthPercentChange) do
|
||||
callback(creature, healthPercent)
|
||||
end
|
||||
end
|
||||
end,
|
||||
onUse = function(pos, itemId, stackPos, subType)
|
||||
for i, callback in ipairs(context._callbacks.onUse) do
|
||||
callback(pos, itemId, stackPos, subType)
|
||||
end
|
||||
end,
|
||||
onUseWith = function(pos, itemId, target, subType)
|
||||
for i, callback in ipairs(context._callbacks.onUseWith) do
|
||||
callback(pos, itemId, target, subType)
|
||||
end
|
||||
end
|
||||
}
|
||||
}
|
||||
end
|
@@ -11,9 +11,10 @@ context.callback = function(callbackType, callback)
|
||||
local callbackData = {}
|
||||
table.insert(context._callbacks[callbackType], function(...)
|
||||
if not callbackData.delay or callbackData.delay < context.now then
|
||||
local prevExecution = context._currentExecution
|
||||
context._currentExecution = callbackData
|
||||
callback(...)
|
||||
context._currentExecution = nil
|
||||
context._currentExecution = prevExecution
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -68,6 +69,16 @@ context.onCreatureHealthPercentChange = function(callback)
|
||||
return context.callback("onCreatureHealthPercentChange", callback)
|
||||
end
|
||||
|
||||
-- onUse(callback) -- callback = function(pos, itemId, stackPos, subType)
|
||||
context.onUse = function(callback)
|
||||
return context.callback("onUse", callback)
|
||||
end
|
||||
|
||||
-- onUseWith(callback) -- callback = function(pos, itemId, target, subType)
|
||||
context.onUseWith = function(callback)
|
||||
return context.callback("onUseWith", callback)
|
||||
end
|
||||
|
||||
|
||||
-- custom callbacks
|
||||
|
||||
|
@@ -52,7 +52,7 @@ context.macro = function(timeout, name, hotkey, callback, parent)
|
||||
local macroData = context._macros[#context._macros]
|
||||
macroData.callback = function()
|
||||
if not macroData.delay or macroData.delay < context.now then
|
||||
context._currentExecution = macroData
|
||||
context._currentExecution = macroData
|
||||
callback()
|
||||
context._currentExecution = nil
|
||||
return true
|
||||
|
@@ -36,4 +36,40 @@ context.getPlayerByName = function(name, multifloor)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
context.findPath = function(startPos, destPos, maxDist, ignoreFields, ignoreCreatures)
|
||||
if type(maxDist) ~= 'number' then
|
||||
maxDist = 100
|
||||
end
|
||||
local complexity = math.min(10000, maxDist * maxDist)
|
||||
local flags = 0
|
||||
if ignoreFields then
|
||||
flags = flags + 4
|
||||
end
|
||||
if ignoreCreatures then
|
||||
flags = flags + 16
|
||||
end
|
||||
return g_map.findPath(startPos, destPos, complexity, flags)
|
||||
end
|
||||
|
||||
context.autoWalk = function(destination, maxDist, ignoreFields, ignoreCreatures)
|
||||
if maxDist == nil then
|
||||
maxDist = 100
|
||||
end
|
||||
if ignoreFields == nil then
|
||||
ignoreFields = false
|
||||
end
|
||||
if ignoreCreatures == nil then
|
||||
ignoreCreatures = false
|
||||
end
|
||||
if context.player:getPosition().z ~= destination.z then
|
||||
return false
|
||||
end
|
||||
local path = context.findPath(context.player:getPosition(), destination, maxDist, ignoreFields, ignoreCreatures)
|
||||
if #path < 1 then
|
||||
return false
|
||||
end
|
||||
g_game.autoWalk(path, context.player:getPosition())
|
||||
return true
|
||||
end
|
@@ -54,7 +54,6 @@ end
|
||||
context.changeOutfit = context.setOutfit
|
||||
context.setSpeed = function(value) context.player:setSpeed(value) end
|
||||
|
||||
context.autoWalk = function(destination) return context.player:autoWalk(destination) end
|
||||
context.walk = function(dir) return modules.game_walking.walk(dir) end
|
||||
context.turn = function(dir) return g_game.turn(dir) end
|
||||
|
||||
|
19
modules/game_bot/panels/attacking.lua
Normal file
19
modules/game_bot/panels/attacking.lua
Normal file
@@ -0,0 +1,19 @@
|
||||
local context = G.botContext
|
||||
local Panels = context.Panels
|
||||
|
||||
Panels.Attacking = function(parent)
|
||||
context.setupUI([[
|
||||
Panel
|
||||
id: attacking
|
||||
height: 150
|
||||
|
||||
BotLabel
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
text: Attacking
|
||||
|
||||
]], parent)
|
||||
|
||||
end
|
||||
|
@@ -195,7 +195,6 @@ Panel
|
||||
ui:setId(panelName)
|
||||
|
||||
ui.item.onItemChange = function(widget)
|
||||
cp("item change")
|
||||
context.storage["healthItem" .. panelId] = widget:getItemId()
|
||||
end
|
||||
ui.item:setItemId(context.storage["healthItem" .. panelId] or 266)
|
||||
|
20
modules/game_bot/panels/looting.lua
Normal file
20
modules/game_bot/panels/looting.lua
Normal file
@@ -0,0 +1,20 @@
|
||||
local context = G.botContext
|
||||
local Panels = context.Panels
|
||||
|
||||
|
||||
Panels.Looting = function(parent)
|
||||
context.setupUI([[
|
||||
Panel
|
||||
id: looting
|
||||
height: 150
|
||||
|
||||
BotLabel
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
text: Looting
|
||||
|
||||
]], parent)
|
||||
|
||||
end
|
||||
|
575
modules/game_bot/panels/waypoints.lua
Normal file
575
modules/game_bot/panels/waypoints.lua
Normal file
@@ -0,0 +1,575 @@
|
||||
local context = G.botContext
|
||||
local Panels = context.Panels
|
||||
|
||||
Panels.Waypoints = function(parent)
|
||||
local ui = context.setupUI([[
|
||||
Panel
|
||||
id: waypoints
|
||||
height: 213
|
||||
|
||||
BotLabel
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
text: Waypoints
|
||||
|
||||
ComboBox
|
||||
id: config
|
||||
anchors.top: prev.bottom
|
||||
anchors.left: parent.left
|
||||
margin-top: 5
|
||||
text-offset: 3 0
|
||||
width: 130
|
||||
|
||||
Button
|
||||
id: enableButton
|
||||
anchors.top: prev.top
|
||||
anchors.left: prev.right
|
||||
anchors.right: parent.right
|
||||
margin-left: 5
|
||||
|
||||
Button
|
||||
margin-top: 1
|
||||
id: add
|
||||
anchors.top: prev.bottom
|
||||
anchors.left: parent.left
|
||||
text: Add
|
||||
width: 60
|
||||
|
||||
Button
|
||||
id: edit
|
||||
anchors.top: prev.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: Edit
|
||||
width: 60
|
||||
|
||||
Button
|
||||
id: remove
|
||||
anchors.top: prev.top
|
||||
anchors.right: parent.right
|
||||
text: Remove
|
||||
width: 60
|
||||
|
||||
TextList
|
||||
id: list
|
||||
anchors.top: prev.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
vertical-scrollbar: listScrollbar
|
||||
margin-right: 15
|
||||
margin-top: 2
|
||||
height: 60
|
||||
focusable: false
|
||||
auto-focus: first
|
||||
|
||||
VerticalScrollBar
|
||||
id: listScrollbar
|
||||
anchors.top: prev.top
|
||||
anchors.bottom: prev.bottom
|
||||
anchors.right: parent.right
|
||||
pixels-scroll: true
|
||||
step: 5
|
||||
|
||||
Label
|
||||
id: pos
|
||||
anchors.top: prev.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
text-align: center
|
||||
margin-top: 2
|
||||
|
||||
Button
|
||||
id: wGoto
|
||||
anchors.top: prev.bottom
|
||||
anchors.left: parent.left
|
||||
text: Goto
|
||||
width: 61
|
||||
margin-top: 1
|
||||
|
||||
Button
|
||||
id: wUse
|
||||
anchors.top: prev.top
|
||||
anchors.left: prev.right
|
||||
text: Use
|
||||
width: 61
|
||||
|
||||
Button
|
||||
id: wUseWith
|
||||
anchors.top: prev.top
|
||||
anchors.left: prev.right
|
||||
text: UseWith
|
||||
width: 61
|
||||
|
||||
Button
|
||||
id: wWait
|
||||
anchors.top: prev.bottom
|
||||
anchors.left: parent.left
|
||||
text: Wait
|
||||
width: 61
|
||||
margin-top: 1
|
||||
|
||||
Button
|
||||
id: wSay
|
||||
anchors.top: prev.top
|
||||
anchors.left: prev.right
|
||||
text: Say
|
||||
width: 61
|
||||
|
||||
Button
|
||||
id: wFunction
|
||||
anchors.top: prev.top
|
||||
anchors.left: prev.right
|
||||
text: Function
|
||||
width: 61
|
||||
|
||||
BotSwitch
|
||||
id: recording
|
||||
anchors.top: prev.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
text: Auto Recording
|
||||
|
||||
]], parent)
|
||||
|
||||
if type(context.storage.cavebot) ~= "table" then
|
||||
context.storage.cavebot = {}
|
||||
end
|
||||
if type(context.storage.cavebot.configs) ~= "table" then
|
||||
context.storage.cavebot.configs = {}
|
||||
end
|
||||
|
||||
local getConfigName = function(config)
|
||||
local matches = regexMatch(config, [[name:\s*([^\n]*)$]])
|
||||
if matches[1] and matches[1][2] then
|
||||
return matches[1][2]:trim()
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local isValidCommand = function(command)
|
||||
if command == "goto" then
|
||||
return true
|
||||
elseif command == "use" then
|
||||
return true
|
||||
elseif command == "usewith" then
|
||||
return true
|
||||
elseif command == "wait" then
|
||||
return true
|
||||
elseif command == "say" then
|
||||
return true
|
||||
elseif command == "function" then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local commands = {}
|
||||
local waitTo = 0
|
||||
local autoRecording = false
|
||||
|
||||
local parseConfig = function(config)
|
||||
commands = {}
|
||||
local matches = regexMatch(config, [[\s*([^:^\n]+)(:?)([^\n]*)]])
|
||||
for i=1,#matches do
|
||||
local command = matches[i][2]
|
||||
local validation = (matches[i][3] == ":")
|
||||
if not validation or isValidCommand(command) then
|
||||
local text = matches[i][4]
|
||||
if validation then
|
||||
table.insert(commands, {command=command:lower(), text=text})
|
||||
elseif #commands > 0 then
|
||||
commands[#commands].text = commands[#commands].text .. "\n" .. command
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for i=1,#commands do
|
||||
local label = g_ui.createWidget("CaveBotLabel", ui.list)
|
||||
label:setText(commands[i].command .. ":" .. commands[i].text)
|
||||
end
|
||||
end
|
||||
|
||||
local ignoreOnOptionChange = true
|
||||
local refreshConfig = function(scrollDown)
|
||||
ignoreOnOptionChange = true
|
||||
if context.storage.cavebot.enabled then
|
||||
autoRecording = false
|
||||
ui.recording:setOn(false)
|
||||
ui.enableButton:setText("On")
|
||||
ui.enableButton:setColor('#00AA00FF')
|
||||
else
|
||||
ui.enableButton:setText("Off")
|
||||
ui.enableButton:setColor('#FF0000FF')
|
||||
ui.recording:setOn(autoRecording)
|
||||
end
|
||||
|
||||
ui.config:clear()
|
||||
for i, config in ipairs(context.storage.cavebot.configs) do
|
||||
local name = getConfigName(config)
|
||||
if not name then
|
||||
name = "Unnamed config"
|
||||
end
|
||||
ui.config:addOption(name)
|
||||
end
|
||||
|
||||
if not context.storage.cavebot.activeConfig and #context.storage.cavebot.configs > 0 then
|
||||
context.storage.cavebot.activeConfig = 1
|
||||
end
|
||||
|
||||
ui.list:destroyChildren()
|
||||
|
||||
if context.storage.cavebot.activeConfig then
|
||||
ui.config:setCurrentIndex(context.storage.cavebot.activeConfig)
|
||||
parseConfig(context.storage.cavebot.configs[context.storage.cavebot.activeConfig])
|
||||
end
|
||||
|
||||
context.saveConfig()
|
||||
if scrollDown and ui.list:getLastChild() then
|
||||
ui.list:focusChild(ui.list:getLastChild())
|
||||
end
|
||||
|
||||
waitTo = 0
|
||||
ignoreOnOptionChange = false
|
||||
end
|
||||
|
||||
|
||||
ui.config.onOptionChange = function(widget)
|
||||
if not ignoreOnOptionChange then
|
||||
context.storage.cavebot.activeConfig = widget.currentIndex
|
||||
refreshConfig()
|
||||
end
|
||||
end
|
||||
ui.enableButton.onClick = function()
|
||||
if not context.storage.cavebot.activeConfig or not context.storage.cavebot.configs[context.storage.cavebot.activeConfig] then
|
||||
return
|
||||
end
|
||||
context.storage.cavebot.enabled = not context.storage.cavebot.enabled
|
||||
refreshConfig()
|
||||
end
|
||||
ui.add.onClick = function()
|
||||
modules.game_textedit.multilineEditor("Waypoints editor", "name:Config name\n", function(newText)
|
||||
table.insert(context.storage.cavebot.configs, newText)
|
||||
context.storage.cavebot.activeConfig = #context.storage.cavebot.configs
|
||||
refreshConfig()
|
||||
end)
|
||||
end
|
||||
ui.edit.onClick = function()
|
||||
if not context.storage.cavebot.activeConfig or not context.storage.cavebot.configs[context.storage.cavebot.activeConfig] then
|
||||
return
|
||||
end
|
||||
modules.game_textedit.multilineEditor("Waypoints editor", context.storage.cavebot.configs[context.storage.cavebot.activeConfig], function(newText)
|
||||
context.storage.cavebot.configs[context.storage.cavebot.activeConfig] = newText
|
||||
refreshConfig()
|
||||
end)
|
||||
end
|
||||
ui.remove.onClick = function()
|
||||
if not context.storage.cavebot.activeConfig or not context.storage.cavebot.configs[context.storage.cavebot.activeConfig] then
|
||||
return
|
||||
end
|
||||
context.storage.cavebot.enabled = false
|
||||
table.remove(context.storage.cavebot.configs, context.storage.cavebot.activeConfig)
|
||||
context.storage.cavebot.activeConfig = 0
|
||||
refreshConfig()
|
||||
end
|
||||
|
||||
-- waypoint editor
|
||||
-- auto recording
|
||||
local stepsSincleLastPos = 0
|
||||
|
||||
context.onPlayerPositionChange(function(newPos, oldPos)
|
||||
ui.pos:setText("Position: " .. newPos.x .. ", " .. newPos.y .. ", " .. newPos.z)
|
||||
if not autoRecording then
|
||||
return
|
||||
end
|
||||
if not context.storage.cavebot.activeConfig or not context.storage.cavebot.configs[context.storage.cavebot.activeConfig] then
|
||||
return
|
||||
end
|
||||
local newText = ""
|
||||
if newPos.z ~= oldPos.z then
|
||||
newText = "goto:" .. oldPos.x .. "," .. oldPos.y .. "," .. oldPos.z
|
||||
if #commands > 0 then
|
||||
local lastCommand = commands[#commands].command .. ":" .. commands[#commands].text
|
||||
if lastCommand == newText then
|
||||
return
|
||||
end
|
||||
end
|
||||
stepsSincleLastPos = 0
|
||||
else
|
||||
stepsSincleLastPos = stepsSincleLastPos + 1
|
||||
if stepsSincleLastPos > 10 then
|
||||
newText = "goto:" .. oldPos.x .. "," .. oldPos.y .. "," .. oldPos.z
|
||||
stepsSincleLastPos = 0
|
||||
end
|
||||
end
|
||||
|
||||
if newText:len() > 0 then
|
||||
context.storage.cavebot.configs[context.storage.cavebot.activeConfig] = context.storage.cavebot.configs[context.storage.cavebot.activeConfig] .. "\n" .. newText
|
||||
refreshConfig(true)
|
||||
end
|
||||
end)
|
||||
|
||||
context.onUse(function(pos, itemId, stackPos, subType)
|
||||
if not autoRecording then
|
||||
return
|
||||
end
|
||||
if not context.storage.cavebot.activeConfig or not context.storage.cavebot.configs[context.storage.cavebot.activeConfig] then
|
||||
return
|
||||
end
|
||||
if pos.x == 0xFFFF then
|
||||
return
|
||||
end
|
||||
stepsSincleLastPos = 0
|
||||
newText = "use:" .. pos.x .. "," .. pos.y .. "," .. pos.z
|
||||
context.storage.cavebot.configs[context.storage.cavebot.activeConfig] = context.storage.cavebot.configs[context.storage.cavebot.activeConfig] .. "\n" .. newText
|
||||
refreshConfig(true)
|
||||
end)
|
||||
context.onUseWith(function(pos, itemId, target, subType)
|
||||
if not autoRecording then
|
||||
return
|
||||
end
|
||||
if not context.storage.cavebot.activeConfig or not context.storage.cavebot.configs[context.storage.cavebot.activeConfig] then
|
||||
return
|
||||
end
|
||||
if not target:isItem() then
|
||||
return
|
||||
end
|
||||
local targetPos = target:getPosition()
|
||||
if targetPos.x == 0xFFFF then
|
||||
return
|
||||
end
|
||||
stepsSincleLastPos = 0
|
||||
newText = "usewith:" .. itemId .. "," .. targetPos.x .. "," .. targetPos.y .. "," .. targetPos.z
|
||||
context.storage.cavebot.configs[context.storage.cavebot.activeConfig] = context.storage.cavebot.configs[context.storage.cavebot.activeConfig] .. "\n" .. newText
|
||||
refreshConfig(true)
|
||||
end)
|
||||
|
||||
-- ui
|
||||
local pos = context.player:getPosition()
|
||||
ui.pos:setText("Position: " .. pos.x .. ", " .. pos.y .. ", " .. pos.z)
|
||||
|
||||
ui.wGoto.onClick = function()
|
||||
if not context.storage.cavebot.activeConfig or not context.storage.cavebot.configs[context.storage.cavebot.activeConfig] then
|
||||
return
|
||||
end
|
||||
local pos = context.player:getPosition()
|
||||
modules.game_textedit.singlelineEditor("" .. pos.x .. "," .. pos.y .. "," .. pos.z, function(newText)
|
||||
context.storage.cavebot.configs[context.storage.cavebot.activeConfig] = context.storage.cavebot.configs[context.storage.cavebot.activeConfig] .. "\ngoto:" .. newText
|
||||
refreshConfig(true)
|
||||
end)
|
||||
end
|
||||
|
||||
ui.wUse.onClick = function()
|
||||
if not context.storage.cavebot.activeConfig or not context.storage.cavebot.configs[context.storage.cavebot.activeConfig] then
|
||||
return
|
||||
end
|
||||
local pos = context.player:getPosition()
|
||||
modules.game_textedit.singlelineEditor("" .. pos.x .. "," .. pos.y .. "," .. pos.z, function(newText)
|
||||
context.storage.cavebot.configs[context.storage.cavebot.activeConfig] = context.storage.cavebot.configs[context.storage.cavebot.activeConfig] .. "\nuse:" .. newText
|
||||
refreshConfig(true)
|
||||
end)
|
||||
end
|
||||
|
||||
ui.wUseWith.onClick = function()
|
||||
if not context.storage.cavebot.activeConfig or not context.storage.cavebot.configs[context.storage.cavebot.activeConfig] then
|
||||
return
|
||||
end
|
||||
local pos = context.player:getPosition()
|
||||
modules.game_textedit.singlelineEditor("ITEMID," .. pos.x .. "," .. pos.y .. "," .. pos.z, function(newText)
|
||||
context.storage.cavebot.configs[context.storage.cavebot.activeConfig] = context.storage.cavebot.configs[context.storage.cavebot.activeConfig] .. "\nusewith:" .. newText
|
||||
refreshConfig(true)
|
||||
end)
|
||||
end
|
||||
|
||||
ui.wWait.onClick = function()
|
||||
if not context.storage.cavebot.activeConfig or not context.storage.cavebot.configs[context.storage.cavebot.activeConfig] then
|
||||
return
|
||||
end
|
||||
modules.game_textedit.singlelineEditor("1000", function(newText)
|
||||
context.storage.cavebot.configs[context.storage.cavebot.activeConfig] = context.storage.cavebot.configs[context.storage.cavebot.activeConfig] .. "\nwait:" .. newText
|
||||
refreshConfig(true)
|
||||
end)
|
||||
end
|
||||
|
||||
ui.wSay.onClick = function()
|
||||
if not context.storage.cavebot.activeConfig or not context.storage.cavebot.configs[context.storage.cavebot.activeConfig] then
|
||||
return
|
||||
end
|
||||
modules.game_textedit.singlelineEditor("text", function(newText)
|
||||
context.storage.cavebot.configs[context.storage.cavebot.activeConfig] = context.storage.cavebot.configs[context.storage.cavebot.activeConfig] .. "\nsay:" .. newText
|
||||
refreshConfig(true)
|
||||
end)
|
||||
end
|
||||
|
||||
ui.wFunction.onClick = function()
|
||||
if not context.storage.cavebot.activeConfig or not context.storage.cavebot.configs[context.storage.cavebot.activeConfig] then
|
||||
return
|
||||
end
|
||||
modules.game_textedit.multilineEditor("Add function", "function(waypoints)\n --your lua code\n\n -- must return true to execute next command, othwerwise will run in loop till correct return\n return true\nend", function(newText)
|
||||
context.storage.cavebot.configs[context.storage.cavebot.activeConfig] = context.storage.cavebot.configs[context.storage.cavebot.activeConfig] .. "\nfunction:" .. newText
|
||||
refreshConfig(true)
|
||||
end)
|
||||
end
|
||||
|
||||
ui.recording.onClick = function()
|
||||
if not context.storage.cavebot.activeConfig or not context.storage.cavebot.configs[context.storage.cavebot.activeConfig] then
|
||||
return
|
||||
end
|
||||
autoRecording = not autoRecording
|
||||
if autoRecording then
|
||||
context.storage.cavebot.enabled = false
|
||||
stepsSincleLastPos = 10
|
||||
end
|
||||
refreshConfig(true)
|
||||
end
|
||||
|
||||
refreshConfig()
|
||||
|
||||
local functions = {
|
||||
enable = function()
|
||||
context.storage.cavebot.enabled = true
|
||||
refreshConfig()
|
||||
end,
|
||||
disable = function()
|
||||
context.storage.cavebot.enabled = false
|
||||
refreshConfig()
|
||||
end,
|
||||
refresh = function()
|
||||
refreshConfig()
|
||||
end
|
||||
}
|
||||
|
||||
local executeNextMacroCall = false
|
||||
local commandExecutionNo = 0
|
||||
local lastGotoSuccesful = true
|
||||
|
||||
context.macro(250, function()
|
||||
if not context.storage.cavebot.enabled then
|
||||
return
|
||||
end
|
||||
|
||||
if context.player:isWalking() then
|
||||
executeNextMacroCall = false
|
||||
return
|
||||
end
|
||||
|
||||
if not executeNextMacroCall then
|
||||
executeNextMacroCall = true
|
||||
return
|
||||
end
|
||||
executeNextMacroCall = false
|
||||
|
||||
local commandWidget = ui.list:getFocusedChild()
|
||||
if not commandWidget then
|
||||
if ui.list:getFirstChild() then
|
||||
ui.list:focusChild(ui.list:getFirstChild())
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local commandIndex = ui.list:getChildIndex(commandWidget)
|
||||
local command = commands[commandIndex]
|
||||
if not command then
|
||||
if ui.list:getFirstChild() then
|
||||
ui.list:focusChild(ui.list:getFirstChild())
|
||||
end
|
||||
return
|
||||
end
|
||||
if command.command == "goto" then
|
||||
local matches = regexMatch(command.text, [[([0-9]+)[^0-9]+([0-9]+)[^0-9]+([0-9]+)]])
|
||||
if #matches == 1 and #matches[1] == 4 then
|
||||
local position = {x=tonumber(matches[1][2]), y=tonumber(matches[1][3]), z=tonumber(matches[1][4])}
|
||||
local distance = context.getDistanceBetween(position, context.player:getPosition())
|
||||
if distance > 0 and position.z == context.player:getPosition().z then
|
||||
commandExecutionNo = commandExecutionNo + 1
|
||||
lastGotoSuccesful = false
|
||||
if commandExecutionNo <= 3 then -- try max 3 times
|
||||
if not context.autoWalk(position, 100 + distance * 2, commandExecutionNo > 1, false) then
|
||||
context.autoWalk(position, 100 + distance * 2, true, true)
|
||||
context.delay(500)
|
||||
return
|
||||
end
|
||||
return
|
||||
elseif commandExecutionNo == 4 then -- try last time, location close to destination
|
||||
position.x = position.x + math.random(-1, 1)
|
||||
position.y = position.y + math.random(-1, 1)
|
||||
if context.autoWalk(position, 100 + distance * 2, true) then
|
||||
return
|
||||
end
|
||||
elseif distance < 2 then
|
||||
lastGotoSuccesful = true
|
||||
end
|
||||
else
|
||||
lastGotoSuccesful = (position.z == context.player:getPosition().z)
|
||||
end
|
||||
else
|
||||
context.error("Waypoints: invalid use of goto function")
|
||||
end
|
||||
elseif command.command == "use" then
|
||||
local matches = regexMatch(command.text, [[([0-9]+)[^0-9]+([0-9]+)[^0-9]+([0-9]+)]])
|
||||
if #matches == 1 and #matches[1] == 4 then
|
||||
local position = {x=tonumber(matches[1][2]), y=tonumber(matches[1][3]), z=tonumber(matches[1][4])}
|
||||
if context.player:getPosition().z == position.z then
|
||||
local tile = g_map.getTile(position)
|
||||
if tile then
|
||||
local topThing = tile:getTopUseThing()
|
||||
if topThing then
|
||||
g_game.use(topThing)
|
||||
context.delay(500)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
context.error("Waypoints: invalid use of use function")
|
||||
end
|
||||
elseif command.command == "usewith" then
|
||||
local matches = regexMatch(command.text, [[([0-9]+)[^0-9]+([0-9]+)[^0-9]+([0-9]+)[^0-9]+([0-9]+)]])
|
||||
if #matches == 1 and #matches[1] == 5 then
|
||||
local itemId = tonumber(matches[1][2])
|
||||
local position = {x=tonumber(matches[1][3]), y=tonumber(matches[1][4]), z=tonumber(matches[1][5])}
|
||||
if context.player:getPosition().z == position.z then
|
||||
local tile = g_map.getTile(position)
|
||||
if tile then
|
||||
local topThing = tile:getTopUseThing()
|
||||
if topThing then
|
||||
context.useWith(itemId, topThing)
|
||||
context.delay(500)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
context.error("Waypoints: invalid use of usewith function")
|
||||
end
|
||||
elseif command.command == "wait" and lastGotoSuccesful then
|
||||
if not waitTo or waitTo == 0 then
|
||||
waitTo = context.now + tonumber(command.text)
|
||||
end
|
||||
if context.now < waitTo then
|
||||
return
|
||||
end
|
||||
waitTo = 0
|
||||
elseif command.command == "say" and lastGotoSuccesful then
|
||||
context.say(command.text)
|
||||
elseif command.command == "function" and lastGotoSuccesful then
|
||||
local status, result = pcall(function()
|
||||
return assert(load("return " .. command.text, nil, nil, context))()(functions)
|
||||
end)
|
||||
if not status then
|
||||
context.error("Waypoints function execution error:\n" .. result)
|
||||
context.delay(2500)
|
||||
end
|
||||
if not result then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local nextIndex = 1 + commandIndex % #commands
|
||||
local nextChild = ui.list:getChildByIndex(nextIndex)
|
||||
if nextChild then
|
||||
ui.list:focusChild(nextChild)
|
||||
commandExecutionNo = 0
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
return functions
|
||||
end
|
@@ -11,7 +11,7 @@ function updateFeatures(version)
|
||||
|
||||
-- you can add custom features here, list of them in modules\gamelib\const.lua
|
||||
g_game.enableFeature(GameBot)
|
||||
--g_game.enableFeature(GameMinimapLimitedToSingleFloor)
|
||||
g_game.enableFeature(GameMinimapLimitedToSingleFloor)
|
||||
--g_game.enableFeature(GameSpritesAlphaChannel)
|
||||
|
||||
if(version >= 770) then
|
||||
|
@@ -35,7 +35,7 @@ function init()
|
||||
end
|
||||
|
||||
function terminate()
|
||||
disconnect(g_game, { onGameEnd = hide })
|
||||
disconnect(g_game, { onGameStart = check, onGameEnd = hide })
|
||||
|
||||
ProtocolGame.unregisterExtendedOpcode(SHOP_EXTENTED_OPCODE, onExtendedOpcode)
|
||||
|
||||
|
@@ -51,6 +51,64 @@ function show(widget)
|
||||
activeWindow:focus()
|
||||
end
|
||||
|
||||
function singlelineEditor(text, callback)
|
||||
if activeWindow then
|
||||
destroyWindow()
|
||||
end
|
||||
local window = g_ui.createWidget('TextEditWindow', rootWidget)
|
||||
|
||||
local destroy = function()
|
||||
window:destroy()
|
||||
if window == activeWindow then
|
||||
activeWindow = nil
|
||||
end
|
||||
end
|
||||
|
||||
window.okButton.onClick = function()
|
||||
local text = window.text:getText()
|
||||
destroy()
|
||||
callback(text)
|
||||
end
|
||||
window.cancelButton.onClick = destroy
|
||||
window.onEscape = destroy
|
||||
window.onEnter = window.okButton.onClick
|
||||
|
||||
window.text:setText(text)
|
||||
|
||||
activeWindow = window
|
||||
activeWindow:raise()
|
||||
activeWindow:focus()
|
||||
end
|
||||
|
||||
function multilineEditor(description, text, callback)
|
||||
if activeWindow then
|
||||
destroyWindow()
|
||||
end
|
||||
local window = g_ui.createWidget('TextEditMultilineWindow', rootWidget)
|
||||
|
||||
local destroy = function()
|
||||
window:destroy()
|
||||
if window == activeWindow then
|
||||
activeWindow = nil
|
||||
end
|
||||
end
|
||||
|
||||
window.okButton.onClick = function()
|
||||
local text = window.text:getText()
|
||||
destroy()
|
||||
callback(text)
|
||||
end
|
||||
window.cancelButton.onClick = destroy
|
||||
window.onEscape = destroy
|
||||
|
||||
window.description:setText(description)
|
||||
window.text:setText(text)
|
||||
|
||||
activeWindow = window
|
||||
activeWindow:raise()
|
||||
activeWindow:focus()
|
||||
end
|
||||
|
||||
function hide()
|
||||
destroyWindow()
|
||||
end
|
||||
|
@@ -23,3 +23,51 @@ TextEditWindow < MainWindow
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
width: 60
|
||||
|
||||
TextEditMultilineWindow < MainWindow
|
||||
id: texteditmultiline
|
||||
size: 650 497
|
||||
!text: tr("Edit text")
|
||||
|
||||
Label
|
||||
id: description
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
text-auto-resize: true
|
||||
text-align: center
|
||||
text-wrap: true
|
||||
|
||||
MultilineTextEdit
|
||||
id: text
|
||||
anchors.top: textScroll.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: textScroll.left
|
||||
anchors.bottom: textScroll.bottom
|
||||
vertical-scrollbar: textScroll
|
||||
text-wrap: true
|
||||
|
||||
VerticalScrollBar
|
||||
id: textScroll
|
||||
anchors.top: description.bottom
|
||||
anchors.bottom: okButton.top
|
||||
anchors.right: parent.right
|
||||
margin-bottom: 10
|
||||
step: 16
|
||||
pixels-scroll: true
|
||||
|
||||
Button
|
||||
id: okButton
|
||||
!text: tr('Ok')
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: next.left
|
||||
margin-right: 10
|
||||
width: 60
|
||||
|
||||
Button
|
||||
id: cancelButton
|
||||
!text: tr('Cancel')
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
width: 60
|
||||
|
||||
|
BIN
otclient_dx.exe
BIN
otclient_dx.exe
Binary file not shown.
BIN
otclient_gl.exe
BIN
otclient_gl.exe
Binary file not shown.
7
otclientv8.log
Normal file
7
otclientv8.log
Normal file
@@ -0,0 +1,7 @@
|
||||
GPU ANGLE (Intel(R) UHD Graphics 620 Direct3D9Ex vs_3_0 ps_3_0)
|
||||
OpenGL OpenGL ES 2.0 (ANGLE 2.1.a502c749b249)
|
||||
== application started at Nov 01 2019 03:27:53
|
||||
OTClientV8 0.999 beta rev 0 (alpha) made by otclient.ovh built on Oct 31 2019 for arch x86
|
||||
[Atlas] Texture size is: 4096x4096 (max: 8192x8192)
|
||||
Login to otclient.ovh:7172
|
||||
Exiting application..
|
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user