diff --git a/modules/corelib/ui/uicombobox.lua b/modules/corelib/ui/uicombobox.lua index 0549764..d3cd16e 100644 --- a/modules/corelib/ui/uicombobox.lua +++ b/modules/corelib/ui/uicombobox.lua @@ -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 diff --git a/modules/game_bot/bot.lua b/modules/game_bot/bot.lua index cb1db55..64d8ea8 100644 --- a/modules/game_bot/bot.lua +++ b/modules/game_bot/bot.lua @@ -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 diff --git a/modules/game_bot/bot.otui b/modules/game_bot/bot.otui index 95fd8ee..30d4a3f 100644 --- a/modules/game_bot/bot.otui +++ b/modules/game_bot/bot.otui @@ -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') diff --git a/modules/game_bot/defaultconfig.lua b/modules/game_bot/defaultconfig.lua index 320b764..d26b58c 100644 --- a/modules/game_bot/defaultconfig.lua +++ b/modules/game_bot/defaultconfig.lua @@ -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) --#other ]=]}, - {}, {}, {} + {}, {}, {}, {} }, enabled = false, selectedConfig = 1 diff --git a/modules/game_bot/executor.lua b/modules/game_bot/executor.lua index aed94dd..e6c43db 100644 --- a/modules/game_bot/executor.lua +++ b/modules/game_bot/executor.lua @@ -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 \ No newline at end of file diff --git a/modules/game_bot/functions/callbacks.lua b/modules/game_bot/functions/callbacks.lua index 683a237..a9ae0b0 100644 --- a/modules/game_bot/functions/callbacks.lua +++ b/modules/game_bot/functions/callbacks.lua @@ -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 diff --git a/modules/game_bot/functions/main.lua b/modules/game_bot/functions/main.lua index 3c3d753..a6d7070 100644 --- a/modules/game_bot/functions/main.lua +++ b/modules/game_bot/functions/main.lua @@ -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 diff --git a/modules/game_bot/functions/map.lua b/modules/game_bot/functions/map.lua index 06386b9..b1246f6 100644 --- a/modules/game_bot/functions/map.lua +++ b/modules/game_bot/functions/map.lua @@ -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 \ No newline at end of file diff --git a/modules/game_bot/functions/player.lua b/modules/game_bot/functions/player.lua index d75d055..ff64637 100644 --- a/modules/game_bot/functions/player.lua +++ b/modules/game_bot/functions/player.lua @@ -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 diff --git a/modules/game_bot/panels/attacking.lua b/modules/game_bot/panels/attacking.lua new file mode 100644 index 0000000..d277e69 --- /dev/null +++ b/modules/game_bot/panels/attacking.lua @@ -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 + diff --git a/modules/game_bot/panels/basic.lua b/modules/game_bot/panels/basic.lua index f9c5135..a936781 100644 --- a/modules/game_bot/panels/basic.lua +++ b/modules/game_bot/panels/basic.lua @@ -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) diff --git a/modules/game_bot/panels/looting.lua b/modules/game_bot/panels/looting.lua new file mode 100644 index 0000000..7794d6f --- /dev/null +++ b/modules/game_bot/panels/looting.lua @@ -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 + diff --git a/modules/game_bot/panels/waypoints.lua b/modules/game_bot/panels/waypoints.lua new file mode 100644 index 0000000..1af947c --- /dev/null +++ b/modules/game_bot/panels/waypoints.lua @@ -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 + diff --git a/modules/game_features/features.lua b/modules/game_features/features.lua index d82cbc1..c542871 100644 --- a/modules/game_features/features.lua +++ b/modules/game_features/features.lua @@ -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 diff --git a/modules/game_shop/shop.lua b/modules/game_shop/shop.lua index 3c1cc1e..be69df0 100644 --- a/modules/game_shop/shop.lua +++ b/modules/game_shop/shop.lua @@ -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) diff --git a/modules/game_textedit/textedit.lua b/modules/game_textedit/textedit.lua index edc2ab0..b17e664 100644 --- a/modules/game_textedit/textedit.lua +++ b/modules/game_textedit/textedit.lua @@ -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 diff --git a/modules/game_textedit/textedit.otui b/modules/game_textedit/textedit.otui index 2d10eec..d4797e8 100644 --- a/modules/game_textedit/textedit.otui +++ b/modules/game_textedit/textedit.otui @@ -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 + diff --git a/otclient_dx.exe b/otclient_dx.exe index 93d7e89..483456d 100644 Binary files a/otclient_dx.exe and b/otclient_dx.exe differ diff --git a/otclient_gl.exe b/otclient_gl.exe index 4b644bf..43138dc 100644 Binary files a/otclient_gl.exe and b/otclient_gl.exe differ diff --git a/otclientv8.log b/otclientv8.log new file mode 100644 index 0000000..402d7eb --- /dev/null +++ b/otclientv8.log @@ -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.. diff --git a/pdb/otclient_dx.pdb b/pdb/otclient_dx.pdb index eacea39..5856c95 100644 Binary files a/pdb/otclient_dx.pdb and b/pdb/otclient_dx.pdb differ diff --git a/pdb/otclient_gl.pdb b/pdb/otclient_gl.pdb index d648f4c..fa5b12c 100644 Binary files a/pdb/otclient_gl.pdb and b/pdb/otclient_gl.pdb differ