diff --git a/data/images/bars/health1.png b/data/images/bars/health1.png new file mode 100644 index 0000000..41579ba Binary files /dev/null and b/data/images/bars/health1.png differ diff --git a/data/images/bars/mana1.png b/data/images/bars/mana1.png new file mode 100644 index 0000000..c635dd5 Binary files /dev/null and b/data/images/bars/mana1.png differ diff --git a/modules/game_bot/default_configs/vBot/0_AAmain.lua b/modules/game_bot/default_configs/vBot/0_AAmain.lua new file mode 100644 index 0000000..3552668 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/0_AAmain.lua @@ -0,0 +1,4 @@ +-- main tab +UI.Label("vBot 1.3 \n Vithrax#5814") +UI.Button("Official OTCv8 Discord!", function() g_platform.openUrl("https://discord.gg/yhqBE4A") end) +UI.Separator() \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/0_BotSever.lua b/modules/game_bot/default_configs/vBot/0_BotSever.lua new file mode 100644 index 0000000..55e1604 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/0_BotSever.lua @@ -0,0 +1,147 @@ +setDefaultTab("Main") + +BotPanelName = "BOTserver" +local ui = setupUI([[ +Panel + height: 18 + + Button + id: botServer + anchors.left: parent.left + anchors.right: parent.right + text-align: center + height: 18 + !text: tr('BotServer') +]]) +ui:setId(BotPanelName) + +if not storage[BotPanelName] then +storage[BotPanelName] = { + manaInfo = true, + mwallInfo = true +} +end + +if not storage.BotServerChannel then + storage.BotServerChannel = tostring(math.random(1000000000000,9999999999999)) +end + +local channel = tostring(storage.BotServerChannel) +BotServer.init(name(), channel) + +rootWidget = g_ui.getRootWidget() +if rootWidget then + botServerWindow = g_ui.createWidget('BotServerWindow', rootWidget) + botServerWindow:hide() + + + botServerWindow.Data.Channel:setText(storage.BotServerChannel) + botServerWindow.Data.Channel.onTextChange = function(widget, text) + storage.BotServerChannel = text + end + + botServerWindow.Data.Random.onClick = function(widget) + storage.BotServerChannel = tostring(math.random(1000000000000,9999999999999)) + botServerWindow.Data.Channel:setText(storage.BotServerChannel) + end + + botServerWindow.Features.Feature1:setOn(storage[BotPanelName].manaInfo) + botServerWindow.Features.Feature1.onClick = function(widget) + storage[BotPanelName].manaInfo = not storage[BotPanelName].manaInfo + widget:setOn(storage[BotPanelName].manaInfo) + end + + botServerWindow.Features.Feature2:setOn(storage[BotPanelName].mwallInfo) + botServerWindow.Features.Feature2.onClick = function(widget) + storage[BotPanelName].mwallInfo = not storage[BotPanelName].mwallInfo + widget:setOn(storage[BotPanelName].mwallInfo) + end +end + +function updateStatusText() + if BotServer._websocket then + botServerWindow.Data.ServerStatus:setText("CONNECTED") + if serverCount then + botServerWindow.Data.Participants:setText(#serverCount) + end + else + botServerWindow.Data.ServerStatus:setText("DISCONNECTED") + botServerWindow.Data.Participants:setText("-") + end +end + +macro(2000, function() + if BotServer._websocket then + BotServer.send("list") + end + updateStatusText() +end) + +local regex = [["(.*?)"]] +BotServer.listen("list", function(name, data) + serverCount = regexMatch(json.encode(data), regex) + storage.serverMembers = json.encode(data) +end) + +ui.botServer.onClick = function(widget) + botServerWindow:show() + botServerWindow:raise() + botServerWindow:focus() +end + +botServerWindow.closeButton.onClick = function(widget) + botServerWindow:hide() +end + + +-- scripts + +storage[BotPanelName].mwalls = {} +BotServer.listen("mwall", function(name, message) + if storage[BotPanelName].mwallInfo then + if not storage[BotPanelName].mwalls[message["pos"]] or storage[BotPanelName].mwalls[message["pos"]] < now then + storage[BotPanelName].mwalls[message["pos"]] = now + message["duration"] - 150 -- 150 is latency correction + end + end +end) + +BotServer.listen("mana", function(name, message) + if storage[BotPanelName].manaInfo then + local creature = getPlayerByName(name) + if creature then + creature:setManaPercent(message["mana"]) + end + end +end) + +onAddThing(function(tile, thing) + if storage[BotPanelName].mwallInfo then + if thing:isItem() and thing:getId() == 2129 then + local pos = tile:getPosition().x .. "," .. tile:getPosition().y .. "," .. tile:getPosition().z + if not storage[BotPanelName].mwalls[pos] or storage[BotPanelName].mwalls[pos] < now then + storage[BotPanelName].mwalls[pos] = now + 20000 + BotServer.send("mwall", {pos=pos, duration=20000}) + end + tile:setTimer(storage[BotPanelName].mwalls[pos] - now) + end + end +end) + +local lastMana = 0 +macro(100, function() + if storage[BotPanelName].manaInfo then + if manapercent() ~= lastMana then + lastMana = manapercent() + BotServer.send("mana", {mana=lastMana}) + end + end +end) + + + + + + + + +addSeparator() \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/1_alarms.lua b/modules/game_bot/default_configs/vBot/1_alarms.lua new file mode 100644 index 0000000..27182ca --- /dev/null +++ b/modules/game_bot/default_configs/vBot/1_alarms.lua @@ -0,0 +1,178 @@ +alarmsPanelName = "alarms" +local ui = setupUI([[ +Panel + height: 19 + + BotSwitch + id: title + anchors.top: parent.top + anchors.left: parent.left + text-align: center + width: 130 + !text: tr('Alarms') + + Button + id: alerts + anchors.top: prev.top + anchors.left: prev.right + anchors.right: parent.right + margin-left: 3 + height: 17 + text: Edit + +]]) +ui:setId(alarmsPanelName) + +if not storage[alarmsPanelName] then +storage[alarmsPanelName] = { + enabled = false, + playerAttack = false, + playerDetected = false, + playerDetectedLogout = false, + creatureDetected = false, + healthBelow = false, + healthValue = 40, + manaBelow = false, + manaValue = 50, + privateMessage = false +} +end + +ui.title:setOn(storage[alarmsPanelName].enabled) +ui.title.onClick = function(widget) +storage[alarmsPanelName].enabled = not storage[alarmsPanelName].enabled +widget:setOn(storage[alarmsPanelName].enabled) +end + +rootWidget = g_ui.getRootWidget() +if rootWidget then + alarmsWindow = g_ui.createWidget('AlarmsWindow', rootWidget) + alarmsWindow:hide() + + alarmsWindow.closeButton.onClick = function(widget) + alarmsWindow:hide() + end + + alarmsWindow.playerAttack:setOn(storage[alarmsPanelName].playerAttack) + alarmsWindow.playerAttack.onClick = function(widget) + storage[alarmsPanelName].playerAttack = not storage[alarmsPanelName].playerAttack + widget:setOn(storage[alarmsPanelName].playerAttack) + end + + alarmsWindow.playerDetected:setOn(storage[alarmsPanelName].playerDetected) + alarmsWindow.playerDetected.onClick = function(widget) + storage[alarmsPanelName].playerDetected = not storage[alarmsPanelName].playerDetected + widget:setOn(storage[alarmsPanelName].playerDetected) + end + + alarmsWindow.playerDetectedLogout:setChecked(storage[alarmsPanelName].playerDetectedLogout) + alarmsWindow.playerDetectedLogout.onClick = function(widget) + storage[alarmsPanelName].playerDetectedLogout = not storage[alarmsPanelName].playerDetectedLogout + widget:setChecked(storage[alarmsPanelName].playerDetectedLogout) + end + + alarmsWindow.creatureDetected:setOn(storage[alarmsPanelName].creatureDetected) + alarmsWindow.creatureDetected.onClick = function(widget) + storage[alarmsPanelName].creatureDetected = not storage[alarmsPanelName].creatureDetected + widget:setOn(storage[alarmsPanelName].creatureDetected) + end + + alarmsWindow.healthBelow:setOn(storage[alarmsPanelName].healthBelow) + alarmsWindow.healthBelow.onClick = function(widget) + storage[alarmsPanelName].healthBelow = not storage[alarmsPanelName].healthBelow + widget:setOn(storage[alarmsPanelName].healthBelow) + end + + alarmsWindow.healthValue.onValueChange = function(scroll, value) + storage[alarmsPanelName].healthValue = value + alarmsWindow.healthBelow:setText("Health < " .. storage[alarmsPanelName].healthValue .. "%") + end + alarmsWindow.healthValue:setValue(storage[alarmsPanelName].healthValue) + + alarmsWindow.manaBelow:setOn(storage[alarmsPanelName].manaBelow) + alarmsWindow.manaBelow.onClick = function(widget) + storage[alarmsPanelName].manaBelow = not storage[alarmsPanelName].manaBelow + widget:setOn(storage[alarmsPanelName].manaBelow) + end + + alarmsWindow.manaValue.onValueChange = function(scroll, value) + storage[alarmsPanelName].manaValue = value + alarmsWindow.manaBelow:setText("Mana < " .. storage[alarmsPanelName].manaValue .. "%") + end + alarmsWindow.manaValue:setValue(storage[alarmsPanelName].manaValue) + + alarmsWindow.privateMessage:setOn(storage[alarmsPanelName].privateMessage) + alarmsWindow.privateMessage.onClick = function(widget) + storage[alarmsPanelName].privateMessage = not storage[alarmsPanelName].privateMessage + widget:setOn(storage[alarmsPanelName].privateMessage) + end + + onTextMessage(function(mode, text) + if storage[alarmsPanelName].enabled and storage[alarmsPanelName].playerAttack and mode == 16 and string.match(text, "hitpoints due to an attack") and not string.match(text, "hitpoints due to an attack by a ") then + playSound("/sounds/Player_Attack.ogg") + end + end) + + macro(100, function() + if not storage[alarmsPanelName].enabled then + return + end + if storage[alarmsPanelName].playerDetected then + for _, spec in ipairs(getSpectators()) do + if spec:isPlayer() and spec:getName() ~= name() then + specPos = spec:getPosition() + if math.max(math.abs(posx()-specPos.x), math.abs(posy()-specPos.y)) <= 8 then + playSound("/sounds/Player_Detected.ogg") + delay(1500) + if storage[alarmsPanelName].playerDetectedLogout then + modules.game_interface.tryLogout(false) + end + return + end + end + end + end + + if storage[alarmsPanelName].creatureDetected then + for _, spec in ipairs(getSpectators()) do + if not spec:isPlayer()then + specPos = spec:getPosition() + if math.max(math.abs(posx()-specPos.x), math.abs(posy()-specPos.y)) <= 8 then + playSound("/sounds/Creature_Detected.ogg") + delay(1500) + return + end + end + end + end + + if storage[alarmsPanelName].healthBelow then + if hppercent() <= storage[alarmsPanelName].healthValue then + playSound("/sounds/Low_Health.ogg") + delay(1500) + return + end + end + + if storage[alarmsPanelName].manaBelow then + if manapercent() <= storage[alarmsPanelName].manaValue then + playSound("/sounds/Low_Mana.ogg") + delay(1500) + return + end + end + end) + + onTalk(function(name, level, mode, text, channelId, pos) + if mode == 4 and storage[alarmsPanelName].enabled and storage[alarmsPanelName].privateMessage then + playSound("/sounds/Private_Message.ogg") + return + end + end) +end + +ui.alerts.onClick = function(widget) + alarmsWindow:show() + alarmsWindow:raise() + alarmsWindow:focus() +end \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/1_combo.lua b/modules/game_bot/default_configs/vBot/1_combo.lua new file mode 100644 index 0000000..641f495 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/1_combo.lua @@ -0,0 +1,440 @@ +ComboPanelName = "combobot" +local ui = setupUI([[ +Panel + height: 19 + + BotSwitch + id: title + anchors.top: parent.top + anchors.left: parent.left + text-align: center + width: 130 + !text: tr('ComboBot') + + Button + id: combos + anchors.top: prev.top + anchors.left: prev.right + anchors.right: parent.right + margin-left: 3 + height: 17 + text: Setup + +]]) +ui:setId(ComboPanelName) + +if not storage[ComboPanelName] then + storage[ComboPanelName] = { + enabled = false, + onSayEnabled = false, + onShootEnabled = false, + onCastEnabled = false, + followLeaderEnabled = false, + attackLeaderTargetEnabled = false, + attackSpellEnabled = false, + attackItemToggle = false, + sayLeader = "", + shootLeader = "", + castLeader = "", + sayPhrase = "", + spell = "", + serverLeader = "", + item = 3155, + attack = "", + follow = "", + commandsEnabled = true, + serverEnabled = false, + serverLeaderTarget = false, + serverTriggers = true + } +end + +ui.title:setOn(storage[ComboPanelName].enabled) +ui.title.onClick = function(widget) +storage[ComboPanelName].enabled = not storage[ComboPanelName].enabled +widget:setOn(storage[ComboPanelName].enabled) +end + +ui.combos.onClick = function(widget) + comboWindow:show() + comboWindow:raise() + comboWindow:focus() +end + +rootWidget = g_ui.getRootWidget() +if rootWidget then + comboWindow = g_ui.createWidget('ComboWindow', rootWidget) + comboWindow:hide() + + -- bot item + + comboWindow.actions.attackItem:setItemId(storage[ComboPanelName].item) + comboWindow.actions.attackItem.onItemChange = function(widget) + storage[ComboPanelName].item = widget:getItemId() + end + + -- switches + + comboWindow.actions.commandsToggle:setOn(storage[ComboPanelName].commandsEnabled) + comboWindow.actions.commandsToggle.onClick = function(widget) + storage[ComboPanelName].commandsEnabled = not storage[ComboPanelName].commandsEnabled + widget:setOn(storage[ComboPanelName].commandsEnabled) + end + + comboWindow.server.botServerToggle:setOn(storage[ComboPanelName].serverEnabled) + comboWindow.server.botServerToggle.onClick = function(widget) + storage[ComboPanelName].serverEnabled = not storage[ComboPanelName].serverEnabled + widget:setOn(storage[ComboPanelName].serverEnabled) + end + + comboWindow.server.Triggers:setOn(storage[ComboPanelName].serverTriggers) + comboWindow.server.Triggers.onClick = function(widget) + storage[ComboPanelName].serverTriggers = not storage[ComboPanelName].serverTriggers + widget:setOn(storage[ComboPanelName].serverTriggers) + end + + comboWindow.server.targetServerLeaderToggle:setOn(storage[ComboPanelName].serverLeaderTarget) + comboWindow.server.targetServerLeaderToggle.onClick = function(widget) + storage[ComboPanelName].serverLeaderTarget = not storage[ComboPanelName].serverLeaderTarget + widget:setOn(storage[ComboPanelName].serverLeaderTarget) + end + + -- buttons + comboWindow.closeButton.onClick = function(widget) + comboWindow:hide() + end + + -- combo boxes + + comboWindow.actions.followLeader:setOption(storage[ComboPanelName].follow) + comboWindow.actions.followLeader.onOptionChange = function(widget) + storage[ComboPanelName].follow = widget:getCurrentOption().text + end + + comboWindow.actions.attackLeaderTarget:setOption(storage[ComboPanelName].attack) + comboWindow.actions.attackLeaderTarget.onOptionChange = function(widget) + storage[ComboPanelName].attack = widget:getCurrentOption().text + end + + -- checkboxes + comboWindow.trigger.onSayToggle:setChecked(storage[ComboPanelName].onSayEnabled) + comboWindow.trigger.onSayToggle.onClick = function(widget) + storage[ComboPanelName].onSayEnabled = not storage[ComboPanelName].onSayEnabled + widget:setChecked(storage[ComboPanelName].onSayEnabled) + end + + comboWindow.trigger.onShootToggle:setChecked(storage[ComboPanelName].onShootEnabled) + comboWindow.trigger.onShootToggle.onClick = function(widget) + storage[ComboPanelName].onShootEnabled = not storage[ComboPanelName].onShootEnabled + widget:setChecked(storage[ComboPanelName].onShootEnabled) + end + + comboWindow.trigger.onCastToggle:setChecked(storage[ComboPanelName].onCastEnabled) + comboWindow.trigger.onCastToggle.onClick = function(widget) + storage[ComboPanelName].onCastEnabled = not storage[ComboPanelName].onCastEnabled + widget:setChecked(storage[ComboPanelName].onCastEnabled) + end + + comboWindow.actions.followLeaderToggle:setChecked(storage[ComboPanelName].followLeaderEnabled) + comboWindow.actions.followLeaderToggle.onClick = function(widget) + storage[ComboPanelName].followLeaderEnabled = not storage[ComboPanelName].followLeaderEnabled + widget:setChecked(storage[ComboPanelName].followLeaderEnabled) + end + + comboWindow.actions.attackLeaderTargetToggle:setChecked(storage[ComboPanelName].attackLeaderTargetEnabled) + comboWindow.actions.attackLeaderTargetToggle.onClick = function(widget) + storage[ComboPanelName].attackLeaderTargetEnabled = not storage[ComboPanelName].attackLeaderTargetEnabled + widget:setChecked(storage[ComboPanelName].attackLeaderTargetEnabled) + end + + comboWindow.actions.attackSpellToggle:setChecked(storage[ComboPanelName].attackSpellEnabled) + comboWindow.actions.attackSpellToggle.onClick = function(widget) + storage[ComboPanelName].attackSpellEnabled = not storage[ComboPanelName].attackSpellEnabled + widget:setChecked(storage[ComboPanelName].attackSpellEnabled) + end + + comboWindow.actions.attackItemToggle:setChecked(storage[ComboPanelName].attackItemEnabled) + comboWindow.actions.attackItemToggle.onClick = function(widget) + storage[ComboPanelName].attackItemEnabled = not storage[ComboPanelName].attackItemEnabled + widget:setChecked(storage[ComboPanelName].attackItemEnabled) + end + + -- text edits + comboWindow.trigger.onSayLeader:setText(storage[ComboPanelName].sayLeader) + comboWindow.trigger.onSayLeader.onTextChange = function(widget, text) + storage[ComboPanelName].sayLeader = text + end + + comboWindow.trigger.onShootLeader:setText(storage[ComboPanelName].shootLeader) + comboWindow.trigger.onShootLeader.onTextChange = function(widget, text) + storage[ComboPanelName].shootLeader = text + end + + comboWindow.trigger.onCastLeader:setText(storage[ComboPanelName].castLeader) + comboWindow.trigger.onCastLeader.onTextChange = function(widget, text) + storage[ComboPanelName].castLeader = text + end + + comboWindow.trigger.onSayPhrase:setText(storage[ComboPanelName].sayPhrase) + comboWindow.trigger.onSayPhrase.onTextChange = function(widget, text) + storage[ComboPanelName].sayPhrase = text + end + + comboWindow.actions.attackSpell:setText(storage[ComboPanelName].spell) + comboWindow.actions.attackSpell.onTextChange = function(widget, text) + storage[ComboPanelName].spell = text + end + + comboWindow.server.botServerLeader:setText(storage[ComboPanelName].serverLeader) + comboWindow.server.botServerLeader.onTextChange = function(widget, text) + storage[ComboPanelName].serverLeader = text + end +end + +-- bot server +-- [[ join party made by Frosty ]] -- + +local shouldCloseWindow = false +local firstInvitee = true +local isInComboTeam = false +macro(10, function() + if shouldCloseWindow and storage[ComboPanelName].serverEnabled and storage[ComboPanelName].enabled then + local channelsWindow = modules.game_console.channelsWindow + if channelsWindow then + local child = channelsWindow:getChildById("buttonCancel") + if child then + child:onClick() + shouldCloseWindow = false + isInComboTeam = true + end + end + end +end) + +comboWindow.server.partyButton.onClick = function(widget) + if storage[ComboPanelName].serverEnabled and storage[ComboPanelName].enabled then + if storage[ComboPanelName].serverLeader:len() > 0 and storage.BotServerChannel:len() > 0 then + talkPrivate(storage[ComboPanelName].serverLeader, "request invite " .. storage.BotServerChannel) + else + error("Request failed. Lack of data.") + end + end +end + +onTextMessage(function(mode, text) + if storage[ComboPanelName].serverEnabled and storage[ComboPanelName].enabled then + if mode == 20 then + if string.find(text, "invited you to") then + local regex = "[a-zA-Z]*" + local regexData = regexMatch(text, regex) + if regexData[1][1]:lower() == storage[ComboPanelName].serverLeader:lower() then + local leader = getCreatureByName(regexData[1][1]) + if leader then + g_game.partyJoin(leader:getId()) + g_game.requestChannels() + g_game.joinChannel(1) + shouldCloseWindow = true + end + end + end + end + end +end) + +onTalk(function(name, level, mode, text, channelId, pos) + if storage[ComboPanelName].serverEnabled and storage[ComboPanelName].enabled then + if mode == 4 then + if string.find(text, "request invite") then + local access = string.match(text, "%d.*") + if access and access == storage.BotServerChannel then + local minion = getCreatureByName(name) + if minion then + g_game.partyInvite(minion:getId()) + if firstInvitee then + g_game.requestChannels() + g_game.joinChannel(1) + shouldCloseWindow = true + firstInvitee = false + end + end + else + talkPrivate(name, "Incorrect access key!") + end + end + end + end + -- [[ End of Frosty's Code ]] -- + if storage[ComboPanelName].enabled and storage[ComboPanelName].enabled then + if name:lower() == storage[ComboPanelName].sayLeader:lower() and string.find(text, storage[ComboPanelName].sayPhrase) and storage[ComboPanelName].onSayEnabled then + startCombo = true + end + if (storage[ComboPanelName].castLeader and name:lower() == storage[ComboPanelName].castLeader:lower()) and isAttSpell(text) and storage[ComboPanelName].onCastEnabled then + startCombo = true + end + end + if storage[ComboPanelName].enabled and storage[ComboPanelName].commandsEnabled and (storage[ComboPanelName].shootLeader and name:lower() == storage[ComboPanelName].shootLeader:lower()) or (storage[ComboPanelName].sayLeader and name:lower() == storage[ComboPanelName].sayLeader:lower()) or (storage[ComboPanelName].castLeader and name:lower() == storage[ComboPanelName].castLeader:lower()) then + if string.find(text, "ue") then + say(storage[ComboPanelName].spell) + elseif string.find(text, "sd") then + local params = string.split(text, ",") + if #params == 2 then + local target = params[2]:trim() + if getCreatureByName(target) then + useWith(3155, getCreatureByName(target)) + end + end + elseif string.find(text, "att") then + local attParams = string.split(text, ",") + if #attParams == 2 then + local atTarget = attParams[2]:trim() + if getCreatureByName(atTarget) and storage[ComboPanelName].attack == "COMMAND TARGET" then + g_game.attack(getCreatureByName(atTarget)) + end + end + end + end + if isAttSpell(text) and storage[ComboPanelName].enabled and storage[ComboPanelName].serverEnabled then + BotServer.send("trigger", "start") + end +end) + +onMissle(function(missle) + if storage[ComboPanelName].enabled and storage[ComboPanelName].onShootEnabled then + if not storage[ComboPanelName].shootLeader or storage[ComboPanelName].shootLeader:len() == 0 then + return + end + local src = missle:getSource() + if src.z ~= posz() then + return + end + local from = g_map.getTile(src) + local to = g_map.getTile(missle:getDestination()) + if not from or not to then + return + end + local fromCreatures = from:getCreatures() + local toCreatures = to:getCreatures() + if #fromCreatures ~= 1 or #toCreatures ~= 1 then + return + end + local c1 = fromCreatures[1] + local t1 = toCreatures[1] + leaderTarget = t1 + if c1:getName():lower() == storage[ComboPanelName].shootLeader:lower() then + if storage[ComboPanelName].attackItemEnabled and storage[ComboPanelName].item and storage[ComboPanelName].item > 100 and findItem(storage[ComboPanelName].item) then + useWith(storage[ComboPanelName].item, t1) + end + if storage[ComboPanelName].attackSpellEnabled and storage[ComboPanelName].spell:len() > 1 then + say(storage[ComboPanelName].spell) + end + end + end +end) + +macro(10, function() + if not storage[ComboPanelName].enabled or not storage[ComboPanelName].attackLeaderTargetEnabled then return end + if leaderTarget and storage[ComboPanelName].attack == "LEADER TARGET" then + if not getTarget() or (getTarget() and getTarget():getName() ~= leaderTarget:getName()) then + g_game.attack(leaderTarget) + end + end + if storage[ComboPanelName].enabled and storage[ComboPanelName].serverEnabled and storage[ComboPanelName].attack == "SERVER LEADER TARGET" and serverTarget then + if serverTarget and not getTarget() or (getTarget() and getTarget():getname() ~= serverTarget) + then + g_game.attack(serverTarget) + end + end +end) + + +local toFollow +local toFollowPos = {} + +macro(100, function() + toFollow = nil + if not storage[ComboPanelName].enabled or not storage[ComboPanelName].followLeaderEnabled then return end + if leaderTarget and storage[ComboPanelName].follow == "LEADER TARGET" and leaderTarget:isPlayer() then + toFollow = leaderTarget:getName() + elseif storage[ComboPanelName].follow == "SERVER LEADER TARGET" and storage[ComboPanelName].serverLeader:len() ~= 0 then + toFollow = serverTarget + elseif storage[ComboPanelName].follow == "SERVER LEADER" and storage[ComboPanelName].serverLeader:len() ~= 0 then + toFollow = storage[ComboPanelName].serverLeader + elseif storage[ComboPanelName].follow == "LEADER" then + if storage[ComboPanelName].onSayEnabled and storage[ComboPanelName].sayLeader:len() ~= 0 then + toFollow = storage[ComboPanelName].sayLeader + elseif storage[ComboPanelName].onCastEnabled and storage[ComboPanelName].castLeader:len() ~= 0 then + toFollow = storage[ComboPanelName].castLeader + elseif storage[ComboPanelName].onShootEnabled and storage[ComboPanelName].shootLeader:len() ~= 0 then + toFollow = storage[ComboPanelName].shootLeader + end + end + if not toFollow then return end + local target = getCreatureByName(toFollow) + if target then + local tpos = target:getPosition() + toFollowPos[tpos.z] = tpos + end + if player:isWalking() then return end + local p = toFollowPos[posz()] + if not p then return end + if CaveBot.walkTo(p, 20, {ignoreNonPathable=true, precision=1, ignoreStairs=false}) then + delay(100) + end +end) + +onCreaturePositionChange(function(creature, oldPos, newPos) + if creature:getName() == toFollow and newPos then + toFollowPos[newPos.z] = newPos + end +end) + +local timeout = now +macro(10, function() + if storage[ComboPanelName].enabled and startCombo then + if storage[ComboPanelName].attackItemEnabled and storage[ComboPanelName].item and storage[ComboPanelName].item > 100 and findItem(storage[ComboPanelName].item) then + useWith(storage[ComboPanelName].item, getTarget()) + end + if storage[ComboPanelName].attackSpellEnabled and storage[ComboPanelName].spell:len() > 1 then + say(storage[ComboPanelName].spell) + end + startCombo = false + end + -- attack part / server + if BotServer._websocket and storage[ComboPanelName].enabled and storage[ComboPanelName].serverEnabled then + if target() and now - timeout > 500 then + targetPos = target():getName() + BotServer.send("target", targetPos) + timeout = now + end + end +end) + +onUseWith(function(pos, itemId, target, subType) + if BotServer._websocket and itemId == 3155 then + BotServer.send("useWith", target:getPosition()) + end +end) + +if BotServer._websocket and storage[ComboPanelName].enabled and storage[ComboPanelName].serverEnabled then + BotServer.listen("trigger", function(name, message) + if message == "start" and name:lower() ~= player:getName():lower() and name:lower() == storage[ComboPanelName].serverLeader:lower() and storage[ComboPanelName].serverTriggers then + startCombo = true + end + end) + BotServer.listen("target", function(name, message) + if name:lower() ~= player:getName():lower() and name:lower() == storage[ComboPanelName].serverLeader:lower() then + if not target() or target():getName() == getCreatureByName(message) then + if storage[ComboPanelName].serverLeaderTarget then + serverTarget = getCreatureByName(message) + g_game.attack(getCreatureByName(message)) + end + end + end + end) + BotServer.listen("useWith", function(name, message) + local tile = g_map.getTile(message) + if storage[ComboPanelName].serverTriggers and name:lower() ~= player:getName():lower() and name:lower() == storage[ComboPanelName].serverLeader:lower() and storage[ComboPanelName].attackItemEnabled and storage[ComboPanelName].item and findItem(storage[ComboPanelName].item) then + useWith(storage[ComboPanelName].item, tile:getTopUseThing()) + end + end) +end \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/1_pushmax.lua b/modules/game_bot/default_configs/vBot/1_pushmax.lua new file mode 100644 index 0000000..9fc9cf5 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/1_pushmax.lua @@ -0,0 +1,187 @@ +setDefaultTab("Main") + +pushPanelName = "pushmax" +local ui = setupUI([[ +Panel + height: 19 + + BotSwitch + id: title + anchors.top: parent.top + anchors.left: parent.left + text-align: center + width: 130 + !text: tr('PUSHMAX') + + Button + id: push + anchors.top: prev.top + anchors.left: prev.right + anchors.right: parent.right + margin-left: 3 + height: 17 + text: Setup + +]]) +ui:setId(pushPanelName) + +if not storage[pushPanelName] then + storage[pushPanelName] = { + enabled = true, + pushDelay = 1060, + pushMaxRuneId = 3188, + mwallBlockId = 2128, + pushMaxKey = "PageUp" + } +end + +ui.title:setOn(storage[pushPanelName].enabled) +ui.title.onClick = function(widget) +storage[pushPanelName].enabled = not storage[pushPanelName].enabled +widget:setOn(storage[pushPanelName].enabled) +end + +ui.push.onClick = function(widget) + pushWindow:show() + pushWindow:raise() + pushWindow:focus() +end + +rootWidget = g_ui.getRootWidget() +if rootWidget then + pushWindow = g_ui.createWidget('PushMaxWindow', rootWidget) + pushWindow:hide() + + pushWindow.closeButton.onClick = function(widget) + pushWindow:hide() + end + + local updateDelayText = function() + pushWindow.delayText:setText("Push Delay: ".. storage[pushPanelName].pushDelay) + end + updateDelayText() + pushWindow.delay.onValueChange = function(scroll, value) + storage[pushPanelName].pushDelay = value + updateDelayText() + end + pushWindow.delay:setValue(storage[pushPanelName].pushDelay) + + pushWindow.runeId.onItemChange = function(widget) + storage[pushPanelName].pushMaxRuneId = widget:getItemId() + end + pushWindow.runeId:setItemId(storage[pushPanelName].pushMaxRuneId) + pushWindow.mwallId.onItemChange = function(widget) + storage[pushPanelName].mwallBlockId = widget:getItemId() + end + pushWindow.mwallId:setItemId(storage[pushPanelName].mwallBlockId) + + pushWindow.hotkey.onTextChange = function(widget, text) + storage[pushPanelName].pushMaxKey = text + end + pushWindow.hotkey:setText(storage[pushPanelName].pushMaxKey) +end + + +function matchPosition(curX, curY, destX, destY) + return (curX == destX and curY == destY) +end + +local target +local targetTile +local targetOldPos +macro(10, function() + if not storage[pushPanelName].enabled then return end + if target and targetTile then + if not matchPosition(target:getPosition().x, target:getPosition().y, targetTile:getPosition().x, targetTile:getPosition().y) then + local tile = g_map.getTile(target:getPosition()) + targetOldPos = tile:getPosition() + if tile then + if tile:getTopUseThing():isPickupable() or not tile:getTopUseThing():isNotMoveable() then + useWith(tonumber(storage[pushPanelName].pushMaxRuneId), target) + delay(10) + end + if targetTile:getTopThing():getId() == 2129 or targetTile:getTopThing():getId() == 2130 or targetTile:getTopThing():getId() == tonumber(storage[pushPanelName].mwallBlockId) then + if targetTile:getTimer() <= tonumber(storage[pushPanelName].pushDelay) then + info("now") + g_game.move(target, targetTile:getPosition()) + tile:setText("") + targetTile:setText("") + target = nil + targetTile = nil + end + else + g_game.move(target, targetTile:getPosition()) + delay(1250) + end + end + else + if targetOldPos then + local tile = g_map.getTile(targetOldPos) + if tile then + tile:setText("") + targetTile:setText("") + end + end + target = nil + targetTile = nil + end + end +end) + +local resetTimer = now +onKeyDown(function(keys) + if not storage[pushPanelName].enabled then return end + if keys == storage[pushPanelName].pushMaxKey and resetTimer == 0 then + if not target then + local tile = getTileUnderCursor() + if tile and getDistanceBetween(pos(), tile:getPosition()) <= 1 then + if tile:getCreatures()[1] then + target = tile:getCreatures()[1] + tile:setText("PUSH TARGET") + end + end + else + local tile = getTileUnderCursor() + if tile and not tile:getCreatures()[1] then + targetTile = tile + tile:setText("DESTINATION") + end + end + resetTimer = now + end +end) + + +onKeyPress(function(keys) + if not storage[pushPanelName].enabled then return end + if keys == storage.pushMaxKey and (resetTimer - now) < -10 then + for _, tile in ipairs(g_map.getTiles(posz())) do + if getDistanceBetween(pos(), tile:getPosition()) < 3 then + if tile:getText() ~= "" then + tile:setText("") + end + end + end + target = nil + targetTile = nil + resetTimer = 0 + else + resetTimer = 0 + end +end) + +onCreaturePositionChange(function(creature, newPos, oldPos) + if target and storage[pushPanelName].enabled then + if creature:getName() == target:getName() then + target = nil + targetTile = nil + for _, tile in ipairs(g_map.getTiles(posz())) do + if getDistanceBetween(pos(), tile:getPosition()) < 3 then + if tile:getText() ~= "" then + tile:setText("") + end + end + end + end + end +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/2HealBot.lua b/modules/game_bot/default_configs/vBot/2HealBot.lua new file mode 100644 index 0000000..fbe928c --- /dev/null +++ b/modules/game_bot/default_configs/vBot/2HealBot.lua @@ -0,0 +1,697 @@ +setDefaultTab("HP") +healPanelName = "healbot" +local ui = setupUI([[ +Panel + height: 38 + + BotSwitch + id: title + anchors.top: parent.top + anchors.left: parent.left + text-align: center + width: 130 + !text: tr('HealBot') + + Button + id: settings + anchors.top: prev.top + anchors.left: prev.right + anchors.right: parent.right + margin-left: 3 + height: 17 + text: Setup + + Button + id: 1 + anchors.top: prev.bottom + anchors.left: parent.left + text: 1 + margin-right: 2 + margin-top: 4 + size: 17 17 + + Button + id: 2 + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + text: 2 + margin-left: 4 + size: 17 17 + + Button + id: 3 + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + text: 3 + margin-left: 4 + size: 17 17 + + Button + id: 4 + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + text: 4 + margin-left: 4 + size: 17 17 + + Button + id: 5 + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + text: 5 + margin-left: 4 + size: 17 17 + + Label + id: name + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + anchors.right: parent.right + text-align: center + margin-left: 4 + height: 17 + text: Profile #1 + background: #292A2A +]]) +ui:setId(healPanelName) + +if not storage[healPanelName] or not storage[healPanelName][1] or #storage[healPanelName] ~= 5 then + storage[healPanelName] = { + [1] = { + enabled = false, + spellTable = {}, + itemTable = {}, + name = "Profile #1", + Visible = true, + Cooldown = true, + Interval = true, + Conditions = true, + Delay = true, + MessageDelay = false + }, + [2] = { + enabled = false, + spellTable = {}, + itemTable = {}, + name = "Profile #2", + Visible = true, + Cooldown = true, + Interval = true, + Conditions = true, + Delay = true, + MessageDelay = false + }, + [3] = { + enabled = false, + spellTable = {}, + itemTable = {}, + name = "Profile #3", + Visible = true, + Cooldown = true, + Interval = true, + Conditions = true, + Delay = true, + MessageDelay = false + }, + [4] = { + enabled = false, + spellTable = {}, + itemTable = {}, + name = "Profile #4", + Visible = true, + Cooldown = true, + Interval = true, + Conditions = true, + Delay = true, + MessageDelay = false + }, + [5] = { + enabled = false, + spellTable = {}, + itemTable = {}, + name = "Profile #5", + Visible = true, + Cooldown = true, + Interval = true, + Conditions = true, + Delay = true, + MessageDelay = false + }, + } +end + +if not storage.currentHealBotProfile or storage.currentHealBotProfile == 0 or storage.currentHealBotProfile > 5 then + storage.currentHealBotProfile = 1 +end + +-- finding correct table, manual unfortunately +local currentSettings +local setActiveProfile = function() + local n = storage.currentHealBotProfile + currentSettings = storage[healPanelName][n] +end +setActiveProfile() + +local activeProfileColor = function() + for i=1,5 do + if i == storage.currentHealBotProfile then + ui[i]:setColor("green") + else + ui[i]:setColor("white") + end + end +end +activeProfileColor() + +ui.title:setOn(currentSettings.enabled) +ui.title.onClick = function(widget) +currentSettings.enabled = not currentSettings.enabled +widget:setOn(currentSettings.enabled) +end + +ui.settings.onClick = function(widget) + healWindow:show() + healWindow:raise() + healWindow:focus() +end + +rootWidget = g_ui.getRootWidget() +if rootWidget then + healWindow = g_ui.createWidget('HealWindow', rootWidget) + healWindow:hide() + + local setProfileName = function() + ui.name:setText(currentSettings.name) + end + healWindow.Name.onTextChange = function(widget, text) + currentSettings.name = text + setProfileName() + end + healWindow.Visible.onClick = function(widget) + currentSettings.Visible = not currentSettings.Visible + healWindow.Visible:setChecked(currentSettings.Visible) + end + healWindow.Cooldown.onClick = function(widget) + currentSettings.Cooldown = not currentSettings.Cooldown + healWindow.Cooldown:setChecked(currentSettings.Cooldown) + end + healWindow.Interval.onClick = function(widget) + currentSettings.Interval = not currentSettings.Interval + healWindow.Interval:setChecked(currentSettings.Interval) + end + healWindow.Conditions.onClick = function(widget) + currentSettings.Conditions = not currentSettings.Conditions + healWindow.Conditions:setChecked(currentSettings.Conditions) + end + healWindow.Delay.onClick = function(widget) + currentSettings.Delay = not currentSettings.Delay + healWindow.Delay:setChecked(currentSettings.Delay) + end + healWindow.MessageDelay.onClick = function(widget) + currentSettings.MessageDelay = not currentSettings.MessageDelay + healWindow.MessageDelay:setChecked(currentSettings.MessageDelay) + end + + local refreshSpells = function() + if currentSettings.spellTable then + for i, child in pairs(healWindow.spells.spellList:getChildren()) do + child:destroy() + end + for _, entry in pairs(currentSettings.spellTable) do + local label = g_ui.createWidget("SpellEntry", healWindow.spells.spellList) + label.enabled:setChecked(entry.enabled) + label.enabled.onClick = function(widget) + entry.enabled = not entry.enabled + label.enabled:setChecked(entry.enabled) + end + label.remove.onClick = function(widget) + table.removevalue(currentSettings.spellTable, entry) + reindexTable(currentSettings.spellTable) + label:destroy() + end + label:setText("(MP>" .. entry.cost .. ") " .. entry.origin .. entry.sign .. entry.value .. ":" .. entry.spell) + end + end + end + refreshSpells() + + local refreshItems = function() + if currentSettings.itemTable then + for i, child in pairs(healWindow.items.itemList:getChildren()) do + child:destroy() + end + for _, entry in pairs(currentSettings.itemTable) do + local label = g_ui.createWidget("SpellEntry", healWindow.items.itemList) + label.enabled:setChecked(entry.enabled) + label.enabled.onClick = function(widget) + entry.enabled = not entry.enabled + label.enabled:setChecked(entry.enabled) + end + label.remove.onClick = function(widget) + table.removevalue(currentSettings.itemTable, entry) + reindexTable(currentSettings.itemTable) + label:destroy() + end + label:setText(entry.origin .. entry.sign .. entry.value .. ":" .. entry.item) + end + end + end + refreshItems() + + healWindow.spells.MoveUp.onClick = function(widget) + local input = healWindow.spells.spellList:getFocusedChild() + if not input then return end + local index = healWindow.spells.spellList:getChildIndex(input) + if index < 2 then return end + + local move + if currentSettings.spellTable and #currentSettings.spellTable > 0 then + for _, entry in pairs(currentSettings.spellTable) do + if entry.index == index -1 then + move = entry + end + if entry.index == index then + move.index = index + entry.index = index -1 + end + end + end + table.sort(currentSettings.spellTable, function(a,b) return a.index < b.index end) + + healWindow.spells.spellList:moveChildToIndex(input, index - 1) + healWindow.spells.spellList:ensureChildVisible(input) + end + + healWindow.spells.MoveDown.onClick = function(widget) + local input = healWindow.spells.spellList:getFocusedChild() + if not input then return end + local index = healWindow.spells.spellList:getChildIndex(input) + if index >= healWindow.spells.spellList:getChildCount() then return end + + local move + local move2 + if currentSettings.spellTable and #currentSettings.spellTable > 0 then + for _, entry in pairs(currentSettings.spellTable) do + if entry.index == index +1 then + move = entry + end + if entry.index == index then + move2 = entry + end + end + if move and move2 then + move.index = index + move2.index = index + 1 + end + end + table.sort(currentSettings.spellTable, function(a,b) return a.index < b.index end) + + healWindow.spells.spellList:moveChildToIndex(input, index + 1) + healWindow.spells.spellList:ensureChildVisible(input) + end + + healWindow.items.MoveUp.onClick = function(widget) + local input = healWindow.items.itemList:getFocusedChild() + if not input then return end + local index = healWindow.items.itemList:getChildIndex(input) + if index < 2 then return end + + local move + if currentSettings.itemTable and #currentSettings.itemTable > 0 then + for _, entry in pairs(currentSettings.itemTable) do + if entry.index == index -1 then + move = entry + end + if entry.index == index then + move.index = index + entry.index = index - 1 + end + end + end + table.sort(currentSettings.itemTable, function(a,b) return a.index < b.index end) + + healWindow.items.itemList:moveChildToIndex(input, index - 1) + healWindow.items.itemList:ensureChildVisible(input) + end + + healWindow.items.MoveDown.onClick = function(widget) + local input = healWindow.items.itemList:getFocusedChild() + if not input then return end + local index = healWindow.items.itemList:getChildIndex(input) + if index >= healWindow.items.itemList:getChildCount() then return end + + local move + local move2 + if currentSettings.itemTable and #currentSettings.itemTable > 0 then + for _, entry in pairs(currentSettings.itemTable) do + if entry.index == index +1 then + move = entry + end + if entry.index == index then + move2 = entry + end + end + if move and move2 then + move.index = index + move2.index = index + 1 + end + end + table.sort(currentSettings.itemTable, function(a,b) return a.index < b.index end) + + healWindow.items.itemList:moveChildToIndex(input, index + 1) + healWindow.items.itemList:ensureChildVisible(input) + end + + healWindow.spells.addSpell.onClick = function(widget) + + local spellFormula = healWindow.spells.spellFormula:getText():trim() + local manaCost = tonumber(healWindow.spells.manaCost:getText()) + local spellTrigger = tonumber(healWindow.spells.spellValue:getText()) + local spellSource = healWindow.spells.spellSource:getCurrentOption().text + local spellEquasion = healWindow.spells.spellCondition:getCurrentOption().text + local source + local equasion + + if not manaCost then + warn("HealBot: incorrect mana cost value!") + healWindow.spells.spellFormula:setText('') + healWindow.spells.spellValue:setText('') + healWindow.spells.manaCost:setText('') + return + end + if not spellTrigger then + warn("HealBot: incorrect condition value!") + healWindow.spells.spellFormula:setText('') + healWindow.spells.spellValue:setText('') + healWindow.spells.manaCost:setText('') + return + end + + if spellSource == "Current Mana" then + source = "MP" + elseif spellSource == "Current Health" then + source = "HP" + elseif spellSource == "Mana Percent" then + source = "MP%" + elseif spellSource == "Health Percent" then + source = "HP%" + else + source = "burst" + end + + if spellEquasion == "Above" then + equasion = ">" + elseif spellEquasion == "Below" then + equasion = "<" + else + equasion = "=" + end + + if spellFormula:len() > 0 then + table.insert(currentSettings.spellTable, {index = #currentSettings.spellTable+1, spell = spellFormula, sign = equasion, origin = source, cost = manaCost, value = spellTrigger, enabled = true}) + healWindow.spells.spellFormula:setText('') + healWindow.spells.spellValue:setText('') + healWindow.spells.manaCost:setText('') + end + refreshSpells() + end + + healWindow.items.addItem.onClick = function(widget) + + local id = healWindow.items.itemId:getItemId() + local trigger = tonumber(healWindow.items.itemValue:getText()) + local src = healWindow.items.itemSource:getCurrentOption().text + local eq = healWindow.items.itemCondition:getCurrentOption().text + local source + local equasion + + if not trigger then + warn("HealBot: incorrect trigger value!") + healWindow.items.itemId:setItemId(0) + healWindow.items.itemValue:setText('') + return + end + + if src == "Current Mana" then + source = "MP" + elseif src == "Current Health" then + source = "HP" + elseif src == "Mana Percent" then + source = "MP%" + elseif src == "Health Percent" then + source = "HP%" + else + source = "burst" + end + + if eq == "Above" then + equasion = ">" + elseif eq == "Below" then + equasion = "<" + else + equasion = "=" + end + + if id > 100 then + table.insert(currentSettings.itemTable, {index = #currentSettings.itemTable+1,item = id, sign = equasion, origin = source, value = trigger, enabled = true}) + refreshItems() + healWindow.items.itemId:setItemId(0) + healWindow.items.itemValue:setText('') + end + end + + healWindow.closeButton.onClick = function(widget) + healWindow:hide() + end + + local loadSettings = function() + ui.title:setOn(currentSettings.enabled) + setProfileName() + healWindow.Name:setText(currentSettings.name) + refreshSpells() + refreshItems() + healWindow.Visible:setChecked(currentSettings.Visible) + healWindow.Cooldown:setChecked(currentSettings.Cooldown) + healWindow.Delay:setChecked(currentSettings.Delay) + healWindow.MessageDelay:setChecked(currentSettings.MessageDelay) + healWindow.Interval:setChecked(currentSettings.Interval) + healWindow.Conditions:setChecked(currentSettings.Conditions) + end + loadSettings() + + local profileChange = function() + setActiveProfile() + activeProfileColor() + loadSettings() + end + + local resetSettings = function() + currentSettings.enabled = false + currentSettings.spellTable = {} + currentSettings.itemTable = {} + currentSettings.Visible = true + currentSettings.Cooldown = true + currentSettings.Delay = true + currentSettings.MessageDelay = false + currentSettings.Interval = true + currentSettings.Conditions = true + currentSettings.name = "Profile #" .. storage.currentBotProfile + end + + -- profile buttons + for i=1,5 do + local button = ui[i] + button.onClick = function() + storage.currentHealBotProfile = i + profileChange() + end + end + + healWindow.ResetSettings.onClick = function() + resetSettings() + loadSettings() + end + + + -- public functions + HealBot = {} -- global table + + HealBot.isOn = function() + return currentSettings.enabled + end + + HealBot.isOff = function() + return not currentSettings.enabled + end + + HealBot.setOff = function() + currentSettings.enabled = false + ui.title:setOn(currentSettings.enabled) + end + + HealBot.setOn = function() + currentSettings.enabled = true + ui.title:setOn(currentSettings.enabled) + end + + HealBot.getActiveProfile = function() + return storage.currentHealBotProfile -- returns number 1-5 + end + + HealBot.setActiveProfile = function(n) + if not n or not tonumber(n) or n < 1 or n > 5 then + return error("[HealBot] wrong profile parameter! should be 1 to 5 is " .. n) + else + storage.currentHealBotProfile = n + profileChange() + end + end +end + +-- spells +macro(100, function() + if not currentSettings.enabled or modules.game_cooldown.isGroupCooldownIconActive(2) or #currentSettings.spellTable == 0 then return end + + for _, entry in pairs(currentSettings.spellTable) do + if canCast(entry.spell, not currentSettings.Conditions, currentSettings.Cooldown) and entry.enabled and entry.cost < mana() then + if entry.origin == "HP%" then + if entry.sign == "=" and hppercent() == entry.value then + say(entry.spell) + return + elseif entry.sign == ">" and hppercent() >= entry.value then + say(entry.spell) + return + elseif entry.sign == "<" and hppercent() <= entry.value then + say(entry.spell) + return + end + elseif entry.origin == "HP" then + if entry.sign == "=" and hp() == entry.value then + say(entry.spell) + return + elseif entry.sign == ">" and hp() >= entry.value then + say(entry.spell) + return + elseif entry.sign == "<" and hp() <= entry.value then + say(entry.spell) + return + end + elseif entry.origin == "MP%" then + if entry.sign == "=" and manapercent() == entry.value then + say(entry.spell) + return + elseif entry.sign == ">" and manapercent() >= entry.value then + say(entry.spell) + return + elseif entry.sign == "<" and manapercent() <= entry.value then + say(entry.spell) + return + end + elseif entry.origin == "MP" then + if entry.sign == "=" and mana() == entry.value then + say(entry.spell) + return + elseif entry.sign == ">" and mana() >= entry.value then + say(entry.spell) + return + elseif entry.sign == "<" and mana() <= entry.value then + say(entry.spell) + return + end + elseif entry.origin == "burst" then + if entry.sign == "=" and burstDamageValue() == entry.value then + say(entry.spell) + return + elseif entry.sign == ">" and burstDamageValue() >= entry.value then + say(entry.spell) + return + elseif entry.sign == "<" and burstDamageValue() <= entry.value then + say(entry.spell) + return + end + end + end + end +end) + +-- items +macro(100, function() + if not currentSettings.enabled or #currentSettings.itemTable == 0 then return end + if currentSettings.Delay and storage.isUsing then return end + if currentSettings.MessageDelay and storage.isUsingPotion then return end + + if not currentSettings.MessageDelay then + delay(400) + end + + if TargetBot.isOn() and TargetBot.Looting.getStatus():len() > 0 and currentSettings.Interval then + if not currentSettings.MessageDelay then + delay(700) + else + delay(200) + end + end + + for _, entry in pairs(currentSettings.itemTable) do + local item = findItem(entry.item) + if (not currentSettings.Visible or item) and entry.enabled then + if entry.origin == "HP%" then + if entry.sign == "=" and hppercent() == entry.value then + g_game.useInventoryItemWith(entry.item, player) + return + elseif entry.sign == ">" and hppercent() >= entry.value then + g_game.useInventoryItemWith(entry.item, player) + return + elseif entry.sign == "<" and hppercent() <= entry.value then + g_game.useInventoryItemWith(entry.item, player) + return + end + elseif entry.origin == "HP" then + if entry.sign == "=" and hp() == tonumberentry.value then + g_game.useInventoryItemWith(entry.item, player) + return + elseif entry.sign == ">" and hp() >= entry.value then + g_game.useInventoryItemWith(entry.item, player) + return + elseif entry.sign == "<" and hp() <= entry.value then + g_game.useInventoryItemWith(entry.item, player) + return + end + elseif entry.origin == "MP%" then + if entry.sign == "=" and manapercent() == entry.value then + g_game.useInventoryItemWith(entry.item, player) + return + elseif entry.sign == ">" and manapercent() >= entry.value then + g_game.useInventoryItemWith(entry.item, player) + return + elseif entry.sign == "<" and manapercent() <= entry.value then + g_game.useInventoryItemWith(entry.item, player) + return + end + elseif entry.origin == "MP" then + if entry.sign == "=" and mana() == entry.value then + g_game.useInventoryItemWith(entry.item, player) + return + elseif entry.sign == ">" and mana() >= entry.value then + g_game.useInventoryItemWith(entry.item, player) + return + elseif entry.sign == "<" and mana() <= entry.value then + g_game.useInventoryItemWith(entry.item, player) + return + end + elseif entry.origin == "burst" then + if entry.sign == "=" and burstDamageValue() == entry.value then + g_game.useInventoryItemWith(entry.item, player) + return + elseif entry.sign == ">" and burstDamageValue() >= entry.value then + g_game.useInventoryItemWith(entry.item, player) + return + elseif entry.sign == "<" and burstDamageValue() <= entry.value then + g_game.useInventoryItemWith(entry.item, player) + return + end + end + end + end +end) +UI.Separator() \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/3_Sio.lua b/modules/game_bot/default_configs/vBot/3_Sio.lua new file mode 100644 index 0000000..7a1133d --- /dev/null +++ b/modules/game_bot/default_configs/vBot/3_Sio.lua @@ -0,0 +1,124 @@ +setDefaultTab("Main") + local panelName = "advancedFriendHealer" + local ui = setupUI([[ +Panel + height: 19 + + BotSwitch + id: title + anchors.top: parent.top + anchors.left: parent.left + text-align: center + width: 130 + !text: tr('Friend Healer') + + Button + id: editList + anchors.top: prev.top + anchors.left: prev.right + anchors.right: parent.right + margin-left: 3 + height: 17 + text: Setup + + ]], parent) + ui:setId(panelName) + + if not storage[panelName] then + storage[panelName] = { + minMana = 60, + minFriendHp = 40, + spellName = "exura sio", + spellHeal = true, + distance = 8, + itemHeal = true, + id = 3160 + } + end + + + rootWidget = g_ui.getRootWidget() + sioListWindow = g_ui.createWidget('SioListWindow', rootWidget) + sioListWindow:hide() + + ui.title:setOn(storage[panelName].enabled) + sioListWindow.spell:setOn(storage[panelName].spellHeal) + sioListWindow.item:setOn(storage[panelName].itemHeal) + + ui.title.onClick = function(widget) + storage[panelName].enabled = not storage[panelName].enabled + widget:setOn(storage[panelName].enabled) + end + + ui.editList.onClick = function(widget) + sioListWindow:show() + sioListWindow:raise() + sioListWindow:focus() + end + sioListWindow.spell.onClick = function(widget) + storage[panelName].spellHeal = not storage[panelName].spellHeal + widget:setOn(storage[panelName].spellHeal) + end + sioListWindow.item.onClick = function(widget) + storage[panelName].itemHeal = not storage[panelName].itemHeal + widget:setOn(storage[panelName].itemHeal) + end + sioListWindow.closeButton.onClick = function(widget) + sioListWindow:hide() + end + sioListWindow.spellName.onTextChange = function(widget, text) + storage[panelName].spellName = text + end + local updateMinManaText = function() + sioListWindow.manaInfo:setText("Minimum Mana >= " .. storage[panelName].minMana .. "%") + end + local updateFriendHpText = function() + sioListWindow.friendHp:setText("Heal Friend Below " .. storage[panelName].minFriendHp .. "% hp") + end + local updateDistanceText = function() + sioListWindow.distText:setText("Max Distance: " .. storage[panelName].distance) + end + sioListWindow.Distance.onValueChange = function(scroll, value) + storage[panelName].distance = value + updateDistanceText() + end + updateDistanceText() + sioListWindow.minMana.onValueChange = function(scroll, value) + storage[panelName].minMana = value + updateMinManaText() + end + sioListWindow.minFriendHp.onValueChange = function(scroll, value) + storage[panelName].minFriendHp = value + + updateFriendHpText() + end + sioListWindow.itemId:setItemId(storage[panelName].id) + sioListWindow.itemId.onItemChange = function(widget) + storage[panelName].id = widget:getItemId() + end + sioListWindow.spellName:setText(storage[panelName].spellName) + sioListWindow.minMana:setValue(storage[panelName].minMana) + sioListWindow.minFriendHp:setValue(storage[panelName].minFriendHp) + sioListWindow.Distance:setValue(storage[panelName].distance) + + local healItem + macro(200, function() + if storage[panelName].enabled and storage[panelName].spellName:len() > 0 and manapercent() > storage[panelName].minMana then + for _, spec in ipairs(getSpectators()) do + if not spec:isLocalPlayer() then + if spec:isPlayer() and storage[panelName].minFriendHp >= spec:getHealthPercent() and isFriend(spec:getName()) then + if storage[panelName].spellHeal then + saySpell(storage[panelName].spellName .. ' "' .. spec:getName(), 100) + return + end + healItem = findItem(storage[panelName].id) + if storage[panelName].itemHeal and distanceFromPlayer(spec:getPosition()) <= storage[panelName].distance and healItem then + useWith(storage[panelName].id, spec) + return + end + end + end + end + end + end) +addSeparator() \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/AttackBot.lua b/modules/game_bot/default_configs/vBot/AttackBot.lua new file mode 100644 index 0000000..f7a9a64 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/AttackBot.lua @@ -0,0 +1,1033 @@ +-- author: Vithrax +-- version 2.0 + +-- if you want to change tab, in line below insert: setDefaultTab("tab name") + + + +attackPanelName = "attackbot" +local ui = setupUI([[ +Panel + height: 38 + + BotSwitch + id: title + anchors.top: parent.top + anchors.left: parent.left + text-align: center + width: 130 + !text: tr('AttackBot') + + Button + id: settings + anchors.top: prev.top + anchors.left: prev.right + anchors.right: parent.right + margin-left: 3 + height: 17 + text: Setup + + Button + id: 1 + anchors.top: prev.bottom + anchors.left: parent.left + text: 1 + margin-right: 2 + margin-top: 4 + size: 17 17 + + Button + id: 2 + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + text: 2 + margin-left: 4 + size: 17 17 + + Button + id: 3 + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + text: 3 + margin-left: 4 + size: 17 17 + + Button + id: 4 + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + text: 4 + margin-left: 4 + size: 17 17 + + Button + id: 5 + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + text: 5 + margin-left: 4 + size: 17 17 + + Label + id: name + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + anchors.right: parent.right + text-align: center + margin-left: 4 + height: 17 + text: Profile #1 + background: #292A2A +]]) + +addSeparator() +ui:setId(attackPanelName) + +local i = 1 +local j = 1 +local k = 1 +local pvpDedicated = false +local item = false + +-- create blank profiles +if not storage[attackPanelName] or not storage[attackPanelName][1] or #storage[attackPanelName] ~= 5 then + storage[attackPanelName] = { + [1] = { + enabled = false, + attackTable = {}, + ignoreMana = true, + Kills = false, + Rotate = false, + name = "Profile #1", + Cooldown = true, + Visible = true, + pvpMode = false, + KillsAmount = 1, + PvpSafe = true, + BlackListSafe = false, + AntiRsRange = 5 + }, + [2] = { + enabled = false, + attackTable = {}, + ignoreMana = true, + Kills = false, + Rotate = false, + name = "Profile #2", + Cooldown = true, + Visible = true, + pvpMode = false, + KillsAmount = 1, + PvpSafe = true, + BlackListSafe = false, + AntiRsRange = 5 + }, + [3] = { + enabled = false, + attackTable = {}, + ignoreMana = true, + Kills = false, + Rotate = false, + name = "Profile #3", + Cooldown = true, + Visible = true, + pvpMode = false, + KillsAmount = 1, + PvpSafe = true, + BlackListSafe = false, + AntiRsRange = 5 + }, + [4] = { + enabled = false, + attackTable = {}, + ignoreMana = true, + Kills = false, + Rotate = false, + name = "Profile #4", + Cooldown = true, + Visible = true, + pvpMode = false, + KillsAmount = 1, + PvpSafe = true, + BlackListSafe = false, + AntiRsRange = 5 + }, + [5] = { + enabled = false, + attackTable = {}, + ignoreMana = true, + Kills = false, + Rotate = false, + name = "Profile #5", + Cooldown = true, + Visible = true, + pvpMode = false, + KillsAmount = 1, + PvpSafe = true, + BlackListSafe = false, + AntiRsRange = 5 + }, + } +end + +if not storage.currentBotProfile or storage.currentBotProfile == 0 or storage.currentBotProfile > 5 then + storage.currentBotProfile = 1 +end + +-- finding correct table, manual unfortunately +local currentSettings +local setActiveProfile = function() + local n = storage.currentBotProfile + currentSettings = storage[attackPanelName][n] +end +setActiveProfile() + +if not currentSettings.AntiRsRange then + currentSettings.AntiRsRange = 5 +end + +local activeProfileColor = function() + for i=1,5 do + if i == storage.currentBotProfile then + ui[i]:setColor("green") + else + ui[i]:setColor("white") + end + end +end +activeProfileColor() + +local categories = { + "Select Category", + "Area Spell (exevo mas san, exevo gran mas flam etc.)", + "Adjacent (exori, exori gran)", + "Front Sweep (exori min)", + "Wave (exevo tera hur, exevo gran vis lux)", + "Targeted Spell (exori ico, exori flam etc.)", + "Targeted Rune (sudden death, heavy magic missle etc.)", + "Area Rune (great fireball, avalanche etc.)", + "Empowerment (utito tempo)" +} + +local labels = { + "", + "Area Spell", + "Adjacent", + "Front Sweep", + "Wave", + "Targeted Spell", + "Targeted Rune", + "Area Rune", + "Buff" +} + +local range = { + "Select Range", + "Range: 1", + "Range: 2", + "Range: 3", + "Range: 4", + "Range: 5", + "Range: 6", + "Range: 7", + "Range: 8", + "Range: 9" +} + +local pattern = { + "Pattern", + "Single (exori frigo, SD)", + "Large AOE (mas tera)", + "Medium AOE (mas frigo)", + "Small AOE (mas san)", + "Large Wave (tera hur)", + "Medium Wave (frigo hur)", + "Small Wave (gran frigo hur)", + "Beam (exevo vis lux)", + "Adjacent (exori)", + "Area Rune (GFB, AVA)", + "Empowerment" +} + +ui.title.onClick = function(widget) +currentSettings.enabled = not currentSettings.enabled +widget:setOn(currentSettings.enabled) +end + +ui.settings.onClick = function(widget) + attackWindow:show() + attackWindow:raise() + attackWindow:focus() +end + +rootWidget = g_ui.getRootWidget() +if rootWidget then + attackWindow = g_ui.createWidget('AttackWindow', rootWidget) + attackWindow:hide() + + -- functions + local updateCategoryText = function() + attackWindow.category:setText(categories[i]) + end + local updateParameter1Text = function() + attackWindow.parameter1:setText(pattern[k]) + end + local updateParameter2Text = function() + attackWindow.parameter2:setText(range[j]) + end + + -- spin box + attackWindow.KillsAmount.onValueChange = function(widget, value) + currentSettings.KillsAmount = value + end + attackWindow.AntiRsRange.onValueChange = function(widget, value) + currentSettings.AntiRsRange = value + end + + -- checkbox + attackWindow.pvpSpell.onClick = function(widget) + pvpDedicated = not pvpDedicated + attackWindow.pvpSpell:setChecked(pvpDedicated) + end + attackWindow.IgnoreMana.onClick = function(widget) + currentSettings.ignoreMana = not currentSettings.ignoreMana + attackWindow.IgnoreMana:setChecked(currentSettings.ignoreMana) + end + attackWindow.Rotate.onClick = function(widget) + currentSettings.Rotate = not currentSettings.Rotate + attackWindow.Rotate:setChecked(currentSettings.Rotate) + end + attackWindow.Kills.onClick = function(widget) + currentSettings.Kills = not currentSettings.Kills + attackWindow.Kills:setChecked(currentSettings.Kills) + end + attackWindow.Cooldown.onClick = function(widget) + currentSettings.Cooldown = not currentSettings.Cooldown + attackWindow.Cooldown:setChecked(currentSettings.Cooldown) + end + attackWindow.Visible.onClick = function(widget) + currentSettings.Visible = not currentSettings.Visible + attackWindow.Visible:setChecked(currentSettings.Visible) + end + attackWindow.PvpMode.onClick = function(widget) + currentSettings.pvpMode = not currentSettings.pvpMode + attackWindow.PvpMode:setChecked(currentSettings.pvpMode) + end + attackWindow.PvpSafe.onClick = function(widget) + currentSettings.PvpSafe = not currentSettings.PvpSafe + attackWindow.PvpSafe:setChecked(currentSettings.PvpSafe) + end + attackWindow.BlackListSafe.onClick = function(widget) + currentSettings.BlackListSafe = not currentSettings.BlackListSafe + attackWindow.BlackListSafe:setChecked(currentSettings.BlackListSafe) + end + + --buttons + attackWindow.CloseButton.onClick = function(widget) + attackWindow:hide() + end + + local inputTypeToggle = function() + if attackWindow.category:getText():lower():find("rune") then + item = true + attackWindow.spellFormula:setText("") + attackWindow.spellFormula:hide() + attackWindow.spellDescription:hide() + attackWindow.itemId:show() + attackWindow.itemDescription:show() + else + item = false + attackWindow.itemId:setItemId(0) + attackWindow.itemId:hide() + attackWindow.itemDescription:hide() + attackWindow.spellFormula:show() + attackWindow.spellDescription:show() + end + end + + local setSimilarPattern = function() + if i == 2 then + k = 3 + elseif i == 3 then + k = 10 + elseif i == 4 then + k = 10 + elseif i == 5 then + k = 6 + elseif i == 6 or i == 7 then + k = 2 + elseif i == 8 then + k = 11 + elseif i == 9 then + k = 12 + end + end + + attackWindow.categoryNext.onClick = function(widget) + if i == #categories then + i = 1 + else + i = i + 1 + end + setSimilarPattern() + updateParameter1Text() + updateCategoryText() + inputTypeToggle() + end + + attackWindow.categoryPrev.onClick = function(widget) + if i == 1 then + i = #categories + else + i = i - 1 + end + setSimilarPattern() + updateParameter1Text() + updateCategoryText() + inputTypeToggle() + end + + attackWindow.parameter1Next.onClick = function(widget) + if k == #pattern then + k = 1 + else + k = k + 1 + end + updateParameter1Text() + end + + attackWindow.parameter1Prev.onClick = function(widget) + if k == 1 then + k = #pattern + else + k = k - 1 + end + updateParameter1Text() + end + + attackWindow.parameter2Next.onClick = function(widget) + if j == #range then + j = 1 + else + j = j + 1 + end + updateParameter2Text() + end + + attackWindow.parameter2Prev.onClick = function(widget) + if j == 1 then + j = #range + else + j = j - 1 + end + updateParameter2Text() + end + + local validVal = function(v) + if type(v) ~= "number" then + local val = tonumber(v) + if not val then return false end + end + if v >= 0 and v < 101 then + return true + else + return false + end + end + + local clearValues = function() + attackWindow.spellFormula:setText("") + attackWindow.minMana:setText(1) + attackWindow.minMonsters:setText(1) + attackWindow.itemId:setItemId(0) + attackWindow.newCooldown:setText(1) + pvpDedicated = false + item = false + attackWindow.pvpSpell:setChecked(false) + i = 1 + j = 1 + k = 1 + updateParameter1Text() + updateParameter2Text() + updateCategoryText() + inputTypeToggle() + end + + local setProfileName = function() + ui.name:setText(currentSettings.name) + end + attackWindow.Name.onTextChange = function(widget, text) + currentSettings.name = text + setProfileName() + end + + local refreshAttacks = function() + if currentSettings.attackTable then + for i, child in pairs(attackWindow.attackList:getChildren()) do + child:destroy() + end + for _, entry in pairs(currentSettings.attackTable) do + local label = g_ui.createWidget("AttackEntry", attackWindow.attackList) + label.enabled:setChecked(entry.enabled) + label.enabled.onClick = function(widget) + entry.enabled = not entry.enabled + label.enabled:setChecked(entry.enabled) + end + label.remove.onClick = function(widget) + table.removevalue(currentSettings.attackTable, entry) + reindexTable(currentSettings.attackTable) + label:destroy() + end + if entry.pvp then + label:setText("(" .. entry.manaCost .. "% MP) " .. labels[entry.category] .. ": " .. entry.attack .. " (Range: ".. entry.dist .. ")") + label:setColor("yellow") + else + label:setText("(" .. entry.manaCost .. "% MP & mob >= " .. entry.minMonsters .. ") " .. labels[entry.category] .. ": " .. entry.attack .. " (Range: ".. entry.dist .. ")") + label:setColor("green") + end + end + end + end + + + attackWindow.MoveUp.onClick = function(widget) + local input = attackWindow.attackList:getFocusedChild() + if not input then return end + local index = attackWindow.attackList:getChildIndex(input) + if index < 2 then return end + + local move + if currentSettings.attackTable and #currentSettings.attackTable > 0 then + for _, entry in pairs(currentSettings.attackTable) do + if entry.index == index -1 then + move = entry + end + if entry.index == index then + move.index = index + entry.index = index -1 + end + end + end + table.sort(currentSettings.attackTable, function(a,b) return a.index < b.index end) + + attackWindow.attackList:moveChildToIndex(input, index - 1) + attackWindow.attackList:ensureChildVisible(input) + end + + attackWindow.MoveDown.onClick = function(widget) + local input = attackWindow.attackList:getFocusedChild() + if not input then return end + local index = attackWindow.attackList:getChildIndex(input) + if index >= attackWindow.attackList:getChildCount() then return end + + local move + local move2 + if currentSettings.attackTable and #currentSettings.attackTable > 0 then + for _, entry in pairs(currentSettings.attackTable) do + if entry.index == index +1 then + move = entry + end + if entry.index == index then + move2 = entry + end + end + if move and move2 then + move.index = index + move2.index = index + 1 + end + end + table.sort(currentSettings.attackTable, function(a,b) return a.index < b.index end) + + attackWindow.attackList:moveChildToIndex(input, index + 1) + attackWindow.attackList:ensureChildVisible(input) + end + + attackWindow.addButton.onClick = function(widget) + local val + if (item and attackWindow.itemId:getItemId() <= 100) or (not item and attackWindow.spellFormula:getText():len() == 0) then + warn("AttackBot: missing spell or item id!") + elseif not tonumber(attackWindow.minMana:getText()) or not validVal(tonumber(attackWindow.minMana:getText())) then + warn("AttackBot: Mana Values incorrect! it has to be number from between 1 and 100") + elseif not tonumber(attackWindow.minMonsters:getText()) or not validVal(tonumber(attackWindow.minMonsters:getText())) then + warn("AttackBot: Monsters Count incorrect! it has to be number higher than 0") + elseif i == 1 or j == 1 or k == 1 then + warn("AttackBot: Categories not changed! You need to be more precise") + else + if item then + val = attackWindow.itemId:getItemId() + else + val = attackWindow.spellFormula:getText() + end + table.insert(currentSettings.attackTable, {index = #currentSettings.attackTable+1, cd = tonumber(attackWindow.newCooldown:getText()) ,attack = val, manaCost = tonumber(attackWindow.minMana:getText()), minMonsters = tonumber(attackWindow.minMonsters:getText()), pvp = pvpDedicated, dist = j-1, model = k, category = i, enabled = true}) + refreshAttacks() + clearValues() + end + end + + -- [[ if added new options, include them below]] + + + + + local loadSettings = function() + ui.title:setOn(currentSettings.enabled) + attackWindow.KillsAmount:setValue(currentSettings.KillsAmount) + updateCategoryText() + updateParameter1Text() + updateParameter2Text() + attackWindow.IgnoreMana:setChecked(currentSettings.ignoreMana) + attackWindow.Rotate:setChecked(currentSettings.Rotate) + attackWindow.Kills:setChecked(currentSettings.Kills) + setProfileName() + inputTypeToggle() + attackWindow.Name:setText(currentSettings.name) + refreshAttacks() + attackWindow.Visible:setChecked(currentSettings.Visible) + attackWindow.Cooldown:setChecked(currentSettings.Cooldown) + attackWindow.PvpMode:setChecked(currentSettings.pvpMode) + attackWindow.PvpSafe:setChecked(currentSettings.PvpSafe) + attackWindow.BlackListSafe:setChecked(currentSettings.BlackListSafe) + attackWindow.AntiRsRange:setValue(currentSettings.AntiRsRnage) + end + loadSettings() + + local profileChange = function() + setActiveProfile() + activeProfileColor() + loadSettings() + end + + -- profile buttons + for i=1,5 do + local button = ui[i] + button.onClick = function() + storage.currentBotProfile = i + profileChange() + end + end + + local resetSettings = function() + currentSettings.enabled = false + currentSettings.attackTable = {} + currentSettings.ignoreMana = true + currentSettings.Kills = false + currentSettings.Rotate = false + currentSettings.name = "Profile #" .. storage.currentBotProfile + currentSettings.Cooldown = true + currentSettings.Visible = true + currentSettings.pvpMode = false + currentSettings.pvpSafe = true + currentSettings.BlackListSafe = false + currentSettings.AntiRsRange = 5 + end + + + + + + -- [[ end ]] -- + + attackWindow.ResetSettings.onClick = function() + resetSettings() + loadSettings() + end + + + -- public functions + AttackBot = {} -- global table + + AttackBot.isOn = function() + return currentSettings.enabled + end + + AttackBot.isOff = function() + return not currentSettings.enabled + end + + AttackBot.setOff = function() + currentSettings.enabled = false + ui.title:setOn(currentSettings.enabled) + end + + AttackBot.setOn = function() + currentSettings.enabled = true + ui.title:setOn(currentSettings.enabled) + end + + AttackBot.getActiveProfile = function() + return storage.currentBotProfile -- returns number 1-5 + end + + AttackBot.setActiveProfile = function(n) + if not n or not tonumber(n) or n < 1 or n > 5 then + return error("[AttackBot] wrong profile parameter! should be 1 to 5 is " .. n) + else + storage.currentBotProfile = n + profileChange() + end + end +end + +-- executor +-- table example (attack = 3155, manaCost = 50(%), minMonsters = 5, pvp = true, dist = 3, model = 6, category = 3) +-- i = category +-- j = range +-- k = pattern - covered + +local patterns = { + "", + "", + [[ + 0000001000000 + 0000011100000 + 0000111110000 + 0001111111000 + 0011111111100 + 0111111111110 + 1111111111111 + 0111111111110 + 0011111111100 + 0001111111000 + 0000111110000 + 0000011100000 + 0000001000000 + ]], + [[ + 00000100000 + 00011111000 + 00111111100 + 01111111110 + 01111111110 + 11111111111 + 01111111110 + 01111111110 + 00111111100 + 00001110000 + 00000100000 + ]], + [[ + 0011100 + 0111110 + 1111111 + 1111111 + 1111111 + 0111110 + 0011100 + ]], + [[ + 0000NNN0000 + 0000NNN0000 + 0000NNN0000 + 00000N00000 + WWW00N00EEE + WWWWW0EEEEE + WWW00S00EEE + 00000S00000 + 0000SSS0000 + 0000SSS0000 + 0000SSS0000 + ]], + [[ + 000NNNNN000 + 000NNNNN000 + 0000NNN0000 + WW00NNN00EE + WWWW0N0EEEE + WWWWW0EEEEE + WWWW0S0EEEE + WW00SSS00EE + 0000SSS0000 + 000SSSSS000 + 000SSSSS000 + ]], + [[ + 00NNN00 + 00NNN00 + WW0N0EE + WWW0EEE + WW0S0EE + 00SSS00 + 00SSS00 + ]], + [[ + 0000000N0000000 + 0000000N0000000 + 0000000N0000000 + 0000000N0000000 + 0000000N0000000 + 0000000N0000000 + 0000000N0000000 + WWWWWWW0EEEEEEE + 0000000S0000000 + 0000000S0000000 + 0000000S0000000 + 0000000S0000000 + 0000000S0000000 + 0000000S0000000 + 0000000S0000000 + ]], + "", + "" +} + +local safePatterns = { + "", + "", + [[ + 000000010000000 + 000000111000000 + 000001111100000 + 000011111110000 + 000111111111000 + 001111111111100 + 011111111111110 + 111111111111111 + 011111111111110 + 001111111111100 + 000111111111000 + 000011111110000 + 000001111100000 + 000000111000000 + 000000010000000 + ]], + [[ + 0000011100000 + 0000111110000 + 0001111111000 + 0011111111100 + 0111111111110 + 0111111111110 + 1111111111111 + 0111111111110 + 0111111111110 + 0011111111100 + 0001111111000 + 0000111110000 + 0000011100000 + ]], + [[ + 000111000 + 001111100 + 011111110 + 111111111 + 111111111 + 111111111 + 011111110 + 001111100 + 000111000 + ]], + [[ + 0000NNNNN0000 + 0000NNNNN0000 + 0000NNNNN0000 + 0000NNNNN0000 + WWWW0NNN0EEEE + WWWWWNNNEEEEE + WWWWWW0EEEEEE + WWWWWSSSEEEEE + WWWW0SSS0EEEE + 0000SSSSS0000 + 0000SSSSS0000 + 0000SSSSS0000 + 0000SSSSS0000 + ]], + [[ + 000NNNNNNN000 + 000NNNNNNN000 + 000NNNNNNN000 + WWWWNNNNNEEEE + WWWWNNNNNEEEE + WWWWWNNNEEEEE + WWWWWW0EEEEEE + WWWWWSSSEEEEE + WWWWSSSSSEEEE + WWWWSSSSSEEEE + 000SSSSSSS000 + 000SSSSSSS000 + 000SSSSSSS000 + ]], + [[ + 00NNNNN00 + 00NNNNN00 + WWNNNNNEE + WWWWNEEEE + WWWW0EEEE + WWWWSEEEE + WWSSSSSEE + 00SSSSS00 + 00SSSSS00 + ]], + [[ + 0000000NNN0000000 + 0000000NNN0000000 + 0000000NNN0000000 + 0000000NNN0000000 + 0000000NNN0000000 + 0000000NNN0000000 + 0000000NNN0000000 + WWWWWWWNNNEEEEEEE + WWWWWWWW0EEEEEEEE + WWWWWWWSSSEEEEEEE + 0000000SSS0000000 + 0000000SSS0000000 + 0000000SSS0000000 + 0000000SSS0000000 + 0000000SSS0000000 + 0000000SSS0000000 + 0000000SSS0000000 + ]], + "", + "" +} + +local posN = [[ + 111 + 000 + 000 +]] +local posE = [[ + 001 + 001 + 001 +]] +local posS = [[ + 000 + 000 + 111 +]] +local posW = [[ + 100 + 100 + 100 +]] + +local bestTile +macro(100, function() + if not currentSettings.enabled then return end + if #currentSettings.attackTable == 0 or isInPz() or not target() or modules.game_cooldown.isGroupCooldownIconActive(1) then return end + + if g_game.getClientVersion() < 960 or not currentSettings.Cooldown then + delay(400) + end + + local monstersN = 0 + local monstersE = 0 + local monstersS = 0 + local monstersW = 0 + monstersN = getCreaturesInArea(pos(), posN, 2) + monstersE = getCreaturesInArea(pos(), posE, 2) + monstersS = getCreaturesInArea(pos(), posS, 2) + monstersW = getCreaturesInArea(pos(), posW, 2) + local posTable = {monstersE, monstersN, monstersS, monstersW} + local bestSide = 0 + local bestDir + -- pulling out the biggest number + for i, v in pairs(posTable) do + if v > bestSide then + bestSide = v + end + end + -- associate biggest number with turn direction + if monstersN == bestSide then bestDir = 0 + elseif monstersE == bestSide then bestDir = 1 + elseif monstersS == bestSide then bestDir = 2 + elseif monstersW == bestSide then bestDir = 3 + end + + if currentSettings.Rotate then + if player:getDirection() ~= bestDir and bestSide > 0 then + turn(bestDir) + end + end + + for _, entry in pairs(currentSettings.attackTable) do + if entry.enabled then + if (type(entry.attack) == "string" and canCast(entry.attack, not currentSettings.ignoreMana, not currentSettings.Cooldown)) or (type(entry.attack) == "number" and (not currentSettings.Visible or findItem(entry.attack))) then + if manapercent() >= entry.manaCost and distanceFromPlayer(target():getPosition()) <= entry.dist then + if currentSettings.pvpMode then + if entry.pvp then + if type(entry.attack) == "string" and target():canShoot() then + cast(entry.attack, entry.cd) + return + else + if not storage.isUsing and target():canShoot() then + g_game.useInventoryItemWith(entry.attack, target()) + return + end + end + end + else + if entry.category == 6 or entry.category == 7 then + if getMonsters(4) >= entry.minMonsters then + if type(entry.attack) == "number" then + if not storage.isUsing then + g_game.useInventoryItemWith(entry.attack, target()) + return + end + else + cast(entry.attack, entry.cd) + return + end + end + else + if (g_game.getClientVersion() < 960 or not currentSettings.Kills or killsToRs() > currentSettings.KillsAmount) and (not currentSettings.BlackListSafe or not isBlackListedPlayerInRange(currentSettings.AntiRsRange)) then + if entry.category == 8 then + bestTile = getBestTileByPatern(patterns[5], 2, entry.dist, not currentSettings.PvpSafe) + end + if entry.category == 4 and (not currentSettings.PvpSafe or isSafe(2, false)) and bestSide >= entry.minMonsters then + cast(entry.attack, entry.cd) + return + elseif entry.category == 3 and (not currentSettings.PvpSafe or isSafe(2, false)) and getMonsters(1) >= entry.minMonsters then + cast(entry.attack, entry.cd) + return + elseif entry.category == 5 and getCreaturesInArea(player, patterns[entry.model], 2) >= entry.minMonsters and (not currentSettings.PvpSafe or getCreaturesInArea(player, safePatterns[entry.model], 3) == 0) then + cast(entry.attack, entry.cd) + return + elseif entry.category == 2 and getCreaturesInArea(pos(), patterns[entry.model], 2) >= entry.minMonsters and (not currentSettings.PvpSafe or getCreaturesInArea(pos(), safePatterns[entry.model], 3) == 0) then + cast(entry.attack, entry.cd) + return + elseif entry.category == 8 and bestTile and bestTile.count >= entry.minMonsters then + if not storage.isUsing then + g_game.useInventoryItemWith(entry.attack, bestTile.pos:getTopUseThing()) + end + return + elseif entry.category == 9 and not isBuffed() and getMonsters(entry.dist) >= entry.minMonsters then + cast(entry.attack, entry.cd) + return + else + if entry.category == 6 or entry.category == 7 then + if getMonsters(4) >= entry.minMonsters then + if type(entry.attack) == "number" then + if not storage.isUsing then + g_game.useInventoryItemWith(entry.attack, target()) + return + end + else + cast(entry.attack, entry.cd) + return + end + end + end + end + else + if entry.category == 6 or entry.category == 7 then + if getMonsters(4) >= entry.minMonsters then + if type(entry.attack) == "number" then + if not storage.isUsing then + g_game.useInventoryItemWith(entry.attack, target()) + return + end + else + cast(entry.attack, entry.cd) + return + end + end + end + end + end + end + end + end + end + end +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/AttackBot.otui b/modules/game_bot/default_configs/vBot/AttackBot.otui new file mode 100644 index 0000000..5ca5023 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/AttackBot.otui @@ -0,0 +1,402 @@ +AttackEntry < Label + background-color: alpha + text-offset: 18 0 + focusable: true + height: 16 + + CheckBox + id: enabled + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + width: 15 + height: 15 + margin-top: 2 + margin-left: 3 + + $focus: + background-color: #00000055 + + Button + id: remove + !text: tr('x') + anchors.right: parent.right + margin-right: 15 + width: 15 + height: 15 + +AttackWindow < MainWindow + !text: tr('AttackBot') + size: 800 350 + @onEscape: self:hide() + + TextList + id: attackList + anchors.left: parent.left + anchors.top: parent.top + padding: 1 + size: 500 150 + margin-left: 3 + margin-top: 3 + margin-left: 3 + vertical-scrollbar: attackListScrollBar + + VerticalScrollBar + id: attackListScrollBar + anchors.top: attackList.top + anchors.bottom: attackList.bottom + anchors.right: attackList.right + step: 14 + pixels-scroll: true + + Label + id: category + anchors.top: attackList.bottom + anchors.left: attackList.left + anchors.right: attackList.right + text-align: center + margin-top: 5 + image-source: /images/ui/panel_flat + image-border: 5 + height: 21 + margin-left: 25 + margin-right: 25 + + NextButton + id: categoryNext + anchors.left: category.right + anchors.verticalCenter: category.verticalCenter + margin-left: 10 + + PreviousButton + id: categoryPrev + anchors.right: category.left + anchors.verticalCenter: category.verticalCenter + margin-right: 10 + + Label + id: parameter1 + anchors.top: category.bottom + anchors.left: category.left + anchors.right: category.horizontalCenter + margin-top: 5 + margin-right: 25 + height: 21 + text-align: center + image-source: /images/ui/panel_flat + image-border: 5 + + NextButton + id: parameter1Next + anchors.left: parameter1.right + anchors.verticalCenter: parameter1.verticalCenter + margin-left: 10 + + PreviousButton + id: parameter1Prev + anchors.right: parameter1.left + anchors.verticalCenter: parameter1.verticalCenter + margin-right: 10 + + Label + id: parameter2 + anchors.top: category.bottom + anchors.left: category.horizontalCenter + anchors.right: category.right + margin-top: 5 + margin-left: 25 + height: 21 + text-align: center + image-source: /images/ui/panel_flat + image-border: 5 + + NextButton + id: parameter2Next + anchors.left: parameter2.right + anchors.verticalCenter: parameter2.verticalCenter + margin-left: 10 + + PreviousButton + id: parameter2Prev + anchors.right: parameter2.left + anchors.verticalCenter: parameter2.verticalCenter + margin-right: 10 + + TextEdit + id: spellFormula + anchors.left: parent.left + anchors.top: parameter2Prev.bottom + margin-top: 20 + margin-left: 30 + width: 200 + + Label + id: spellDescription + anchors.left: prev.left + anchors.right: prev.right + anchors.bottom: prev.top + margin-bottom: 2 + text-align: center + text: Insert Spell Formula Below + + BotItem + id: itemId + anchors.left: parent.left + anchors.top: parameter2Prev.bottom + margin-top: 10 + margin-left: 20 + + Label + id: itemDescription + anchors.left: itemId.right + margin-left: 5 + anchors.verticalCenter: itemId.verticalCenter + text: < insert id or drag item here + + Label + anchors.left: parent.left + anchors.bottom: BottomSeparator.top + margin-bottom: 10 + text-align: center + text: Min Monsters: + + SpinBox + id: minMonsters + anchors.left: prev.right + anchors.verticalCenter: prev.verticalCenter + margin-left: 5 + width: 45 + minimum: 1 + maximum: 100 + focusable: true + + Label + anchors.left: minMonsters.right + anchors.verticalCenter: minMonsters.verticalCenter + margin-left: 10 + text-align: center + text: Min Mana%: + + SpinBox + id: minMana + anchors.left: prev.right + anchors.verticalCenter: prev.verticalCenter + margin-left: 5 + width: 45 + minimum: 1 + maximum: 100 + focusable: true + + Label + anchors.left: prev.right + anchors.verticalCenter: prev.verticalCenter + margin-left: 10 + text: Cooldown(ms): + !tooltip: tr('Optional, can be left at 1, recommended for custom spells/old tibia') + + SpinBox + id: newCooldown + anchors.left: prev.right + anchors.verticalCenter: prev.verticalCenter + margin-left: 5 + width: 60 + minimum: 0 + maximum: 99999 + focusable: true + + CheckBox + id: pvpSpell + anchors.verticalCenter: spellFormula.verticalCenter + anchors.left: spellFormula.right + width: 100 + margin-left: 50 + text: Spell for PVP + + Button + id: addButton + anchors.right: attackList.right + anchors.bottom: BottomSeparator.top + text-align: center + text: Add + margin-bottom: 10 + size: 80 20 + + Button + id: MoveUp + anchors.right: prev.right + anchors.bottom: prev.top + size: 80 20 + text: Move Up + margin-bottom: 2 + + Button + id: MoveDown + anchors.right: prev.right + anchors.bottom: prev.top + size: 80 20 + text: Move Down + text-align: center + margin-bottom: 2 + + VerticalSeparator + anchors.top: parent.top + anchors.bottom: BottomSeparator.top + anchors.left: MoveDown.right + margin-top: 3 + margin-bottom: 3 + margin-left: 10 + + Label + id: thing + anchors.left: prev.right + anchors.right: parent.right + anchors.top: parent.top + margin-top: 3 + text-align: center + text: Additional Options + + HorizontalSeparator + anchors.left: prev.left + anchors.right: prev.right + anchors.top: prev.bottom + margin-top: 3 + margin-left: 5 + + CheckBox + id: IgnoreMana + anchors.top: prev.bottom + anchors.left: prev.left + margin-top: 10 + margin-left: 5 + width: 200 + text: Check RL Tibia conditions + + CheckBox + id: Kills + anchors.top: prev.bottom + anchors.left: prev.left + margin-top: 8 + width: 200 + height: 22 + text: Don't use area attacks if less than kills to red skull + text-wrap: true + text-align: left + + SpinBox + id: KillsAmount + anchors.top: prev.top + anchors.bottom: prev.bottom + anchors.left: prev.right + text-align: center + width: 50 + minimum: 1 + maximum: 10 + focusable: true + margin-left: 5 + + Label + anchors.left: Kills.left + anchors.bottom: BottomSeparator.top + margin-bottom: 8 + text: Profile: + + TextEdit + id: Name + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 5 + + Button + id: ResetSettings + anchors.verticalCenter: prev.verticalCenter + anchors.right: parent.right + text: Reset Settings + margin-top: 1 + + CheckBox + id: Rotate + anchors.top: Kills.bottom + anchors.left: Kills.left + margin-top: 8 + width: 220 + text: Turn to side with most monsters + + CheckBox + id: Cooldown + anchors.top: prev.bottom + anchors.left: prev.left + margin-top: 8 + width: 220 + text: Check spell cooldowns + + CheckBox + id: Visible + anchors.top: prev.bottom + anchors.left: prev.left + margin-top: 8 + width: 245 + text: Items must be visible (recommended) + + CheckBox + id: PvpMode + anchors.top: prev.bottom + anchors.left: prev.left + margin-top: 8 + width: 245 + text: PVP mode + + CheckBox + id: PvpSafe + anchors.top: prev.bottom + anchors.left: prev.left + margin-top: 8 + width: 245 + text: PVP safe + + CheckBox + id: BlackListSafe + anchors.top: prev.bottom + anchors.left: prev.left + margin-top: 8 + width: 200 + height: 18 + text: Stop if Anti-RS player in range + + SpinBox + id: AntiRsRange + anchors.top: prev.top + anchors.bottom: prev.bottom + anchors.left: prev.right + text-align: center + width: 50 + minimum: 1 + maximum: 10 + focusable: true + margin-left: 5 + + Label + anchors.left: thing.left + anchors.right: thing.right + anchors.bottom: ResetSettings.top + margin-bottom: 10 + text: Note: Cooldown value is optional for new global Tibia, recommended for Old tibia and custom OT + text-wrap: true + text-align: center + height: 40 + multiline: true + + HorizontalSeparator + id: BottomSeparator + anchors.right: parent.right + anchors.left: parent.left + anchors.bottom: CloseButton.top + margin-bottom: 8 + + Button + id: CloseButton + !text: tr('Close') + font: cipsoftFont + anchors.right: parent.right + anchors.bottom: parent.bottom + size: 45 21 + margin-top: 15 + margin-right: 5 \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/BotServer.otui b/modules/game_bot/default_configs/vBot/BotServer.otui new file mode 100644 index 0000000..b9dbc87 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/BotServer.otui @@ -0,0 +1,145 @@ +BotServerData < Panel + size: 340 70 + image-source: /images/ui/window + image-border: 6 + padding: 3 + + Label + id: label + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + text-align: center + !text: tr("BotServer Data") + + Label + id: label + anchors.top: parent.top + anchors.left: parent.left + margin-top: 23 + text-align: center + text: Channel Name: + margin-left: 6 + + TextEdit + id: Channel + anchors.top: parent.top + anchors.left: prev.right + margin-top: 20 + width: 150 + margin-left: 5 + text-align: center + + Button + id: Random + anchors.left: prev.right + anchors.top: prev.top + anchors.right: parent.right + text-align: center + text: Randomize + margin-left: 6 + margin-right: 6 + + Label + id: label + anchors.left: parent.left + anchors.bottom: parent.bottom + margin-left: 6 + margin-bottom: 4 + text-align: center + text: Status: + + BotLabel + id: ServerStatus + anchors.left: prev.right + anchors.bottom: parent.bottom + margin-left: 10 + margin-bottom: 4 + text-align: center + text: CONNECTED + + BotLabel + id: Participants + anchors.right: parent.right + anchors.bottom: parent.bottom + margin-right: 8 + margin-bottom: 4 + text-align: center + + Label + id: label + anchors.right: Participants.left + anchors.bottom: parent.bottom + margin-right: 10 + margin-bottom: 4 + text-align: center + text: Members: + +FeaturePanel < Panel + size: 340 150 + image-source: /images/ui/panel_flat + image-border: 5 + padding: 3 + + Label + id: title + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + text-align: center + text: Features + + HorizontalSeparator + id: sep + anchors.top: prev.bottom + anchors.left: parent.left + anchors.right: parent.right + margin-top: 2 + + BotSwitch + id: Feature1 + anchors.top: prev.bottom + anchors.left: parent.left + margin-left: 3 + margin-top: 5 + text: Mana info + + BotSwitch + id: Feature2 + anchors.top: sep.bottom + anchors.left: prev.right + margin-top: 5 + margin-left: 5 + text: MWall info + +BotServerWindow < MainWindow + !text: tr('BotServer') + size: 370 310 + @onEscape: self:hide() + + BotServerData + id: Data + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + + FeaturePanel + id: Features + anchors.top: prev.bottom + anchors.horizontalCenter: parent.horizontalCenter + margin-top: 10 + + HorizontalSeparator + id: separator + anchors.right: parent.right + anchors.left: parent.left + anchors.bottom: closeButton.top + margin-bottom: 8 + + Button + id: closeButton + !text: tr('Close') + font: cipsoftFont + anchors.right: parent.right + anchors.bottom: parent.bottom + size: 45 21 + margin-top: 15 + margin-right: 5 \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/Conditions.otui b/modules/game_bot/default_configs/vBot/Conditions.otui new file mode 100644 index 0000000..eadf1f9 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/Conditions.otui @@ -0,0 +1,425 @@ +UturaComboBoxPopupMenu < ComboBoxPopupMenu +UturaComboBoxPopupMenuButton < ComboBoxPopupMenuButton +UturaComboBox < ComboBox + @onSetup: | + self:addOption("Utura") + self:addOption("Utura Gran") + +CureConditions < Panel + id: Cure + image-source: /images/ui/panel_flat + image-border: 6 + padding: 3 + size: 200 190 + + Label + id: label1 + anchors.top: parent.top + anchors.left: parent.left + margin-top: 10 + margin-left: 5 + text: Poison + color: #ffaa00 + + Label + id: label11 + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 40 + text: Mana: + + TextEdit + id: PoisonCost + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 3 + width: 40 + + CheckBox + id: CurePoison + anchors.verticalCenter: prev.verticalCenter + anchors.right: parent.right + margin-right: 10 + + Label + id: label2 + anchors.left: label1.left + anchors.top: label1.bottom + margin-top: 10 + text: Curse + color: #ffaa00 + + Label + id: label22 + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 44 + text: Mana: + + TextEdit + id: CurseCost + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 3 + width: 40 + + CheckBox + id: CureCurse + anchors.verticalCenter: prev.verticalCenter + anchors.right: parent.right + margin-right: 10 + + Label + id: label3 + anchors.left: label2.left + anchors.top: label2.bottom + margin-top: 10 + text: Bleed + color: #ffaa00 + + Label + id: label33 + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 46 + text: Mana: + + TextEdit + id: BleedCost + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 3 + width: 40 + + CheckBox + id: CureBleed + anchors.verticalCenter: prev.verticalCenter + anchors.right: parent.right + margin-right: 10 + + Label + id: label4 + anchors.left: label3.left + anchors.top: label3.bottom + margin-top: 10 + text: Burn + color: #ffaa00 + + Label + id: label44 + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 50 + text: Mana: + + TextEdit + id: BurnCost + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 3 + width: 40 + + CheckBox + id: CureBurn + anchors.verticalCenter: prev.verticalCenter + anchors.right: parent.right + margin-right: 10 + + Label + id: label5 + anchors.left: label4.left + anchors.top: label4.bottom + margin-top: 10 + text: Electify + color: #ffaa00 + + Label + id: label55 + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 33 + text: Mana: + + TextEdit + id: ElectrifyCost + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 3 + width: 40 + + CheckBox + id: CureElectrify + anchors.verticalCenter: prev.verticalCenter + anchors.right: parent.right + margin-right: 10 + + Label + id: label6 + anchors.left: label5.left + anchors.top: label5.bottom + margin-top: 10 + text: Paralyse + color: #ffaa00 + + Label + id: label66 + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 26 + text: Mana: + + TextEdit + id: ParalyseCost + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 3 + width: 40 + + CheckBox + id: CureParalyse + anchors.verticalCenter: prev.verticalCenter + anchors.right: parent.right + margin-right: 10 + + Label + id: label7 + anchors.left: label6.left + anchors.top: label6.bottom + margin-top: 10 + margin-left: 12 + text: Spell: + + TextEdit + id: ParalyseSpell + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 10 + width: 100 + +HoldConditions < Panel + id: Hold + image-source: /images/ui/panel_flat + image-border: 6 + padding: 3 + size: 200 190 + + Label + id: label1 + anchors.top: parent.top + anchors.left: parent.left + margin-top: 10 + margin-left: 5 + text: Haste + color: #ffaa00 + + Label + id: label11 + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 44 + text: Mana: + + TextEdit + id: HasteCost + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 3 + width: 40 + + CheckBox + id: HoldHaste + anchors.verticalCenter: prev.verticalCenter + anchors.right: parent.right + margin-right: 10 + + Label + id: label2 + anchors.left: label1.left + anchors.top: label1.bottom + margin-top: 10 + margin-left: 12 + text: Spell: + + TextEdit + id: HasteSpell + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 10 + width: 100 + + Label + id: label3 + anchors.left: label1.left + anchors.top: label2.bottom + margin-top: 10 + text: Utana Vid + color: #ffaa00 + + Label + id: label33 + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 21 + text: Mana: + + TextEdit + id: UtanaCost + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 3 + width: 40 + + CheckBox + id: HoldUtana + anchors.verticalCenter: prev.verticalCenter + anchors.right: parent.right + margin-right: 10 + + Label + id: label4 + anchors.left: label3.left + anchors.top: label3.bottom + margin-top: 10 + text: Utamo Vita + color: #ffaa00 + + Label + id: label44 + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 12 + text: Mana: + + TextEdit + id: UtamoCost + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 3 + width: 40 + + CheckBox + id: HoldUtamo + anchors.verticalCenter: prev.verticalCenter + anchors.right: parent.right + margin-right: 10 + + Label + id: label5 + anchors.left: label4.left + anchors.top: label4.bottom + margin-top: 10 + text: Recovery + color: #ffaa00 + + Label + id: label55 + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 20 + text: Mana: + + TextEdit + id: UturaCost + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 3 + width: 40 + + CheckBox + id: HoldUtura + anchors.verticalCenter: prev.verticalCenter + anchors.right: parent.right + margin-right: 10 + + Label + id: label6 + anchors.left: label5.left + anchors.top: label5.bottom + margin-top: 10 + margin-left: 12 + text: Spell: + + UturaComboBox + id: UturaType + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 10 + width: 100 + + CheckBox + id: IgnoreInPz + anchors.left: label5.left + anchors.top: label6.bottom + margin-top: 12 + + Label + anchors.verticalCenter: IgnoreInPz.verticalCenter + anchors.left: prev.right + margin-top: 3 + margin-left: 5 + text: Don't Cast in Protection Zones + font: cipsoftFont + + CheckBox + id: StopHaste + anchors.horizontalCenter: IgnoreInPz.horizontalCenter + anchors.top: IgnoreInPz.bottom + margin-top: 8 + + Label + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-top: 3 + margin-left: 5 + text: Stop Haste if TargetBot Is Active + font: cipsoftFont + +ConditionsWindow < MainWindow + !text: tr('Condition Manager') + size: 445 280 + @onEscape: self:hide() + + CureConditions + id: Cure + anchors.top: parent.top + anchors.left: parent.left + margin-top: 7 + + Label + id: label + anchors.top: parent.top + anchors.left: parent.left + text: Cure Conditions + color: #88e3dd + margin-left: 10 + + HoldConditions + id: Hold + anchors.top: parent.top + anchors.right: parent.right + margin-top: 7 + + Label + id: label + anchors.top: parent.top + anchors.right: parent.right + text: Hold Conditions + color: #88e3dd + margin-right: 100 + + HorizontalSeparator + id: separator + anchors.right: parent.right + anchors.left: parent.left + anchors.bottom: closeButton.top + margin-bottom: 8 + + Button + id: closeButton + !text: tr('Close') + font: cipsoftFont + anchors.right: parent.right + anchors.bottom: parent.bottom + size: 45 21 + margin-top: 15 + margin-right: 5 \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/HealBot.otui b/modules/game_bot/default_configs/vBot/HealBot.otui new file mode 100644 index 0000000..4f45c9e --- /dev/null +++ b/modules/game_bot/default_configs/vBot/HealBot.otui @@ -0,0 +1,406 @@ +SpellSourceBoxPopupMenu < ComboBoxPopupMenu +SpellSourceBoxPopupMenuButton < ComboBoxPopupMenuButton +SpellSourceBox < ComboBox + @onSetup: | + self:addOption("Current Mana") + self:addOption("Current Health") + self:addOption("Mana Percent") + self:addOption("Health Percent") + self:addOption("Burst Damage") + +SpellConditionBoxPopupMenu < ComboBoxPopupMenu +SpellConditionBoxPopupMenuButton < ComboBoxPopupMenuButton +SpellConditionBox < ComboBox + @onSetup: | + self:addOption("Below") + self:addOption("Above") + self:addOption("Equal To") + +SpellEntry < Label + background-color: alpha + text-offset: 18 0 + focusable: true + height: 16 + + CheckBox + id: enabled + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + width: 15 + height: 15 + margin-top: 2 + margin-left: 3 + + $focus: + background-color: #00000055 + + Button + id: remove + !text: tr('x') + anchors.right: parent.right + margin-right: 15 + width: 15 + height: 15 + +ItemEntry < Label + background-color: alpha + text-offset: 2 0 + focusable: true + height: 16 + + $focus: + background-color: #00000055 + + Button + id: remove + !text: tr('x') + anchors.right: parent.right + margin-right: 15 + width: 15 + height: 15 + +SpellHealing < Panel + image-source: /images/ui/panel_flat + image-border: 6 + padding: 3 + size: 490 130 + + Label + id: whenSpell + anchors.left: spellList.right + anchors.top: parent.top + text: When + margin-top: 10 + margin-left: 7 + + SpellSourceBox + id: spellSource + anchors.top: parent.top + anchors.left: whenSpell.right + margin-top: 5 + margin-left: 35 + width: 128 + + Label + id: isSpell + anchors.left: spellList.right + anchors.top: whenSpell.bottom + text: Is + margin-top: 9 + margin-left: 7 + + SpellConditionBox + id: spellCondition + anchors.left: spellSource.left + anchors.top: spellSource.bottom + marin-top: 15 + width: 80 + + TextEdit + id: spellValue + anchors.left: spellCondition.right + anchors.top: spellCondition.top + anchors.bottom: spellCondition.bottom + width: 49 + + Label + id: castSpell + anchors.left: isSpell.left + anchors.top: isSpell.bottom + text: Cast + margin-top: 9 + + TextEdit + id: spellFormula + anchors.left: spellCondition.left + anchors.top: spellCondition.bottom + anchors.right: spellValue.right + + Label + id: manaSpell + anchors.left: castSpell.left + anchors.top: castSpell.bottom + text: Mana Cost: + margin-top: 8 + + TextEdit + id: manaCost + anchors.left: spellFormula.left + anchors.top: spellFormula.bottom + width: 40 + + TextList + id: spellList + anchors.left: parent.left + anchors.bottom: parent.bottom + padding: 1 + size: 270 116 + margin-bottom: 3 + margin-left: 3 + vertical-scrollbar: spellListScrollBar + + VerticalScrollBar + id: spellListScrollBar + anchors.top: spellList.top + anchors.bottom: spellList.bottom + anchors.right: spellList.right + step: 14 + pixels-scroll: true + + Button + id: addSpell + anchors.right: spellFormula.right + anchors.bottom: parent.bottom + margin-bottom: 2 + margin-right: 10 + text: Add + size: 40 17 + font: cipsoftFont + + Button + id: MoveUp + anchors.right: prev.left + anchors.bottom: parent.bottom + margin-bottom: 2 + margin-right: 5 + text: Move Up + size: 55 17 + font: cipsoftFont + + Button + id: MoveDown + anchors.right: prev.left + anchors.bottom: parent.bottom + margin-bottom: 2 + margin-right: 5 + text: Move Down + size: 55 17 + font: cipsoftFont + +ItemHealing < Panel + image-source: /images/ui/panel_flat + image-border: 6 + padding: 3 + size: 490 130 + + Label + id: whenItem + anchors.left: itemList.right + anchors.top: parent.top + text: When + margin-top: 10 + margin-left: 7 + + SpellSourceBox + id: itemSource + anchors.top: parent.top + anchors.left: whenItem.right + margin-top: 5 + margin-left: 35 + width: 128 + + Label + id: isItem + anchors.left: itemList.right + anchors.top: whenItem.bottom + text: Is + margin-top: 9 + margin-left: 7 + + SpellConditionBox + id: itemCondition + anchors.left: itemSource.left + anchors.top: itemSource.bottom + marin-top: 15 + width: 80 + + TextEdit + id: itemValue + anchors.left: itemCondition.right + anchors.top: itemCondition.top + anchors.bottom: itemCondition.bottom + width: 49 + + Label + id: useItem + anchors.left: isItem.left + anchors.top: isItem.bottom + text: Use + margin-top: 15 + + BotItem + id: itemId + anchors.left: itemCondition.left + anchors.top: itemCondition.bottom + + TextList + id: itemList + anchors.left: parent.left + anchors.bottom: parent.bottom + padding: 1 + size: 270 116 + margin-top: 3 + margin-bottom: 3 + margin-left: 3 + vertical-scrollbar: itemListScrollBar + + VerticalScrollBar + id: itemListScrollBar + anchors.top: itemList.top + anchors.bottom: itemList.bottom + anchors.right: itemList.right + step: 14 + pixels-scroll: true + + Button + id: addItem + anchors.right: itemValue.right + anchors.bottom: parent.bottom + margin-bottom: 2 + margin-right: 10 + text: Add + size: 40 17 + font: cipsoftFont + + Button + id: MoveUp + anchors.right: prev.left + anchors.bottom: parent.bottom + margin-bottom: 2 + margin-right: 5 + text: Move Up + size: 55 17 + font: cipsoftFont + + Button + id: MoveDown + anchors.right: prev.left + anchors.bottom: parent.bottom + margin-bottom: 2 + margin-right: 5 + text: Move Down + size: 55 17 + font: cipsoftFont + +HealWindow < MainWindow + !text: tr('Self Healer') + size: 800 350 + @onEscape: self:hide() + + SpellHealing + id: spells + anchors.top: parent.top + anchors.left: parent.left + + ItemHealing + id: items + anchors.top: prev.bottom + anchors.left: parent.left + margin-top: 10 + + VerticalSeparator + id: sep + anchors.top: parent.top + anchors.left: prev.right + anchors.bottom: separator.top + margin-left: 10 + margin-bottom: 5 + + Label + anchors.left: prev.right + anchors.right: parent.right + anchors.top: parent.top + text-align: center + text: Additional Options + + HorizontalSeparator + anchors.left: prev.left + anchors.top: prev.bottom + anchors.right: prev.right + margin-top: 5 + margin-left: 10 + + CheckBox + id: Cooldown + anchors.top: prev.bottom + anchors.left: prev.left + margin-top: 10 + margin-left: 5 + width: 200 + text: Check spell cooldowns + + CheckBox + id: Visible + anchors.top: prev.bottom + anchors.left: prev.left + margin-top: 8 + width: 250 + text: Items must be visible (recommended) + + CheckBox + id: Delay + anchors.top: prev.bottom + anchors.left: prev.left + margin-top: 8 + width: 250 + text: Don't use items when interacting + + CheckBox + id: Interval + anchors.top: prev.bottom + anchors.left: prev.left + margin-top: 8 + width: 250 + text: Additional delay when looting corpses + + CheckBox + id: Conditions + anchors.top: prev.bottom + anchors.left: prev.left + margin-top: 8 + width: 250 + text: Also check conditions from RL Tibia + + CheckBox + id: MessageDelay + anchors.top: prev.bottom + anchors.left: prev.left + margin-top: 8 + width: 250 + text: Cooldown based on "Aaaah..." message + + Label + anchors.left: Visible.left + anchors.bottom: separator.top + margin-bottom: 8 + text: Profile: + + TextEdit + id: Name + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 5 + + Button + id: ResetSettings + anchors.verticalCenter: prev.verticalCenter + anchors.right: parent.right + text: Reset Settings + margin-top: 1 + + HorizontalSeparator + id: separator + anchors.right: parent.right + anchors.left: parent.left + anchors.bottom: closeButton.top + margin-bottom: 8 + + Button + id: closeButton + !text: tr('Close') + font: cipsoftFont + anchors.right: parent.right + anchors.bottom: parent.bottom + size: 45 21 + margin-top: 15 + margin-right: 5 \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/Title.lua b/modules/game_bot/default_configs/vBot/Title.lua new file mode 100644 index 0000000..506cf97 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/Title.lua @@ -0,0 +1,20 @@ +local vocation = player:getVocation() +local vocText = "" + +if vocation == 1 or vocation == 11 then + vocText = "- EK" +elseif vocation == 2 or vocation == 12 then + vocText = "- RP" +elseif vocation == 3 or vocation == 13 then + vocText = "- MS" +elseif vocation == 4 or vocation == 14 then + vocText = "- ED" +end + +macro(2000, function() + if hppercent() > 0 then + g_window.setTitle("Tibia - " .. player:getName() .. " - " .. lvl() .. "lvl " .. vocText) + else + g_window.setTitle("Tibia - " .. player:getName() .. " - DEAD") + end +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/_Conditions.lua b/modules/game_bot/default_configs/vBot/_Conditions.lua new file mode 100644 index 0000000..d4e8b86 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/_Conditions.lua @@ -0,0 +1,242 @@ +setDefaultTab("HP") + local conditionPanelName = "ConditionPanel" + local ui = setupUI([[ +Panel + height: 19 + + BotSwitch + id: title + anchors.top: parent.top + anchors.left: parent.left + text-align: center + width: 130 + !text: tr('Conditions') + + Button + id: conditionList + anchors.top: prev.top + anchors.left: prev.right + anchors.right: parent.right + margin-left: 3 + height: 17 + text: Setup + + ]]) + ui:setId(conditionPanelName) + + if not storage[conditionPanelName] then + storage[conditionPanelName] = { + enabled = false, + curePosion = false, + poisonCost = 20, + cureCurse = false, + curseCost = 80, + cureBleed = false, + bleedCost = 45, + cureBurn = false, + burnCost = 30, + cureElectrify = false, + electrifyCost = 22, + cureParalyse = false, + paralyseCost = 40, + paralyseSpell = "utani hur", + holdHaste = false, + hasteCost = 40, + hasteSpell = "utani hur", + holdUtamo = false, + utamoCost = 40, + holdUtana = false, + utanaCost = 440, + holdUtura = false, + uturaType = "", + uturaCost = 100, + ignoreInPz = true, + stopHaste = false + } + end + + ui.title:setOn(storage[conditionPanelName].enabled) + ui.title.onClick = function(widget) + storage[conditionPanelName].enabled = not storage[conditionPanelName].enabled + widget:setOn(storage[conditionPanelName].enabled) + end + + ui.conditionList.onClick = function(widget) + conditionsWindow:show() + conditionsWindow:raise() + conditionsWindow:focus() + end + + + + local rootWidget = g_ui.getRootWidget() + if rootWidget then + conditionsWindow = g_ui.createWidget('ConditionsWindow', rootWidget) + conditionsWindow:hide() + + -- text edits + conditionsWindow.Cure.PoisonCost:setText(storage[conditionPanelName].poisonCost) + conditionsWindow.Cure.PoisonCost.onTextChange = function(widget, text) + storage[conditionPanelName].poisonCost = tonumber(text) + end + + conditionsWindow.Cure.CurseCost:setText(storage[conditionPanelName].curseCost) + conditionsWindow.Cure.CurseCost.onTextChange = function(widget, text) + storage[conditionPanelName].curseCost = tonumber(text) + end + + conditionsWindow.Cure.BleedCost:setText(storage[conditionPanelName].bleedCost) + conditionsWindow.Cure.BleedCost.onTextChange = function(widget, text) + storage[conditionPanelName].bleedCost = tonumber(text) + end + + conditionsWindow.Cure.BurnCost:setText(storage[conditionPanelName].burnCost) + conditionsWindow.Cure.BurnCost.onTextChange = function(widget, text) + storage[conditionPanelName].burnCost = tonumber(text) + end + + conditionsWindow.Cure.ElectrifyCost:setText(storage[conditionPanelName].electrifyCost) + conditionsWindow.Cure.ElectrifyCost.onTextChange = function(widget, text) + storage[conditionPanelName].electrifyCost = tonumber(text) + end + + conditionsWindow.Cure.ParalyseCost:setText(storage[conditionPanelName].paralyseCost) + conditionsWindow.Cure.ParalyseCost.onTextChange = function(widget, text) + storage[conditionPanelName].paralyseCost = tonumber(text) + end + + conditionsWindow.Cure.ParalyseSpell:setText(storage[conditionPanelName].paralyseSpell) + conditionsWindow.Cure.ParalyseSpell.onTextChange = function(widget, text) + storage[conditionPanelName].paralyseSpell = text + end + + conditionsWindow.Hold.HasteSpell:setText(storage[conditionPanelName].hasteSpell) + conditionsWindow.Hold.HasteSpell.onTextChange = function(widget, text) + storage[conditionPanelName].hasteSpell = text + end + + conditionsWindow.Hold.HasteCost:setText(storage[conditionPanelName].hasteCost) + conditionsWindow.Hold.HasteCost.onTextChange = function(widget, text) + storage[conditionPanelName].hasteCost = tonumber(text) + end + + conditionsWindow.Hold.UtamoCost:setText(storage[conditionPanelName].utamoCost) + conditionsWindow.Hold.UtamoCost.onTextChange = function(widget, text) + storage[conditionPanelName].utamoCost = tonumber(text) + end + + conditionsWindow.Hold.UtanaCost:setText(storage[conditionPanelName].utanaCost) + conditionsWindow.Hold.UtanaCost.onTextChange = function(widget, text) + storage[conditionPanelName].utanaCost = tonumber(text) + end + + conditionsWindow.Hold.UturaCost:setText(storage[conditionPanelName].uturaCost) + conditionsWindow.Hold.UturaCost.onTextChange = function(widget, text) + storage[conditionPanelName].uturaCost = tonumber(text) + end + + -- combo box + conditionsWindow.Hold.UturaType:setOption(storage[conditionPanelName].uturaType) + conditionsWindow.Hold.UturaType.onOptionChange = function(widget) + storage[conditionPanelName].uturaType = widget:getCurrentOption().text + end + + -- checkboxes + conditionsWindow.Cure.CurePoison:setChecked(storage[conditionPanelName].curePoison) + conditionsWindow.Cure.CurePoison.onClick = function(widget) + storage[conditionPanelName].curePoison = not storage[conditionPanelName].curePoison + widget:setChecked(storage[conditionPanelName].curePoison) + end + + conditionsWindow.Cure.CureCurse:setChecked(storage[conditionPanelName].cureCurse) + conditionsWindow.Cure.CureCurse.onClick = function(widget) + storage[conditionPanelName].cureCurse = not storage[conditionPanelName].cureCurse + widget:setChecked(storage[conditionPanelName].cureCurse) + end + + conditionsWindow.Cure.CureBleed:setChecked(storage[conditionPanelName].cureBleed) + conditionsWindow.Cure.CureBleed.onClick = function(widget) + storage[conditionPanelName].cureBleed = not storage[conditionPanelName].cureBleed + widget:setChecked(storage[conditionPanelName].cureBleed) + end + + conditionsWindow.Cure.CureBurn:setChecked(storage[conditionPanelName].cureBurn) + conditionsWindow.Cure.CureBurn.onClick = function(widget) + storage[conditionPanelName].cureBurn = not storage[conditionPanelName].cureBurn + widget:setChecked(storage[conditionPanelName].cureBurn) + end + + conditionsWindow.Cure.CureElectrify:setChecked(storage[conditionPanelName].cureElectrify) + conditionsWindow.Cure.CureElectrify.onClick = function(widget) + storage[conditionPanelName].cureElectrify = not storage[conditionPanelName].cureElectrify + widget:setChecked(storage[conditionPanelName].cureElectrify) + end + + conditionsWindow.Cure.CureParalyse:setChecked(storage[conditionPanelName].cureParalyse) + conditionsWindow.Cure.CureParalyse.onClick = function(widget) + storage[conditionPanelName].cureParalyse = not storage[conditionPanelName].cureParalyse + widget:setChecked(storage[conditionPanelName].cureParalyse) + end + + conditionsWindow.Hold.HoldHaste:setChecked(storage[conditionPanelName].holdHaste) + conditionsWindow.Hold.HoldHaste.onClick = function(widget) + storage[conditionPanelName].holdHaste = not storage[conditionPanelName].holdHaste + widget:setChecked(storage[conditionPanelName].holdHaste) + end + + conditionsWindow.Hold.HoldUtamo:setChecked(storage[conditionPanelName].holdUtamo) + conditionsWindow.Hold.HoldUtamo.onClick = function(widget) + storage[conditionPanelName].holdUtamo = not storage[conditionPanelName].holdUtamo + widget:setChecked(storage[conditionPanelName].holdUtamo) + end + + conditionsWindow.Hold.HoldUtana:setChecked(storage[conditionPanelName].holdUtana) + conditionsWindow.Hold.HoldUtana.onClick = function(widget) + storage[conditionPanelName].holdUtana = not storage[conditionPanelName].holdUtana + widget:setChecked(storage[conditionPanelName].holdUtana) + end + + conditionsWindow.Hold.HoldUtura:setChecked(storage[conditionPanelName].holdUtura) + conditionsWindow.Hold.HoldUtura.onClick = function(widget) + storage[conditionPanelName].holdUtura = not storage[conditionPanelName].holdUtura + widget:setChecked(storage[conditionPanelName].holdUtura) + end + + conditionsWindow.Hold.IgnoreInPz:setChecked(storage[conditionPanelName].ignoreInPz) + conditionsWindow.Hold.IgnoreInPz.onClick = function(widget) + storage[conditionPanelName].ignoreInPz = not storage[conditionPanelName].ignoreInPz + widget:setChecked(storage[conditionPanelName].ignoreInPz) + end + + conditionsWindow.Hold.StopHaste:setChecked(storage[conditionPanelName].stopHaste) + conditionsWindow.Hold.StopHaste.onClick = function(widget) + storage[conditionPanelName].stopHaste = not storage[conditionPanelName].stopHaste + widget:setChecked(storage[conditionPanelName].stopHaste) + end + + -- buttons + conditionsWindow.closeButton.onClick = function(widget) + conditionsWindow:hide() + end + end + + local utanaCast = nil + macro(500, function() + if not storage[conditionPanelName].enabled or modules.game_cooldown.isGroupCooldownIconActive(2) then return end + if storage[conditionPanelName].curePoison and mana() >= storage[conditionPanelName].poisonCost and isPoisioned() then say("exana pox") + elseif storage[conditionPanelName].cureCurse and mana() >= storage[conditionPanelName].curseCost and isCursed() then say("exana mort") + elseif storage[conditionPanelName].cureBleed and mana() >= storage[conditionPanelName].bleedCost and isBleeding() then say("exana kor") + elseif storage[conditionPanelName].cureBurn and mana() >= storage[conditionPanelName].burnCost and isBurning() then say("exana flam") + elseif storage[conditionPanelName].cureElectrify and mana() >= storage[conditionPanelName].electrifyCost and isEnergized() then say("exana vis") + elseif (not storage[conditionPanelName].ignoreInPz or not isInPz()) and storage[conditionPanelName].holdUtura and mana() >= storage[conditionPanelName].uturaCost and not hasPartyBuff() then say(storage[conditionPanelName].uturaType) + elseif (not storage[conditionPanelName].ignoreInPz or not isInPz()) and storage[conditionPanelName].holdUtana and mana() >= storage[conditionPanelName].utanaCost and (not utanaCast or (now - utanaCast > 120000)) then say("utana vid") utanaCast = now + end + end) + + macro(50, function() + if not storage[conditionPanelName].enabled then return end + if (not storage[conditionPanelName].ignoreInPz or not isInPz()) and storage[conditionPanelName].holdUtamo and mana() >= storage[conditionPanelName].utamoCost and not hasManaShield() then say("utamo vita") + elseif (not storage[conditionPanelName].ignoreInPz or not isInPz()) and storage[conditionPanelName].holdHaste and mana() >= storage[conditionPanelName].hasteCost and not hasHaste() and not getSpellCoolDown(storage[conditionPanelName].hasteSpell) and (not target() or not storage[conditionPanelName].stopHaste or TargetBot.isCaveBotActionAllowed()) then say(storage[conditionPanelName].hasteSpell) + elseif storage[conditionPanelName].cureParalyse and mana() >= storage[conditionPanelName].paralyseCost and isParalyzed() and not getSpellCoolDown(storage[conditionPanelName].paralyseSpell) then say(storage[conditionPanelName].paralyseSpell) + end + end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/__vlib.lua b/modules/game_bot/default_configs/vBot/__vlib.lua new file mode 100644 index 0000000..6977f91 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/__vlib.lua @@ -0,0 +1,889 @@ +-- Author: Vithrax +-- contains mostly basic function shortcuts and code shorteners + + +-- burst damage calculation, for function burstDamageValue() +local dmgTable = {} +local lastDmgMessage = now +onTextMessage(function(mode, text) + if not text:lower():find("you lose") or not text:lower():find("due to") then return end + local dmg = string.match(text, "%d+") + if #dmgTable > 0 then + for k, v in ipairs(dmgTable) do + if now - v.t > 3000 then + table.remove(dmgTable, k) + end + end + end + lastDmgMessage = now + table.insert(dmgTable, {d = dmg, t = now}) + schedule(3050, function() + if now - lastDmgMessage > 3000 then + dmgTable = {} end + end) +end) + +function whiteInfoMessage(text) + return modules.game_textmessage.displayGameMessage(text) +end + +function burstDamageValue() + local d = 0 + local time = 0 + if #dmgTable > 1 then + for i, v in ipairs(dmgTable) do + if i == 1 then + time = v.t + end + d = d + v.d + end + end + return math.ceil(d/((now-time)/1000)) +end + + +function scheduleNpcSay(text, delay) + if not text or not delay then return false end + + return schedule(delay, function() NPC.say(text) end) +end + +function getFirstNumberInText(text) + local n = 0 + if string.match(text, "%d+") then + n = tonumber(string.match(text, "%d+")) + end + return n +end + +function isOnTile(id, p1, p2, p3) + if not id then return end + local tile + if type(p1) == "table" then + tile = g_map.getTile(p1) + elseif type(p1) ~= "number" then + tile = p1 + else + local p = getPos(p1, p2, p3) + tile = g_map.getTile(p) + end + if not tile then return end + + local item = false + if #tile:getItems() ~= 0 then + for i,v in ipairs(tile:getItems()) do + if v:getId() == id then + item = true + end + end + else + return false + end + + return item +end + +function getPos(x,y,z) + if not x or not y or not z then return nil end + local pos = pos() + pos.x = x + pos.y = y + pos.z = z + + return pos +end + +function openPurse() + return g_game.use(g_game.getLocalPlayer():getInventoryItem(InventorySlotPurse)) +end + +function containerIsFull(c) + if not c then return false end + + if c:getCapacity() > #c:getItems() then + return false + else + return true + end + +end + +function isBuffed() + local var = false + for i=1,4 do + local premium = (player:getSkillLevel(i) - player:getSkillBaseLevel(i)) + local base = player:getSkillBaseLevel(i) + if hasPartyBuff() and (premium/100)*305 > base then + var = true + end + end + return var +end + +function reindexTable(t) + if not t or type(t) ~= "table" then return end + + local i = 0 + for _, e in pairs(t) do + i = i + 1 + e.index = i + end +end + +function killsToRs() + return math.min(g_game.getUnjustifiedPoints().killsDayRemaining, g_game.getUnjustifiedPoints().killsWeekRemaining, g_game.getUnjustifiedPoints().killsMonthRemaining) +end + +-- [[ experimental healing cooldown calculation ]] -- +storage.isUsingPotion = false +onTalk(function(name, level, mode, text, channelId, pos) + if name ~= player:getName() then return end + if mode ~= 34 then return end + + if text == "Aaaah..." then + storage.isUsingPotion = true + schedule(950, function() + storage.isUsingPotion = false + end) + end +end) + +-- [[ eof ]] -- + +-- [[ canCast and cast functions ]] -- +SpellCastTable = {} +onTalk(function(name, level, mode, text, channelId, pos) + if name ~= player:getName() then return end + + if SpellCastTable[text] then + SpellCastTable[text].t = now + end +end) + +function cast(text, delay) + if type(text) ~= "string" then return end + if not delay or delay < 100 then + return say(text) -- if not added delay or delay is really low then just treat it like casual say + end + if not SpellCastTable[text] or SpellCastTable[text].d ~= delay then + SpellCastTable[text] = {t=now-delay,d=delay} + return say(text) + end + local lastCast = SpellCastTable[text].t + local spellDelay = SpellCastTable[text].d + if now - lastCast > spellDelay then + return say(text) + end + return +end +local Spells = modules.gamelib.SpellInfo['Default'] +function canCast(spell, ignoreRL, ignoreCd) + if type(spell) ~= "string" then return end + spell = spell:lower() + if not getSpellData(spell) then + if SpellCastTable[spell] then + if now - SpellCastTable[spell].t > SpellCastTable[spell].d then + return true + else + return false + end + else + return true + end + end + if (ignoreCd or not getSpellCoolDown(spell)) and (ignoreRL or level() >= getSpellData(spell).level and mana() >= getSpellData(spell).mana) then + return true + else + return false + end +end + +function getSpellData(spell) + if not spell then return false end + spell = spell:lower() + local t = nil + for k,v in pairs(Spells) do + if v.words == spell then + t = k + break + end + end + if t then + return Spells[t] + else + return false + end +end + +function getSpellCoolDown(text) + if not text then return false end + text = text:lower() + if not getSpellData(text) then return false end + for i,v in pairs(Spells) do + if v.words == text then + return modules.game_cooldown.isCooldownIconActive(v.id) + end + end +end + +storage.isUsing = false + +onUse(function(pos, itemId, stackPos, subType) + if pos.x < 65000 then + storage.isUsing = true + end + schedule(1500, function() if storage.isUsing then storage.isUsing = false end end) +end) + +onUseWith(function(pos, itemId, target, subType) + if itemId ~= 3180 then return end + if pos.x < 65000 then + storage.isUsing = true + end + schedule(1500, function() if storage.isUsing then storage.isUsing = false end end) +end) + +function string.starts(String,Start) + return string.sub(String,1,string.len(Start))==Start +end + +local cachedFriends = {} +local cachedNeutrals = {} +local cachedEnemies = {} +function isFriend(c) + local name = c + if type(c) ~= "string" then + if c == player then return true end + name = c:getName() + if name == name() then return true end + end + + if table.find(cachedFriends, c) then return true end + if table.find(cachedNeutrals, c) or table.find(cachedEnemies, c) then return false end + + if table.find(storage.playerList.friendList, name) then + table.insert(cachedFriends, c) + return true + elseif string.find(storage.serverMembers, name) then + table.insert(cachedFriends, c) + return true + elseif storage.playerList.groupMembers then + local p = c + if type(c) == "string" then + p = getCreatureByName(c, true) + end + if p:isLocalPlayer() then return true end + if p:isPlayer() then + if ((p:getShield() >= 3 and p:getShield() <= 10) or p:getEmblem() == 2) then + table.insert(cachedFriends, c) + table.insert(cachedFriends, p) + return true + else + table.insert(cachedNeutrals, c) + table.insert(cachedNeutrals, p) + return false + end + end + else + table.insert(cachedNeutrals, c) + table.insert(cachedNeutrals, p) + return false + end +end + +function isEnemy(name) + if not name then return false end + local p = getCreatureByName(name, true) + if p:isLocalPlayer() then return end + + if p:isPlayer() and table.find(storage.playerList.enemyList, name) or (storage.playerList.marks and not isFriend(name)) then + return true + else + return false + end +end + +function isAttSpell(expr) + if string.starts(expr, "exori") or string.starts(expr, "exevo") then + return true + else + return false + end +end + +function getActiveItemId(id) + if not id then + return false + end + + if id == 3049 then + return 3086 + elseif id == 3050 then + return 3087 + elseif id == 3051 then + return 3088 + elseif id == 3052 then + return 3089 + elseif id == 3053 then + return 3090 + elseif id == 3091 then + return 3094 + elseif id == 3092 then + return 3095 + elseif id == 3093 then + return 3096 + elseif id == 3097 then + return 3099 + elseif id == 3098 then + return 3100 + elseif id == 16114 then + return 16264 + elseif id == 23531 then + return 23532 + elseif id == 23533 then + return 23534 + elseif id == 23529 then + return 23530 + else + return id + end +end + +function getInactiveItemId(id) + if not id then + return false + end + + if id == 3086 then + return 3049 + elseif id == 3087 then + return 3050 + elseif id == 3088 then + return 3051 + elseif id == 3089 then + return 3052 + elseif id == 3090 then + return 3053 + elseif id == 3094 then + return 3091 + elseif id == 3095 then + return 3092 + elseif id == 3096 then + return 3093 + elseif id == 3099 then + return 3097 + elseif id == 3100 then + return 3098 + elseif id == 16264 then + return 16114 + elseif id == 23532 then + return 23531 + elseif id == 23534 then + return 23533 + elseif id == 23530 then + return 23529 + else + return id + end +end + +function getMonstersInRange(pos, range) + if not pos or not range then + return false + end + local monsters = 0 + for i, spec in pairs(getSpectators()) do + if spec:isMonster() and (g_game.getClientVersion() < 960 or spec:getType() < 3) and getDistanceBetween(pos, spec:getPosition()) < range then + monsters = monsters + 1 + end + end + return monsters +end + +function distanceFromPlayer(coords) + if not coords then + return false + end + return getDistanceBetween(pos(), coords) +end + +function getMonsters(range, multifloor) + if not range then + range = 10 + end + local mobs = 0; + for _, spec in pairs(getSpectators(multifloor)) do + mobs = (g_game.getClientVersion() < 960 or spec:getType() < 3) and spec:isMonster() and distanceFromPlayer(spec:getPosition()) <= range and mobs + 1 or mobs; + end + return mobs; +end + +function getPlayers(range, multifloor) + if not range then + range = 10 + end + local specs = 0; + for _, spec in pairs(getSpectators(multifloor)) do + specs = not spec:isLocalPlayer() and spec:isPlayer() and distanceFromPlayer(spec:getPosition()) <= range and not ((spec:getShield() >= 3 and spec:getShield() <= 10) or spec:getEmblem() == 1) and specs + 1 or specs; + end + return specs; +end + +function isBlackListedPlayerInRange(range) + if #storage.playerList.blackList == 0 then return end + if not range then range = 10 end + local safe = false + for _, spec in pairs(getSpectators()) do + if spec:isPlayer() and distanceFromPlayer(spec:getPosition()) < range then + if table.find(storage.playerList.blackList, spec:getName()) then + safe = true + end + end + end + + return safe +end + +function isSafe(range, multifloor, padding) + local onSame = 0 + local onAnother = 0 + if not multifloor and padding then + multifloor = false + padding = false + end + + for _, spec in pairs(getSpectators(multifloor)) do + if spec:isPlayer() and not spec:isLocalPlayer() and not isFriend(spec:getName()) then + if spec:getPosition().z == posz() and distanceFromPlayer(spec:getPosition()) <= range then + onSame = onSame + 1 + end + if multifloor and padding and spec:getPosition().z ~= posz() and distanceFromPlayer(spec:getPosition()) <= (range + padding) then + onAnother = onAnother + 1 + end + end + end + + if onSame + onAnother > 0 then + return false + else + return true + end +end + +function getAllPlayers(range, multifloor) + if not range then + range = 10 + end + local specs = 0; + for _, spec in pairs(getSpectators(multifloor)) do + specs = not spec:isLocalPlayer() and spec:isPlayer() and distanceFromPlayer(spec:getPosition()) <= range and specs + 1 or specs; + end + return specs; +end + +function getNpcs(range, multifloor) + if not range then + range = 10 + end + local npcs = 0; + for _, spec in pairs(getSpectators(multifloor)) do + npcs = spec:isNpc() and distanceFromPlayer(spec:getPosition()) <= range and npcs + 1 or npcs; + end + return npcs; +end + +function itemAmount(id) + local totalItemCount = 0 + for _, container in pairs(getContainers()) do + for _, item in ipairs(container:getItems()) do + totalItemCount = item:getId() == id and totalItemCount + item:getCount() or totalItemCount + end + end + if getHead() and getHead():getId() == id then + totalItemCount = totalItemCount + getHead():getCount() + end + if getNeck() and getNeck():getId() == id then + totalItemCount = totalItemCount + getNeck():getCount() + end + if getBack() and getBack():getId() == id then + totalItemCount = totalItemCount + getBack():getCount() + end + if getBody() and getBody():getId() == id then + totalItemCount = totalItemCount + getBody():getCount() + end + if getRight() and getRight():getId() == id then + totalItemCount = totalItemCount + getRight():getCount() + end + if getLeft() and getLeft():getId() == id then + totalItemCount = totalItemCount + getLeft():getCount() + end + if getLeg() and getLeg():getId() == id then + totalItemCount = totalItemCount + getLeg():getCount() + end + if getFeet() and getFeet():getId() == id then + totalItemCount = totalItemCount + getFeet():getCount() + end + if getFinger() and getFinger():getId() == id then + totalItemCount = totalItemCount + getFinger():getCount() + end + if getAmmo() and getAmmo():getId() == id then + totalItemCount = totalItemCount + getAmmo():getCount() + end + return totalItemCount +end + +function hasSupplies() + local items = { + {ID = storage.supplies.item1, minAmount = storage.supplies.item1Min}, + {ID = storage.supplies.item2, minAmount = storage.supplies.item2Min}, + {ID = storage.supplies.item3, minAmount = storage.supplies.item3Min}, + {ID = storage.supplies.item4, minAmount = storage.supplies.item4Min}, + {ID = storage.supplies.item5, minAmount = storage.supplies.item5Min}, + {ID = storage.supplies.item6, minAmount = storage.supplies.item6Min}, + {ID = storage.supplies.item7, minAmount = storage.supplies.item7Min} + } + -- false = no supplies + -- true = supplies available + + local hasSupplies = true + + for i, supply in pairs(items) do + if supply.min and supply.ID then + if supply.ID > 100 and itemAmount(supply.ID) < supply.min then + hasSupplies = false + end + end + end + + return hasSupplies +end + +function cordsToPos(x, y, z) + if not x or not y or not z then + return false + end + local tilePos = pos() + tilePos.x = x + tilePos.y = y + tilePos.z = z + return tilePos +end + +function reachGroundItem(id) + if not id then return nil end + local targetTile + for _, tile in ipairs(g_map.getTiles(posz())) do + if tile:getTopUseThing():getId() == id then + targetTile = tile:getPosition() + end + end + if targetTile then + CaveBot.walkTo(targetTile, 10, {ignoreNonPathable = true, precision=1}) + delay(500*getDistanceBetween(targetTile, pos())) + return true + else + return nil + end +end + +function useGroundItem(id) + if not id then + return nil + end + local targetTile = nil + for _, tile in ipairs(g_map.getTiles(posz())) do + if tile:getTopUseThing():getId() == id then + targetTile = tile:getPosition() + end + end + if targetTile then + g_game.use(g_map.getTile(targetTile):getTopUseThing()) + delay(500*getDistanceBetween(targetTile, pos())) + else + return nil + end +end + +function target() + if not g_game.isAttacking() then + return + else + return g_game.getAttackingCreature() + end +end + +function getTarget() + return target() +end + +function targetPos(dist) + if not g_game.isAttacking() then + return + end + if dist then + return distanceFromPlayer(target():getPosition()) + else + return target():getPosition() + end +end + +-- for gunzodus +function reopenPurse() + for i, c in pairs(getContainers()) do + if c:getName():lower() == "loot bag" or c:getName():lower() == "store inbox" then + g_game.close(c) + end + end + schedule(100, function() g_game.use(g_game.getLocalPlayer():getInventoryItem(InventorySlotPurse)) end) + schedule(1400, function() + for i, c in pairs(getContainers()) do + if c:getName():lower() == "store inbox" then + for _, i in pairs(c:getItems()) do + if i:getId() == 23721 then + g_game.open(i, c) + end + end + end + end + end) + return CaveBot.delay(1500) +end + +-- getSpectator patterns + +function getCreaturesInArea(param1, param2, param3) + -- param1 - pos/creature + -- param2 - pattern + -- param3 - type of return + -- 1 - everyone, 2 - monsters, 3 - players + local specs = 0 + local monsters = 0 + local players = 0 + for i, spec in pairs(getSpectators(param1, param2)) do + if spec ~= player then + specs = specs + 1 + if spec:isMonster() and (g_game.getClientVersion() < 960 or spec:getType() < 3) then + monsters = monsters + 1 + elseif spec:isPlayer() and not isFriend(spec:getName()) then + players = players +1 + end + end + end + + if param3 == 1 then + return specs + elseif param3 == 2 then + return monsters + else + return players + end +end + +function getBestTileByPatern(pattern, specType, maxDist, safe) + if not pattern or not specType then return end + if not maxDist then maxDist = 4 end + + + local bestTile = nil + local best = nil + -- best area tile to use + for _, tile in pairs(g_map.getTiles(posz())) do + if distanceFromPlayer(tile:getPosition()) <= maxDist then + local minimapColor = g_map.getMinimapColor(tile:getPosition()) + local stairs = (minimapColor >= 210 and minimapColor <= 213) + if tile:canShoot() and tile:isWalkable() and not stairs then + if getCreaturesInArea(tile:getPosition(), pattern, specType) > 0 then + if (not safe or getCreaturesInArea(tile:getPosition(), pattern, 3) == 0) then + local candidate = {pos = tile, count = getCreaturesInArea(tile:getPosition(), pattern, specType)} + if not best or best.count <= candidate.count then + best = candidate + end + end + end + end + end + end + + bestTile = best + + if bestTile then + return bestTile + else + return false + end +end + +function getContainerByName(name) + if type(name) ~= "string" then return nil end + + local d = nil + for i, c in pairs(getContainers()) do + if c:getName():lower() == name:lower() then + d = c + break + end + end + return d +end + +function getContainerByItem(id) + if type(name) ~= "number" then return nil end + + local d = nil + for i, c in pairs(getContainers()) do + if c:getContainerItem():getId() == id then + d = c + break + end + end + return d +end + +LargeUeArea = [[ + 0000001000000 + 0000011100000 + 0000111110000 + 0001111111000 + 0011111111100 + 0111111111110 + 1111111111111 + 0111111111110 + 0011111111100 + 0001111111000 + 0000111110000 + 0000011100000 + 0000001000000 +]] + +NormalUeAreaMs = [[ + 00000100000 + 00011111000 + 00111111100 + 01111111110 + 01111111110 + 11111111111 + 01111111110 + 01111111110 + 00111111100 + 00001110000 + 00000100000 +]] + +NormalUeAreaEd = [[ + 00000100000 + 00001110000 + 00011111000 + 00111111100 + 01111111110 + 11111111111 + 01111111110 + 00111111100 + 00011111000 + 00001110000 + 00000100000 +]] + +smallUeArea = [[ + 0011100 + 0111110 + 1111111 + 1111111 + 1111111 + 0111110 + 0011100 +]] + +largeRuneArea = [[ + 0011100 + 0111110 + 1111111 + 1111111 + 1111111 + 0111110 + 0011100 +]] + +adjacentArea = [[ + 111 + 101 + 111 +]] + +longBeamArea = [[ + 0000000N0000000 + 0000000N0000000 + 0000000N0000000 + 0000000N0000000 + 0000000N0000000 + 0000000N0000000 + 0000000N0000000 + WWWWWWW0EEEEEEE + 0000000S0000000 + 0000000S0000000 + 0000000S0000000 + 0000000S0000000 + 0000000S0000000 + 0000000S0000000 + 0000000S0000000 +]] + +shortBeamArea = [[ + 00000100000 + 00000100000 + 00000100000 + 00000100000 + 00000100000 + EEEEE0WWWWW + 00000S00000 + 00000S00000 + 00000S00000 + 00000S00000 + 00000S00000 +]] + +newWaveArea = [[ + 000NNNNN000 + 000NNNNN000 + 0000NNN0000 + WW00NNN00EE + WWWW0N0EEEE + WWWWW0EEEEE + WWWW0S0EEEE + WW00SSS00EE + 0000SSS0000 + 000SSSSS000 + 000SSSSS000 +]] + +bigWaveArea = [[ + 0000NNN0000 + 0000NNN0000 + 0000NNN0000 + 00000N00000 + WWW00N00EEE + WWWWW0EEEEE + WWW00S00EEE + 00000S00000 + 0000SSS0000 + 0000SSS0000 + 0000SSS0000 +]] + + +smallWaveArea = [[ + 00NNN00 + 00NNN00 + WW0N0EE + WWW0EEE + WW0S0EE + 00SSS00 + 00SSS00 +]] + +diamondArrowArea = [[ + 01110 + 11111 + 11111 + 11111 + 01110 +]] \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/_cavebot.lua b/modules/game_bot/default_configs/vBot/_cavebot.lua new file mode 100644 index 0000000..7e9040b --- /dev/null +++ b/modules/game_bot/default_configs/vBot/_cavebot.lua @@ -0,0 +1,55 @@ +-- Cavebot by otclient@otclient.ovh +-- visit http://bot.otclient.ovh/ + +local cavebotTab = "Cave" +local targetingTab = "Target" + +setDefaultTab(cavebotTab) +CaveBot = {} -- global namespace +CaveBot.Extensions = {} +importStyle("/cavebot/cavebot.otui") +importStyle("/cavebot/config.otui") +importStyle("/cavebot/editor.otui") +importStyle("/cavebot/supply.otui") +dofile("/cavebot/actions.lua") +dofile("/cavebot/config.lua") +dofile("/cavebot/editor.lua") +dofile("/cavebot/example_functions.lua") +dofile("/cavebot/recorder.lua") +dofile("/cavebot/walking.lua") +-- in this section you can add extensions, check extension_template.lua +--dofile("/cavebot/extension_template.lua") +dofile("/cavebot/sell_all.lua") +dofile("/cavebot/depositor.lua") +dofile("/cavebot/buy_supplies.lua") +dofile("/cavebot/d_withdraw.lua") +dofile("/cavebot/depositer.lua") +dofile("/cavebot/supply.lua") +dofile("/cavebot/supply_check.lua") +dofile("/cavebot/travel.lua") +dofile("/cavebot/doors.lua") +dofile("/cavebot/pos_check.lua") +dofile("/cavebot/withdraw.lua") +dofile("/cavebot/inbox_withdraw.lua") +dofile("/cavebot/lure.lua") +dofile("/cavebot/bank.lua") +dofile("/cavebot/depositer.lua") +dofile("/cavebot/supply.lua") +dofile("/cavebot/clear_tile.lua") +dofile("/cavebot/tasker.lua") +-- main cavebot file, must be last +dofile("/cavebot/cavebot.lua") + +setDefaultTab(targetingTab) +TargetBot = {} -- global namespace +importStyle("/targetbot/looting.otui") +importStyle("/targetbot/target.otui") +importStyle("/targetbot/creature_editor.otui") +dofile("/targetbot/creature.lua") +dofile("/targetbot/creature_attack.lua") +dofile("/targetbot/creature_editor.lua") +dofile("/targetbot/creature_priority.lua") +dofile("/targetbot/looting.lua") +dofile("/targetbot/walking.lua") +-- main targetbot file, must be last +dofile("/targetbot/target.lua") diff --git a/modules/game_bot/default_configs/vBot/alarms.otui b/modules/game_bot/default_configs/vBot/alarms.otui new file mode 100644 index 0000000..23682de --- /dev/null +++ b/modules/game_bot/default_configs/vBot/alarms.otui @@ -0,0 +1,105 @@ +AlarmsWindow < MainWindow + !text: tr('Alarms') + size: 270 200 + @onEscape: self:hide() + + BotSwitch + id: playerAttack + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + text-align: center + text: Player Attack + + BotSwitch + id: playerDetected + anchors.left: parent.left + anchors.right: parent.horizontalCenter + anchors.top: prev.bottom + margin-top: 4 + text-align: center + text: Player Detected + + CheckBox + id: playerDetectedLogout + anchors.top: playerDetected.top + anchors.left: parent.horizontalCenter + anchors.right: parent.right + margin-top: 3 + margin-left: 4 + text: Logout + + BotSwitch + id: creatureDetected + anchors.left: parent.left + anchors.right: parent.right + anchors.top: playerDetected.bottom + margin-top: 4 + text-align: center + text: Creature Detected + + BotSwitch + id: healthBelow + anchors.left: parent.left + anchors.top: prev.bottom + anchors.right: parent.horizontalCenter + text-align: center + margin-top: 4 + text: Health < 50% + + HorizontalScrollBar + id: healthValue + anchors.left: parent.horizontalCenter + anchors.right: parent.right + anchors.top: healthBelow.top + margin-left: 3 + margin-top: 2 + minimum: 1 + maximum: 100 + step: 1 + + BotSwitch + id: manaBelow + anchors.left: parent.left + anchors.top: healthBelow.bottom + anchors.right: parent.horizontalCenter + text-align: center + margin-top: 4 + text: Mana < 50% + + HorizontalScrollBar + id: manaValue + anchors.left: parent.horizontalCenter + anchors.right: parent.right + anchors.top: manaBelow.top + margin-left: 3 + margin-top: 2 + minimum: 1 + maximum: 100 + step: 1 + + BotSwitch + id: privateMessage + anchors.left: parent.left + anchors.top: manaBelow.bottom + anchors.right: parent.right + text-align: center + margin-top: 4 + text: Private Message + + HorizontalSeparator + id: separator + anchors.right: parent.right + anchors.left: parent.left + anchors.bottom: closeButton.top + margin-bottom: 8 + + Button + id: closeButton + !text: tr('Close') + font: cipsoftFont + anchors.right: parent.right + anchors.bottom: parent.bottom + size: 45 21 + margin-top: 15 + margin-right: 5 \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/antikick.lua b/modules/game_bot/default_configs/vBot/antikick.lua new file mode 100644 index 0000000..bf9c326 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/antikick.lua @@ -0,0 +1,7 @@ +local lastMove = now +onPlayerPositionChange(function(newPos, oldPos) + if now - lastMove > 13*60*1000 then + turn(math.random(0,3)) + lastMove = now + end +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/bless_buy.lua b/modules/game_bot/default_configs/vBot/bless_buy.lua new file mode 100644 index 0000000..de4e68c --- /dev/null +++ b/modules/game_bot/default_configs/vBot/bless_buy.lua @@ -0,0 +1,8 @@ +if player:getBlessings() == 0 then + say("!bless") + schedule(2000, function() + if player:getBlessings() == 0 then + warn("!! Blessings not bought !!") + end + end) +end diff --git a/modules/game_bot/default_configs/vBot/cavebot/actions.lua b/modules/game_bot/default_configs/vBot/cavebot/actions.lua new file mode 100644 index 0000000..edb0ef4 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/actions.lua @@ -0,0 +1,339 @@ +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) diff --git a/modules/game_bot/default_configs/vBot/cavebot/bank.lua b/modules/game_bot/default_configs/vBot/cavebot/bank.lua new file mode 100644 index 0000000..dda9e64 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/bank.lua @@ -0,0 +1,72 @@ +CaveBot.Extensions.Bank = {} + +CaveBot.Extensions.Bank.setup = function() + CaveBot.registerAction("bank", "#db5a5a", 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 \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/cavebot/buy_supplies.lua b/modules/game_bot/default_configs/vBot/cavebot/buy_supplies.lua new file mode 100644 index 0000000..7b85b7d --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/buy_supplies.lua @@ -0,0 +1,100 @@ +CaveBot.Extensions.BuySupplies = {} + +CaveBot.Extensions.BuySupplies.setup = function() + CaveBot.registerAction("BuySupplies", "#C300FF", function(value, retries) + local item1Count = itemAmount(storage[suppliesPanelName].item1) + local item2Count = itemAmount(storage[suppliesPanelName].item2) + local item3Count = itemAmount(storage[suppliesPanelName].item3) + local item4Count = itemAmount(storage[suppliesPanelName].item4) + local item5Count = itemAmount(storage[suppliesPanelName].item5) + local item6Count = itemAmount(storage[suppliesPanelName].item6) + local item7Count = itemAmount(storage[suppliesPanelName].item7) + local possibleItems = {} + + 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 > 50 then + print("CaveBot[BuySupplies]: Too many tries, can't buy") + return false + end + + delay(200) + + 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 + + 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}, + item6 = {ID = storage[suppliesPanelName].item6, maxAmount = storage[suppliesPanelName].item6Max, currentAmount = item6Count}, + item7 = {ID = storage[suppliesPanelName].item7, maxAmount = storage[suppliesPanelName].item7Max, currentAmount = item7Count} + } + + if not NPC.isTrading() then + NPC.say("hi") + schedule(500, function() NPC.say("trade") end) + return "retry" + end + + -- get items from npc + local npcItems = NPC.getBuyItems() + for i,v in pairs(npcItems) do + table.insert(possibleItems, v.id) + end + + for i, item in pairs(itemList) do + -- info(table.find(possibleItems, item["ID"])) + if item["ID"] and item["ID"] > 100 and table.find(possibleItems, item["ID"]) 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)) + print("CaveBot[BuySupplies]: bought " .. amountToBuy .. "x " .. item["ID"]) + return "retry" + end + else + if amountToBuy > 0 then + NPC.buy(item["ID"], math.min(100, amountToBuy)) + print("CaveBot[BuySupplies]: bought " .. amountToBuy .. "x " .. item["ID"]) + return "retry" + end + end + end + end + print("CaveBot[BuySupplies]: bought everything, proceeding") + return true + end) + + CaveBot.Editor.registerAction("buysupplies", "buy supplies", { + value="NPC name", + title="Buy Supplies", + description="NPC Name, delay(in ms, optional)", + }) +end \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/cavebot/cavebot.lua b/modules/game_bot/default_configs/vBot/cavebot/cavebot.lua new file mode 100644 index 0000000..55a455e --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/cavebot.lua @@ -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 + warn("Invalid return from cavebot action (" .. currentAction.action .. "), should be \"retry\", false or true, is: " .. tostring(result)) + end + else + warn("warn while executing cavebot action (" .. currentAction.action .. "):\n" .. result) + end + else + warn("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 + warn("warn 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 + warn("warn 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 diff --git a/modules/game_bot/default_configs/vBot/cavebot/cavebot.otui b/modules/game_bot/default_configs/vBot/cavebot/cavebot.otui new file mode 100644 index 0000000..b92ed05 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/cavebot.otui @@ -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 \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/cavebot/clear_tile.lua b/modules/game_bot/default_configs/vBot/cavebot/clear_tile.lua new file mode 100644 index 0000000..2eeb1b3 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/clear_tile.lua @@ -0,0 +1,81 @@ +CaveBot.Extensions.ClearTile = {} + +CaveBot.Extensions.ClearTile.setup = function() + CaveBot.registerAction("ClearTile", "#00FFFF", function(value, retries) + local pos = regexMatch(value, "\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)") + if not pos[1] then + warn("CaveBot[ClearTile]: invalid value. It should be position (x,y,z), is: " .. value) + return false + end + + if retries >= 20 then + print("CaveBot[ClearTile]: too many tries, can't open doors") + return false -- tried 20 times, can't clear it + end + + pos = {x=tonumber(pos[1][2]), y=tonumber(pos[1][3]), z=tonumber(pos[1][4])} + local tile = g_map.getTile(pos) + if not tile then + print("CaveBot[ClearTile]: can't find tile or tile is unreachable, skipping") + return false + end + + -- no items on tile and walkability means we are done + if tile:isWalkable() and tile:getTopUseThing():isNotMoveable() and not tile:hasCreature() then + print("CaveBot[ClearTile]: tile clear, proceeding") + return true + end + + local pPos = player:getPosition() + local tPos = tile:getPosition() + if math.max(math.abs(pPos.x - tPos.x), math.abs(pPos.y - tPos.y)) ~= 1 then + CaveBot.walkTo(tPos, 20, {ignoreNonPathable = true, precision=3}) + delay(300) + return "retry" + end + + if retries > 0 then + delay(1100) + end + + -- but if not then first check for creatures + if tile:hasCreature() then + local c = tile:getCreatures()[1] + if c:isMonster() then + attack(c) + + -- ok here we will find tile to push player, random + elseif c:isPlayer() then + local candidates = {} + for _, tile in ipairs(g_map.getTiles(posz())) do + if getDistanceBetween(c:getPosition(), tile:getPosition()) == 1 and tile:getPosition() ~= pPos then + table.insert(candidates, tile:getPosition()) + end + end + + if #candidates == 0 then + print("CaveBot[ClearTile]: can't find tile to push, cannot clear way, skipping") + return false + else + print("CaveBot[ClearTile]: pushing player... " .. c:getName() .. " out of the way") + g_game.move(c, candidates[math.random(1,#candidates)]) + return "retry" + end + end + end + if #tile:getItems() > 1 then + local item = tile:getTopUseThing() + print("CaveBot[ClearTile]: moving item... " .. item:getId().. " from tile") + g_game.move(item, pPos, item:getCount()) + return "retry" + end + end) + + CaveBot.Editor.registerAction("cleartile", "clear tile", { + value=function() return posx() .. "," .. posy() .. "," .. posz() end, + title="position of tile to clear", + description="tile position (x,y,z)", + multiline=false, + validation="^\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)$" +}) +end \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/cavebot/config.lua b/modules/game_bot/default_configs/vBot/cavebot/config.lua new file mode 100644 index 0000000..be6bdc2 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/config.lua @@ -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 warn("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 warn("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 warn("Invalid CaveBot.Config.get, id: " .. id) + end + return CaveBot.Config.values[id] +end \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/cavebot/config.otui b/modules/game_bot/default_configs/vBot/cavebot/config.otui new file mode 100644 index 0000000..21d479d --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/config.otui @@ -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 \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/cavebot/d_withdraw.lua b/modules/game_bot/default_configs/vBot/cavebot/d_withdraw.lua new file mode 100644 index 0000000..6910930 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/d_withdraw.lua @@ -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", "#002FFF", 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="insert index, destination container name and it's ID", + }) +end + +onPlayerPositionChange(function(newPos, oldPos) + storage.lootContainerOpen = false + storage.stopSearch = false +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/cavebot/depositer.lua b/modules/game_bot/default_configs/vBot/cavebot/depositer.lua new file mode 100644 index 0000000..d397c47 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/depositer.lua @@ -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 diff --git a/modules/game_bot/default_configs/vBot/cavebot/depositor.lua b/modules/game_bot/default_configs/vBot/cavebot/depositor.lua new file mode 100644 index 0000000..6ea0f71 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/depositor.lua @@ -0,0 +1,384 @@ +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 + +local ifPing = function() + if ping() and ping() > 150 then + return ping() + else + return 1 + end +end + +CaveBot.Extensions.Depositor.setup = function() + CaveBot.registerAction("depositor", "#002FFF", 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 + 2*ifPing()) -- 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+ifPing()) + 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+2*ifPing()) + 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+2*ifPing()) + 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+2*ifPing()) + 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+2*ifPing()) + storage.lootContainerOpen = true + break + end + else + if item:isContainer() and item:getId() == mainBp then + delay(500+2*ifPing()) + g_game.use(item, container) + storage.lootContainerOpen = true + break + end + end + end + break + end + end + end + + if #valueString == 3 then + delay(150+ifPing()) + 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+ifPing()) + 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) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/cavebot/doors.lua b/modules/game_bot/default_configs/vBot/cavebot/doors.lua new file mode 100644 index 0000000..d9a6502 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/doors.lua @@ -0,0 +1,57 @@ +CaveBot.Extensions.OpenDoors = {} + +CaveBot.Extensions.OpenDoors.setup = function() + CaveBot.registerAction("OpenDoors", "#00FFFF", function(value, retries) + local pos = string.split(value, ",") + local key = nil + if #pos == 4 then + key = tonumber(pos[4]) + end + if not pos[1] then + warn("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]), y=tonumber(pos[2]), z=tonumber(pos[3])} + + 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 + if not key then + use(doorTile:getTopUseThing()) + delay(200) + return "retry" + else + useWith(key, doorTile:getTopUseThing()) + delay(200) + return "retry" + end + 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) and key id (optional)", + multiline=false, +}) +end \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/cavebot/editor.lua b/modules/game_bot/default_configs/vBot/cavebot/editor.lua new file mode 100644 index 0000000..a75f1be --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/editor.lua @@ -0,0 +1,186 @@ +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 warn("CaveBot editor warn: 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("follow", { + value="NPC name", + title="Follow Creature", + description="insert creature name to follow", + multiline=false + }) + registerAction("npcsay", { + value="text", + title="NPC Say", + description="Enter text to NPC 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 diff --git a/modules/game_bot/default_configs/vBot/cavebot/editor.otui b/modules/game_bot/default_configs/vBot/cavebot/editor.otui new file mode 100644 index 0000000..d11288c --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/editor.otui @@ -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/") diff --git a/modules/game_bot/default_configs/vBot/cavebot/example_functions.lua b/modules/game_bot/default_configs/vBot/cavebot/example_functions.lua new file mode 100644 index 0000000..e2400a2 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/example_functions.lua @@ -0,0 +1,108 @@ +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 PZ and wait until dropped", [[ +if retries > 25 or not isPzLocked() then + return true +else + if isPoisioned() then + say("exana pox") + end + if isPzLocked() then + delay(8000) + end + return "retry" +end +]]) + +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" +]]) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/cavebot/extension_template.lua b/modules/game_bot/default_configs/vBot/cavebot/extension_template.lua new file mode 100644 index 0000000..d015f11 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/extension_template.lua @@ -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 diff --git a/modules/game_bot/default_configs/vBot/cavebot/follow.lua b/modules/game_bot/default_configs/vBot/cavebot/follow.lua new file mode 100644 index 0000000..c91d984 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/follow.lua @@ -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 \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/cavebot/inbox_withdraw.lua b/modules/game_bot/default_configs/vBot/cavebot/inbox_withdraw.lua new file mode 100644 index 0000000..0cd2d9f --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/inbox_withdraw.lua @@ -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", "#002FFF", function(value, retries) + local data = string.split(value, ",") + local withdrawId + local count + local itemCount = 0 + local depotAmount = 0 + if #data ~= 2 then + warn("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 \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/cavebot/lure.lua b/modules/game_bot/default_configs/vBot/cavebot/lure.lua new file mode 100644 index 0000000..f7aa9c5 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/lure.lua @@ -0,0 +1,28 @@ +CaveBot.Extensions.Lure = {} + +CaveBot.Extensions.Lure.setup = function() + CaveBot.registerAction("lure", "#FF0090", function(value, retries) + value = value:lower() + if value == "start" then + TargetBot.setOff() + elseif value == "stop" then + TargetBot.setOn() + elseif value == "toggle" then + if TargetBot.isOn() then + TargetBot.setOff() + else + TargetBot.setOn() + end + else + warn("incorrect lure value!") + end + return true + end) + + CaveBot.Editor.registerAction("lure", "lure", { + value="toggle", + title="Lure", + description="TargetBot: start, stop, toggle", + multiline=false, +}) +end \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/cavebot/pos_check.lua b/modules/game_bot/default_configs/vBot/cavebot/pos_check.lua new file mode 100644 index 0000000..acfaee3 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/pos_check.lua @@ -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 + warn("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 \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/cavebot/recorder.lua b/modules/game_bot/default_configs/vBot/cavebot/recorder.lua new file mode 100644 index 0000000..27206ba --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/recorder.lua @@ -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 \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/cavebot/sell_all.lua b/modules/game_bot/default_configs/vBot/cavebot/sell_all.lua new file mode 100644 index 0000000..1794f0e --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/sell_all.lua @@ -0,0 +1,68 @@ +CaveBot.Extensions.SellAll = {} + +storage.sellAllCap = 0 +CaveBot.Extensions.SellAll.setup = function() + CaveBot.registerAction("SellAll", "#C300FF", 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(val[1]) + 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 \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/cavebot/supply.lua b/modules/game_bot/default_configs/vBot/cavebot/supply.lua new file mode 100644 index 0000000..32fbc8b --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/supply.lua @@ -0,0 +1,31 @@ +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) + --widget.fields.max.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 diff --git a/modules/game_bot/default_configs/vBot/cavebot/supply.otui b/modules/game_bot/default_configs/vBot/cavebot/supply.otui new file mode 100644 index 0000000..83c76ac --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/supply.otui @@ -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 diff --git a/modules/game_bot/default_configs/vBot/cavebot/supply_check.lua b/modules/game_bot/default_configs/vBot/cavebot/supply_check.lua new file mode 100644 index 0000000..a504e64 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/supply_check.lua @@ -0,0 +1,70 @@ +CaveBot.Extensions.SupplyCheck = {} + +storage.supplyRetries = 0 +CaveBot.Extensions.SupplyCheck.setup = function() + CaveBot.registerAction("supplyCheck", "#db5a5a", 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 \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/cavebot/tasker.lua b/modules/game_bot/default_configs/vBot/cavebot/tasker.lua new file mode 100644 index 0000000..eaf5166 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/tasker.lua @@ -0,0 +1,183 @@ +CaveBot.Extensions.Tasker = {} + +local dataValidationFailed = function() + print("CaveBot[Tasker]: data validation failed! incorrect data, check cavebot/tasker for more info") + return false +end + +-- miniconfig +local talkDelay = 300 -- default delay between npc messages +if not storage.caveBotTasker then + storage.caveBotTasker = { + inProgress = false, + monster = "", + taskName = "", + count = 0, + max = 0 + } +end + +local resetTaskData = function() + storage.caveBotTasker.inProgress = false + storage.caveBotTasker.monster = "" + storage.caveBotTasker.monster2 = "" + storage.caveBotTasker.taskName = "" + storage.caveBotTasker.count = 0 + storage.caveBotTasker.max = 0 +end + +CaveBot.Extensions.Tasker.setup = function() + CaveBot.registerAction("Tasker", "#FF0090", function(value, retries) + local taskName = "" + local monster = "" + local monster2 = "" + local count = 0 + local label1 = "" + local label2 = "" + local task + + local data = string.split(value, ",") + if not data or #data < 1 then + dataValidationFailed() + end + local marker = tonumber(data[1]) + + if not marker then + dataValidationFailed() + resetTaskData() + elseif marker == 1 then + if getNpcs(3) == 0 then + print("CaveBot[Tasker]: no NPC found in range! skipping") + return false + end + if #data ~= 4 and #data ~= 5 then + dataValidationFailed() + resetTaskData() + else + taskName = data[2]:lower():trim() + count = tonumber(data[3]:trim()) + monster = data[4]:lower():trim() + if #data == 5 then + monster2 = data[5]:lower():trim() + end + end + elseif marker == 2 then + if #data ~= 3 then + dataValidationFailed() + else + label1 = data[2]:lower():trim() + label2 = data[3]:lower():trim() + end + elseif marker == 3 then + if getNpcs(3) == 0 then + print("CaveBot[Tasker]: no NPC found in range! skipping") + return false + end + if #data ~= 1 then + dataValidationFailed() + end + end + + -- let's cover markers now + if marker == 1 then -- starting task + NPC.say("hi") + scheduleNpcSay("task", talkDelay) + scheduleNpcSay(taskName, talkDelay*2) + scheduleNpcSay("yes", talkDelay*3) + delay(talkDelay*4) + + storage.caveBotTasker.monster = monster + if monster2 then storage.caveBotTasker.monster2 = monster2 end + storage.caveBotTasker.taskName = taskName + storage.caveBotTasker.inProgress = true + storage.caveBotTasker.max = count + storage.caveBotTasker.count = 0 + + print("CaveBot[Tasker]: taken task for: " .. monster .. " x" .. count) + return true + elseif marker == 2 then -- only checking + if not storage.caveBotTasker.inProgress then + CaveBot.gotoLabel(label2) + print("CaveBot[Tasker]: there is no task in progress so going to take one.") + return true + end + + local max = storage.caveBotTasker.max + local count = storage.caveBotTasker.count + + if count >= max then + CaveBot.gotoLabel(label2) + print("CaveBot[Tasker]: task completed: " .. storage.caveBotTasker.taskName) + return true + else + CaveBot.gotoLabel(label1) + print("CaveBot[Tasker]: task in progress, left: " .. max - count .. " " .. storage.caveBotTasker.taskName) + return true + end + + + elseif marker == 3 then -- reporting task + NPC.say("hi") + scheduleNpcSay("report", talkDelay) + scheduleNpcSay("task", talkDelay*2) + delay(talkDelay*3) + + resetTaskData() + print("CaveBot[Tasker]: task reported, done") + return true + end + + end) + + CaveBot.Editor.registerAction("tasker", "tasker", { + value=[[ There is 3 scenarios for this extension, as example we will use medusa: + + 1. start task, + parameters: + - scenario for extension: 1 + - task name in gryzzly adams: medusae + - monster count: 500 + - monster name to track: medusa + - optional, monster name 2: + 2. check status, + to be used on refill to decide whether to go back or spawn or go give task back + parameters: + - scenario for extension: 2 + - label if task in progress: skipTask + - label if task done: taskDone + 3. report task, + parameters: + - scenario for extension: 3 + + Strong suggestion, almost mandatory - USE POS CHECK to verify position! this module will only check if there is ANY npc in range! + + when begin remove all the text and leave just a single string of parameters + some examples: + + 2, skipReport, goReport + 3 + 1, drakens, 500, draken warmaster, draken spellweaver + 1, medusae, 500, medusa]], + title="Tasker", + multiline = true + }) +end + +local regex = "Loot of ([a-z])* ([a-z A-Z]*):" +local regex2 = "Loot of ([a-z A-Z]*):" +onTextMessage(function(mode, text) + -- if CaveBot.isOff() then return end + if not text:lower():find("loot of") then return end + if #regexMatch(text, regex) == 1 and #regexMatch(text, regex)[1] == 3 then + monster = regexMatch(text, regex)[1][3] + elseif #regexMatch(text, regex2) == 1 and #regexMatch(text, regex2)[1] == 2 then + monster = regexMatch(text, regex2)[1][2] + end + + local m1 = storage.caveBotTasker.monster + local m2 = storage.caveBotTasker.monster2 + + if monster == m1 or monster == m2 and storage.caveBotTasker.countaa then + storage.caveBotTasker.count = storage.caveBotTasker.count + 1 + end +end) diff --git a/modules/game_bot/default_configs/vBot/cavebot/travel.lua b/modules/game_bot/default_configs/vBot/cavebot/travel.lua new file mode 100644 index 0000000..7734dfc --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/travel.lua @@ -0,0 +1,52 @@ +CaveBot.Extensions.Travel = {} + +CaveBot.Extensions.Travel.setup = function() + CaveBot.registerAction("Travel", "#db5a5a", 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 \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/cavebot/walking.lua b/modules/game_bot/default_configs/vBot/cavebot/walking.lua new file mode 100644 index 0000000..c8a7133 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/walking.lua @@ -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 diff --git a/modules/game_bot/default_configs/vBot/cavebot/withdraw.lua b/modules/game_bot/default_configs/vBot/cavebot/withdraw.lua new file mode 100644 index 0000000..74f7fbc --- /dev/null +++ b/modules/game_bot/default_configs/vBot/cavebot/withdraw.lua @@ -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", "#002FFF", 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 \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/combo.otui b/modules/game_bot/default_configs/vBot/combo.otui new file mode 100644 index 0000000..b89013a --- /dev/null +++ b/modules/game_bot/default_configs/vBot/combo.otui @@ -0,0 +1,391 @@ +AttackComboBoxPopupMenu < ComboBoxPopupMenu +AttackComboBoxPopupMenuButton < ComboBoxPopupMenuButton +AttackComboBox < ComboBox + @onSetup: | + self:addOption("LEADER TARGET") + self:addOption("COMMAND TARGET") + +FollowComboBoxPopupMenu < ComboBoxPopupMenu +FollowComboBoxPopupMenuButton < ComboBoxPopupMenuButton +FollowComboBox < ComboBox + @onSetup: | + self:addOption("LEADER TARGET") + self:addOption("SERVER LEADER TARGET") + self:addOption("LEADER") + self:addOption("SERVER LEADER") + +ComboTrigger < Panel + id: trigger + image-source: /images/ui/panel_flat + image-border: 6 + padding: 3 + size: 450 72 + + Label + id: triggerLabel1 + anchors.left: parent.left + anchors.top: parent.top + text: On Say + margin-top: 8 + margin-left: 5 + color: #ffaa00 + + Label + id: leaderLabel + anchors.left: triggerLabel1.right + anchors.top: triggerLabel1.top + text: Leader: + margin-left: 35 + + TextEdit + id: onSayLeader + anchors.left: leaderLabel.right + anchors.top: leaderLabel.top + anchors.bottom: leaderLabel.bottom + margin-left: 5 + width: 120 + font: cipsoftFont + + Label + id: phrase + anchors.left: onSayLeader.right + anchors.top: onSayLeader.top + text: Phrase: + margin-left: 5 + + TextEdit + id: onSayPhrase + anchors.left: phrase.right + anchors.top: leaderLabel.top + anchors.bottom: leaderLabel.bottom + margin-left: 5 + width: 120 + font: cipsoftFont + + CheckBox + id: onSayToggle + anchors.left: onSayPhrase.right + anchors.top: onSayPhrase.top + margin-top: 1 + margin-left: 5 + + Label + id: triggerLabel2 + anchors.left: triggerLabel1.left + anchors.top: triggerLabel1.bottom + text: On Shoot + margin-top: 5 + color: #ffaa00 + + Label + id: leaderLabel1 + anchors.left: triggerLabel2.right + anchors.top: triggerLabel2.top + text: Leader: + margin-left: 24 + + TextEdit + id: onShootLeader + anchors.left: leaderLabel1.right + anchors.top: leaderLabel1.top + anchors.bottom: leaderLabel1.bottom + anchors.right: onSayPhrase.right + margin-left: 5 + width: 120 + font: cipsoftFont + + CheckBox + id: onShootToggle + anchors.left: onShootLeader.right + anchors.top: onShootLeader.top + margin-top: 1 + margin-left: 5 + + Label + id: triggerLabel3 + anchors.left: triggerLabel2.left + anchors.top: triggerLabel2.bottom + text: On Cast + margin-top: 5 + color: #ffaa00 + + Label + id: leaderLabel2 + anchors.left: triggerLabel3.right + anchors.top: triggerLabel3.top + text: Leader: + margin-left: 32 + + TextEdit + id: onCastLeader + anchors.left: leaderLabel2.right + anchors.top: leaderLabel2.top + anchors.bottom: leaderLabel2.bottom + anchors.right: onSayPhrase.right + margin-left: 5 + width: 120 + font: cipsoftFont + + CheckBox + id: onCastToggle + anchors.left: onCastLeader.right + anchors.top: onCastLeader.top + margin-top: 1 + margin-left: 5 + +ComboActions < Panel + id: actions + image-source: /images/ui/panel_flat + image-border: 6 + padding: 3 + size: 220 100 + + Label + id: label1 + anchors.left: parent.left + anchors.top: parent.top + text: Follow: + margin-top: 5 + margin-left: 3 + height: 15 + color: #ffaa00 + + FollowComboBox + id: followLeader + anchors.left: prev.right + anchors.top: prev.top + margin-left: 7 + height: 15 + width: 145 + font: cipsoftFont + + CheckBox + id: followLeaderToggle + anchors.left: followLeader.right + anchors.top: followLeader.top + margin-top: 2 + margin-left: 5 + + Label + id: label2 + anchors.left: label1.left + anchors.top: label1.bottom + margin-top: 5 + text: Attack: + color: #ffaa00 + + AttackComboBox + id: attackLeaderTarget + anchors.left: prev.right + anchors.top: prev.top + margin-left: 5 + height: 15 + width: 145 + font: cipsoftFont + + CheckBox + id: attackLeaderTargetToggle + anchors.left: attackLeaderTarget.right + anchors.top: attackLeaderTarget.top + margin-top: 2 + margin-left: 5 + + Label + id: label3 + anchors.left: label2.left + anchors.top: label2.bottom + margin-top: 5 + text: Spell: + color: #ffaa00 + + TextEdit + id: attackSpell + anchors.left: prev.right + anchors.top: prev.top + anchors.right: attackLeaderTarget.right + margin-left: 17 + height: 15 + width: 145 + font: cipsoftFont + + CheckBox + id: attackSpellToggle + anchors.left: attackSpell.right + anchors.top: attackSpell.top + margin-top: 2 + margin-left: 5 + + Label + id: label4 + anchors.left: label3.left + anchors.top: label3.bottom + margin-top: 15 + text: Attack Item: + color: #ffaa00 + + BotItem + id: attackItem + anchors.left: prev.right + anchors.verticalCenter: prev.verticalCenter + margin-left: 10 + + CheckBox + id: attackItemToggle + anchors.left: prev.right + anchors.verticalCenter: prev.verticalCenter + margin-left: 5 + + BotSwitch + id: commandsToggle + anchors.left: prev.right + anchors.top: attackItem.top + anchors.right: attackSpellToggle.right + anchors.bottom: attackItem.bottom + margin-left: 5 + text: Leader Commands + text-wrap: true + multiline: true + +BotServer < Panel + id: server + image-source: /images/ui/panel_flat + image-border: 6 + padding: 3 + size: 220 100 + + Label + id: labelX + anchors.left: parent.left + anchors.top: parent.top + text: Leader: + height: 15 + color: #ffaa00 + margin-left: 3 + margin-top: 5 + + TextEdit + id: botServerLeader + anchors.left: prev.right + anchors.top: prev.top + anchors.right: parent.right + margin-right: 3 + margin-left: 9 + height: 15 + font: cipsoftFont + + Button + id: partyButton + anchors.left: labelX.left + anchors.top: botServerLeader.bottom + margin-top: 5 + height: 30 + text: Join Party + text-wrap: true + multiline: true + + BotSwitch + id: botServerToggle + anchors.left: prev.right + anchors.top: botServerLeader.bottom + anchors.right: parent.right + height: 30 + margin-left: 3 + margin-right: 3 + margin-top: 5 + text: Server Enabled + + BotSwitch + id: targetServerLeaderToggle + anchors.left: partyButton.left + anchors.top: partyButton.bottom + anchors.right: partyButton.right + margin-top: 3 + height: 30 + text: Leader Targets + + BotSwitch + id: Triggers + anchors.left: prev.right + anchors.top: partyButton.bottom + anchors.right: parent.right + margin-top: 3 + height: 30 + margin-left: 3 + margin-right: 3 + text: Triggers + +ComboWindow < MainWindow + !text: tr('Combo Options') + size: 500 280 + @onEscape: self:hide() + + ComboTrigger + id: trigger + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + margin-top: 7 + + Label + id: title + anchors.top: parent.top + anchors.left: parent.left + margin-left: 10 + text: Combo Trigger + color: #ff7700 + + ComboActions + id: actions + anchors.top: trigger.bottom + anchors.left: trigger.left + margin-top: 15 + + Label + id: title + anchors.top: parent.top + anchors.left: parent.left + margin-left: 10 + margin-top: 85 + text: Combo Actions + color: #ff7700 + + BotServer + id: server + anchors.top: actions.top + anchors.left: actions.right + margin-left: 10 + + Label + id: title + anchors.top: parent.top + anchors.left: server.left + margin-left: 3 + margin-top: 85 + text: BotServer + color: #ff7700 + + HorizontalSeparator + id: separator + anchors.right: parent.right + anchors.left: parent.left + anchors.bottom: closeButton.top + margin-bottom: 8 + + Button + id: closeButton + !text: tr('Close') + font: cipsoftFont + anchors.right: parent.right + anchors.bottom: parent.bottom + size: 45 21 + margin-top: 15 + margin-right: 5 + + Button + id: toolsButton + !text: tr('Help') + font: cipsoftFont + anchors.right: closeButton.left + anchors.top: closeButton.top + margin-right: 10 + size: 45 21 + @onClick: g_platform.openUrl("http://bot.otclient.ovh/books/scripts/page/combobot") \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/eat_food.lua b/modules/game_bot/default_configs/vBot/eat_food.lua new file mode 100644 index 0000000..9f0fcb5 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/eat_food.lua @@ -0,0 +1,29 @@ +setDefaultTab("HP") + +UI.Separator() + +UI.Label("Eatable items:") +if type(storage.foodItems) ~= "table" then + storage.foodItems = {3582, 3577} +end + +local foodContainer = UI.Container(function(widget, items) + storage.foodItems = items +end, true) +foodContainer:setHeight(35) +foodContainer:setItems(storage.foodItems) + + +macro(500, "Eat Food", function() + if player:getRegenerationTime() > 400 or not storage.foodItems[1] then return end + -- search for food in containers + for _, container in pairs(g_game.getContainers()) do + for __, item in ipairs(container:getItems()) do + for i, foodItem in ipairs(storage.foodItems) do + if item:getId() == foodItem.id then + return g_game.use(item) + end + end + end + end +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/equip.lua b/modules/game_bot/default_configs/vBot/equip.lua new file mode 100644 index 0000000..b0c2f80 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/equip.lua @@ -0,0 +1,36 @@ +-- config +setDefaultTab("HP") +local scripts = 2 -- if you want more auto equip panels you can change 2 to higher value + +-- script by kondrah, don't edit below unless you know what you are doing +UI.Label("Auto equip") +if type(storage.autoEquip) ~= "table" then + storage.autoEquip = {} +end +for i=1,scripts do + if not storage.autoEquip[i] then + storage.autoEquip[i] = {on=false, title="Auto Equip", item1=i == 1 and 3052 or 0, item2=i == 1 and 3089 or 0, slot=i == 1 and 9 or 0} + end + UI.TwoItemsAndSlotPanel(storage.autoEquip[i], function(widget, newParams) + storage.autoEquip[i] = newParams + end) +end +macro(250, function() + local containers = g_game.getContainers() + for index, autoEquip in ipairs(storage.autoEquip) do + if autoEquip.on then + local slotItem = getSlot(autoEquip.slot) + if not slotItem or (slotItem:getId() ~= autoEquip.item1 and slotItem:getId() ~= autoEquip.item2) then + for _, container in pairs(containers) do + for __, item in ipairs(container:getItems()) do + if item:getId() == autoEquip.item1 or item:getId() == autoEquip.item2 then + g_game.move(item, {x=65535, y=autoEquip.slot, z=0}, item:getCount()) + delay(1000) -- don't call it too often + return + end + end + end + end + end + end +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/exeta.lua b/modules/game_bot/default_configs/vBot/exeta.lua new file mode 100644 index 0000000..249cb6a --- /dev/null +++ b/modules/game_bot/default_configs/vBot/exeta.lua @@ -0,0 +1,26 @@ +local voc = player:getVocation() +if voc == 1 or voc == 11 then + setDefaultTab("Cave") + UI.Separator() + local m = macro(100000, "Exeta when low hp", function() end) + local lastCast = now + onCreatureHealthPercentChange(function(creature, healthPercent) + if m.isOff() then return end + if healthPercent > 15 then return end + if CaveBot.isOff() or TargetBot.isOff() or not isBuffed() then return end + if modules.game_cooldown.isGroupCooldownIconActive(3) then return end + if creature:getPosition() and getDistanceBetween(pos(),creature:getPosition()) > 1 then return end + if canCast("exeta res") and now - lastCast > 6000 then + say("exeta res") + lastCast = now + end + end) + + macro(500, "ExetaIfPlayer", function() + if getMonsters(6) >= 1 and getPlayers(6) > 0 then + say("exeta res") + delay(6000) + end + end) + UI.Separator() +end \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/jewellery_equipper.lua b/modules/game_bot/default_configs/vBot/jewellery_equipper.lua new file mode 100644 index 0000000..c483965 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/jewellery_equipper.lua @@ -0,0 +1,365 @@ +setDefaultTab("HP") +function jewelleryEquip() + panelName = "jewelleryEquipper" + + local ui = setupUI([[ +Panel + height: 133 + margin-top: 2 + + BotItem + id: ringId + anchors.left: parent.left + anchors.top: parent.top + + SmallBotSwitch + id: ringSwitch + anchors.left: ringId.right + anchors.right: parent.right + anchors.top: parent.top + text-align: center + text: Equip Ring + margin-left: 3 + margin-right: 45 + + SmallBotSwitch + id: valueRing + anchors.left: ringSwitch.right + anchors.right: parent.right + anchors.top: parent.top + text-align: center + text: Mana + margin-left: 3 + margin-right: 0 + + BotLabel + id: ringTitle + anchors.left: ringId.right + anchors.right: parent.right + anchors.top: ringId.verticalCenter + text-align: center + + HorizontalScrollBar + id: ringScroll1 + anchors.left: parent.left + anchors.right: parent.horizontalCenter + anchors.top: ringId.bottom + margin-right: 2 + margin-top: 2 + minimum: 0 + maximum: 100 + step: 1 + + HorizontalScrollBar + id: ringScroll2 + anchors.left: parent.horizontalCenter + anchors.right: parent.right + anchors.top: prev.top + margin-left: 2 + minimum: 0 + maximum: 100 + step: 1 + + BotItem + id: ammyId + anchors.left: parent.left + anchors.top: ringScroll1.bottom + margin-top: 5 + + SmallBotSwitch + id: ammySwitch + anchors.left: ammyId.right + anchors.right: parent.right + anchors.top: ringScroll2.bottom + text-align: center + text: Equip Amulet + margin-top: 5 + margin-left: 3 + margin-right: 45 + + SmallBotSwitch + id: valueAmmy + anchors.left: ammySwitch.right + anchors.right: parent.right + anchors.top: ringScroll2.bottom + text-align: center + text: Mana + margin-top: 5 + margin-left: 3 + + BotLabel + id: ammyTitle + anchors.left: ammyId.right + anchors.right: parent.right + anchors.top: ammyId.verticalCenter + text-align: center + + HorizontalScrollBar + id: ammyScroll1 + anchors.left: parent.left + anchors.right: parent.horizontalCenter + anchors.top: ammyId.bottom + margin-right: 2 + margin-top: 2 + minimum: 0 + maximum: 100 + step: 1 + + HorizontalScrollBar + id: ammyScroll2 + anchors.left: parent.horizontalCenter + anchors.right: parent.right + anchors.top: prev.top + margin-left: 2 + minimum: 0 + maximum: 100 + step: 1 + + SmallBotSwitch + id: safe + anchors.top: ammyScroll2.bottom + anchors.right: parent.right + anchors.bottom: parent.bottom + text: Safe min + margin-top: 5 + width: 60 + + BotLabel + id: safeText + anchors.top: ammyScroll2.bottom + anchors.left: parent.left + anchors.right: prev.left + anchors.bottom: prev.verticalCenter + text-align: center + text: Stop if below 99% + + HorizontalScrollBar + id: safeMin + anchors.top: prev.bottom + anchors.left: parent.left + anchors.right: safe.left + anchors.bottom: safe.bottom + margin-left: 2 + margin-top: 2 + margin-right: 5 + minimum: 0 + maximum: 99 + step: 1 + + ]], parent) + ui:setId(panelName) + if not storage[panelName] or not storage[panelName].ringId or not storage[panelName].ammyId then + storage[panelName] = { + ringSwitch = true, + ammySwitch = true, + ringId = 3048, + ammyId = 3081, + ringMin = 30, + ringMax = 80, + ammyMin = 30, + ammyMax = 80, + valueAmmy = false, + valueRing = false, + ringValue = "HP", + ammyValue = "HP", + safe = true, + safeMin = 30 + } + end + if not storage[panelName].safeMin then + storage[panelName].safeMin = 30 + end + + + ui.ringSwitch:setOn(storage[panelName].ringEnabled) + ui.ringSwitch.onClick = function(widget) + storage[panelName].ringEnabled = not storage[panelName].ringEnabled + widget:setOn(storage[panelName].ringEnabled) + end + ui.safe:setOn(storage[panelName].safe) + ui.safe.onClick = function(widget) + storage[panelName].safe = not storage[panelName].safe + widget:setOn(storage[panelName].safe) + end + ui.ammySwitch:setOn(storage[panelName].ammyEnabled) + ui.ammySwitch.onClick = function(widget) + storage[panelName].ammyEnabled = not storage[panelName].ammyEnabled + widget:setOn(storage[panelName].ammyEnabled) + end + + local updateRingText = function() + ui.ringTitle:setText("" .. storage[panelName].ringMin .. "% <= " .. storage[panelName].ringValue .. " >= " .. storage[panelName].ringMax .. "%") + end + local updateAmmyText = function() + ui.ammyTitle:setText("" .. storage[panelName].ammyMin .. "% <= " .. storage[panelName].ammyValue .. " >= " .. storage[panelName].ammyMax .. "%") + end + local updateSafeText = function() + ui.safeText:setText("Stop if below " .. storage[panelName].safeMin .. "%") + end + updateSafeText() + + ui.valueRing:setOn(storage[panelName].valueRing) + ui.valueRing.onClick = function(widget) + storage[panelName].valueRing = not storage[panelName].valueRing + widget:setOn(storage[panelName].valueRing) + if storage[panelName].valueRing then + storage[panelName].ringValue = "MP" + else + storage[panelName].ringValue = "HP" + end + updateRingText() + end + ui.valueAmmy:setOn(storage[panelName].valueAmmy) + ui.valueAmmy.onClick = function(widget) + storage[panelName].valueAmmy = not storage[panelName].valueAmmy + widget:setOn(storage[panelName].valueAmmy) + if storage[panelName].valueAmmy then + storage[panelName].ammyValue = "MP" + else + storage[panelName].ammyValue = "HP" + end + updateAmmyText() + end + + ui.ringScroll1.onValueChange = function(scroll, value) + storage[panelName].ringMin = value + updateRingText() + end + ui.ringScroll2.onValueChange = function(scroll, value) + storage[panelName].ringMax = value + updateRingText() + end + ui.ammyScroll1.onValueChange = function(scroll, value) + storage[panelName].ammyMin = value + updateAmmyText() + end + ui.ammyScroll2.onValueChange = function(scroll, value) + storage[panelName].ammyMax = value + updateAmmyText() + end + ui.ringId.onItemChange = function(widget) + storage[panelName].ringId = widget:getItemId() + end + ui.ammyId.onItemChange = function(widget) + storage[panelName].ammyId = widget:getItemId() + end + ui.safeMin.onValueChange = function(scroll, value) + storage[panelName].safeMin = value + updateSafeText() + end + + ui.ringScroll1:setValue(storage[panelName].ringMin) + ui.ringScroll2:setValue(storage[panelName].ringMax) + ui.ammyScroll1:setValue(storage[panelName].ammyMin) + ui.ammyScroll2:setValue(storage[panelName].ammyMax) + ui.ringId:setItemId(storage[panelName].ringId) + ui.ammyId:setItemId(storage[panelName].ammyId) + ui.safeMin:setValue(storage[panelName].safeMin) + + local defaultRing + local defaultAmmy + + -- basic ring check + function defaultRingFind() + if storage[panelName].ringEnabled then + if getFinger() and (getFinger():getId() ~= storage[panelName].ringId and getFinger():getId() ~= getActiveItemId(storage[panelName].ringId)) then + defaultRing = getInactiveItemId(getFinger():getId()) + else + defaultRing = false + end + end + end + + -- basic amulet check + function defaultAmmyFind() + if storage[panelName].ammyEnabled then + if getNeck() and (getNeck():getId() ~= storage[panelName].ammyId and getNeck():getId() ~= getActiveItemId(storage[panelName].ammyId)) then + defaultAmmy = getInactiveItemId(getNeck():getId()) + else + defaultAmmy = false + end + end + end + + local lastAction = now + macro(20, function() + if now - lastAction < math.max(math.max(g_game.getPing()*2,150),300) then return end + if not storage[panelName].ringEnabled and not storage[panelName].ammyEnabled then return end + + -- [[ safe findout ]] -- + local safeAmmyVal + local safeRingVal + if not storage[panelName].valueAmmy then + safeAmmyVal = hppercent() + else + safeAmmyVal = manapercent() + end + if not storage[panelName].valueRing then + safeRingVal = hppercent() + else + safeRingVal = manapercent() + end + + -- [[ condition list ]] -- + local ringEnabled = storage[panelName].ringEnabled + local ringEquipped = getFinger() and (getFinger():getId() == storage[panelName].ringId or getFinger():getId() == getActiveItemId(storage[panelName].ringId)) + local shouldEquipRing = not storage[panelName].valueRing and hppercent() <= storage[panelName].ringMin or storage[panelName].valueRing and manapercent() <= storage[panelName].ringMin + local shouldUnequipRing = not storage[panelName].valueRing and hppercent() >= storage[panelName].ringMax or storage[panelName].valueRing and manapercent() >= storage[panelName].ringMax + local hasDefaultRing = defaultRing and findItem(defaultRing) + local ammyEnabled = storage[panelName].ammyEnabled + local ammyEquipped = getNeck() and (getNeck():getId() == storage[panelName].ammyId or getNeck():getId() == getActiveItemId(storage[panelName].ammyId)) + local shouldEquipAmmy = not storage[panelName].valueAmmy and hppercent() <= storage[panelName].ammyMin or storage[panelName].valueAmmy and manapercent() <= storage[panelName].ammyMin + local shouldUnequipAmmy = not storage[panelName].valueAmmy and hppercent() >= storage[panelName].ammyMax or storage[panelName].valueAmmy and manapercent() >= storage[panelName].ammyMax + local hasDefaultAmmy = defaultAmmy and findItem(defaultAmmy) + local ringIsSafe = not storage[panelName].safe or safeRingVal >= storage[panelName].safeMin + local ammyIsSafe = not storage[panelName].safe or safeAmmyVal >= storage[panelName].safeMin + + -- [[ ring ]] -- + if ringEnabled then + if not ringEquipped and shouldEquipRing and ringIsSafe then + defaultRingFind() + g_game.equipItemId(storage[panelName].ringId) + lastAction = now + return + elseif ringEquipped and (shouldUnequipRing or not ringIsSafe) then + if hasDefaultRing then + g_game.equipItemId(defaultRing) + lastAction = now + return + else + g_game.equipItemId(storage[panelName].ringId) + lastAction = now + return + end + end + end + -- [[ amulet ]] -- + if ammyEnabled then + if not ammyEquipped and shouldEquipAmmy and ammyIsSafe then + defaultAmmyFind() + g_game.equipItemId(storage[panelName].ammyId) + lastAction = now + return + elseif ammyEquipped and (shouldUnequipAmmy or not ammyIsSafe) then + if hasDefaultAmmy then + g_game.equipItemId(defaultAmmy) + lastAction = now + return + else + g_game.equipItemId(storage[panelName].ammyId) + lastAction = now + return + end + end + end + end) + -- end of function +end + +if g_game.getClientVersion() >= 1000 then + addSeparator() + UI.Label("-- [[ Equipper ]] --") + addSeparator() + jewelleryEquip() + addSeparator() +end \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/kill_counter.lua b/modules/game_bot/default_configs/vBot/kill_counter.lua new file mode 100644 index 0000000..e07bd82 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/kill_counter.lua @@ -0,0 +1,22 @@ +if type(storage.killedCreatures) ~= "table" then + storage.killedCreatures = {} +end +local regex = "Loot of ([a-z])* ([a-z A-Z]*):" +local regex2 = "Loot of ([a-z A-Z]*):" + +onTextMessage(function(mode, text) + if not text:lower():find("loot of") then return end + local monster + + if #regexMatch(text, regex) == 1 and #regexMatch(text, regex)[1] == 3 then + monster = regexMatch(text, regex)[1][3] + else + monster = regexMatch(text, regex2)[1][2] + end + + if storage.killedCreatures[monster] then + storage.killedCreatures[monster] = storage.killedCreatures[monster] + 1 + else + storage.killedCreatures[monster] = 1 + end +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/mwall_timer.lua b/modules/game_bot/default_configs/vBot/mwall_timer.lua new file mode 100644 index 0000000..6dc1ec4 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/mwall_timer.lua @@ -0,0 +1,41 @@ +-- Magic wall & Wild growth timer + +-- config +local magicWallId = 2129 +local magicWallTime = 20000 +local wildGrowthId = 2130 +local wildGrowthTime = 45000 + +-- script +local activeTimers = {} + +onAddThing(function(tile, thing) + if not thing:isItem() then + return + end + local timer = 0 + if thing:getId() == magicWallId then + timer = magicWallTime + elseif thing:getId() == wildGrowthId then + timer = wildGrowthTime + else + return + end + + local pos = tile:getPosition().x .. "," .. tile:getPosition().y .. "," .. tile:getPosition().z + if not activeTimers[pos] or activeTimers[pos] < now then + activeTimers[pos] = now + timer + end + tile:setTimer(activeTimers[pos] - now) +end) + +onRemoveThing(function(tile, thing) + if not thing:isItem() then + return + end + if (thing:getId() == magicWallId or thing:getId() == wildGrowthId) and tile:getGround() then + local pos = tile:getPosition().x .. "," .. tile:getPosition().y .. "," .. tile:getPosition().z + activeTimers[pos] = nil + tile:setTimer(0) + end +end) diff --git a/modules/game_bot/default_configs/vBot/oberon.lua b/modules/game_bot/default_configs/vBot/oberon.lua new file mode 100644 index 0000000..c28e9da --- /dev/null +++ b/modules/game_bot/default_configs/vBot/oberon.lua @@ -0,0 +1,23 @@ +onTalk(function(name, level, mode, text, channelId, pos) + if mode == 34 then + if string.find(text, "world will suffer for") then + say("Are you ever going to fight or do you prefer talking!") + elseif string.find(text, "feet when they see me") then + say("Even before they smell your breath?") + elseif string.find(text, "from this plane") then + say("Too bad you barely exist at all!") + elseif string.find(text, "ESDO LO") then + say("SEHWO ASIMO, TOLIDO ESD") + elseif string.find(text, "will soon rule this world") then + say("Excuse me but I still do not get the message!") + elseif string.find(text, "honourable and formidable") then + say("Then why are we fighting alone right now?") + elseif string.find(text, "appear like a worm") then + say("How appropriate, you look like something worms already got the better of!") + elseif string.find(text, "will be the end of mortal") then + say("Then let me show you the concept of mortality before it!") + elseif string.find(text, "virtues of chivalry") then + say("Dare strike up a Minnesang and you will receive your last accolade!") + end + end +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/player_list.otui b/modules/game_bot/default_configs/vBot/player_list.otui new file mode 100644 index 0000000..5f7b71d --- /dev/null +++ b/modules/game_bot/default_configs/vBot/player_list.otui @@ -0,0 +1,203 @@ +PlayerName < Label + background-color: alpha + text-offset: 2 0 + focusable: true + height: 16 + + $focus: + background-color: #00000055 + + Button + id: remove + !text: tr('x') + anchors.right: parent.right + margin-right: 15 + width: 15 + height: 15 + +PlayerListsWindow < MainWindow + !text: tr('Player Lists') + size: 570 350 + @onEscape: self:hide() + + Label + anchors.left: FriendList.left + anchors.top: parent.top + anchors.right: FriendList.right + text-align: center + text: Friends List + margin-right: 3 + + TextList + id: FriendList + anchors.top: parent.top + anchors.left: parent.left + margin-top: 15 + margin-bottom: 5 + margin-right: 3 + padding: 1 + width: 180 + height: 180 + vertical-scrollbar: FriendListScrollBar + + VerticalScrollBar + id: FriendListScrollBar + anchors.top: FriendList.top + anchors.bottom: FriendList.bottom + anchors.right: FriendList.right + step: 14 + pixels-scroll: true + + TextEdit + id: FriendName + anchors.right: FriendList.right + anchors.left: FriendList.left + anchors.top: FriendList.bottom + margin-right: 3 + margin-top: 5 + + Button + id: AddFriend + !text: tr('Add Friend') + anchors.right: FriendList.right + anchors.left: FriendList.left + anchors.top: prev.bottom + margin-right: 3 + margin-top: 3 + + Label + anchors.right: EnemyList.right + anchors.top: parent.top + anchors.left: EnemyList.left + text-align: center + text: Enemy List + margin-left: 3 + + TextList + id: EnemyList + anchors.top: parent.top + anchors.left: FriendList.right + margin-top: 15 + margin-bottom: 5 + margin-left: 3 + padding: 1 + width: 180 + height: 180 + vertical-scrollbar: EnemyListScrollBar + + VerticalScrollBar + id: EnemyListScrollBar + anchors.top: EnemyList.top + anchors.bottom: EnemyList.bottom + anchors.right: EnemyList.right + step: 14 + pixels-scroll: true + + TextEdit + id: EnemyName + anchors.left: EnemyList.left + anchors.right: EnemyList.right + anchors.top: EnemyList.bottom + margin-left: 3 + margin-top: 5 + + Button + id: AddEnemy + !text: tr('Add Enemy') + anchors.left: EnemyList.left + anchors.right: EnemyList.right + anchors.top: prev.bottom + margin-left: 3 + margin-top: 3 + + Label + anchors.right: BlackList.right + anchors.top: parent.top + anchors.left: BlackList.left + text-align: center + text: Anty RS List + margin-left: 3 + + TextList + id: BlackList + anchors.top: parent.top + anchors.left: EnemyList.right + margin-top: 15 + margin-bottom: 5 + margin-left: 3 + padding: 1 + width: 180 + height: 180 + vertical-scrollbar: BlackListScrollBar + + VerticalScrollBar + id: BlackListScrollBar + anchors.top: BlackList.top + anchors.bottom: BlackList.bottom + anchors.right: BlackList.right + step: 14 + pixels-scroll: true + + TextEdit + id: BlackName + anchors.left: BlackList.left + anchors.right: BlackList.right + anchors.top: BlackList.bottom + margin-left: 3 + margin-top: 5 + + Button + id: AddBlack + !text: tr('Add Anty-RS') + anchors.left: BlackList.left + anchors.right: BlackList.right + anchors.top: prev.bottom + margin-left: 3 + margin-top: 3 + + BotSwitch + id: Members + anchors.left: FriendList.left + anchors.right: FriendList.right + anchors.top: AddEnemy.bottom + margin-top: 10 + width: 114 + text-align: center + text: Group Members + + BotSwitch + id: Outfit + anchors.left: EnemyList.left + anchors.right: EnemyList.right + anchors.top: AddEnemy.bottom + margin-top: 10 + width: 114 + text-align: center + text: Color Outfits + + BotSwitch + id: Marks + anchors.left: BlackList.left + anchors.right: BlackList.right + anchors.top: AddEnemy.bottom + margin-top: 10 + width: 114 + text-align: center + text: Not Ally = Enemy + + HorizontalSeparator + id: separator + anchors.right: parent.right + anchors.left: parent.left + anchors.bottom: closeButton.top + margin-bottom: 8 + + Button + id: closeButton + !text: tr('Close') + font: cipsoftFont + anchors.right: parent.right + anchors.bottom: parent.bottom + size: 45 21 + margin-top: 15 + margin-right: 5 \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/playerlist.lua b/modules/game_bot/default_configs/vBot/playerlist.lua new file mode 100644 index 0000000..4bd2692 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/playerlist.lua @@ -0,0 +1,183 @@ + local listPanelName = "playerList" + local ui = setupUI([[ +Panel + height: 18 + + Button + id: editList + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + height: 18 + text: Player Lists + ]], parent) + ui:setId(listPanelName) + + if not storage[listPanelName] then + storage[listPanelName] = { + enemyList = {}, + friendList = {}, + blackList = {}, + groupMembers = true, + outfits = false, + marks = false + } + end + -- for backward compability + if not storage[listPanelName].blackList then + storage[listPanelName].blackList = {} + end + + rootWidget = g_ui.getRootWidget() + playerListWindow = g_ui.createWidget('PlayerListsWindow', rootWidget) + playerListWindow:hide() + + playerListWindow.Members:setOn(storage[listPanelName].groupMembers) + playerListWindow.Members.onClick = function(widget) + storage[listPanelName].groupMembers = not storage[listPanelName].groupMembers + widget:setOn(storage[listPanelName].groupMembers) + end + playerListWindow.Outfit:setOn(storage[listPanelName].outfits) + playerListWindow.Outfit.onClick = function(widget) + storage[listPanelName].outfits = not storage[listPanelName].outfits + widget:setOn(storage[listPanelName].outfits) + end + playerListWindow.Marks:setOn(storage[listPanelName].marks) + playerListWindow.Marks.onClick = function(widget) + storage[listPanelName].marks = not storage[listPanelName].marks + widget:setOn(storage[listPanelName].marks) + end + + if storage[listPanelName].enemyList and #storage[listPanelName].enemyList > 0 then + for _, name in ipairs(storage[listPanelName].enemyList) do + local label = g_ui.createWidget("PlayerName", playerListWindow.EnemyList) + label.remove.onClick = function(widget) + table.removevalue(storage[listPanelName].enemyList, label:getText()) + label:destroy() + end + label:setText(name) + end + end + + if storage[listPanelName].blackList and #storage[listPanelName].blackList > 0 then + for _, name in ipairs(storage[listPanelName].blackList) do + local label = g_ui.createWidget("PlayerName", playerListWindow.BlackList) + label.remove.onClick = function(widget) + table.removevalue(storage[listPanelName].blackList, label:getText()) + label:destroy() + end + label:setText(name) + end + end + + playerListWindow.AddEnemy.onClick = function(widget) + local friendName = playerListWindow.FriendName:getText() + if friendName:len() > 0 and not table.contains(storage[listPanelName].enemyList, friendName, true) then + table.insert(storage[listPanelName].enemyList, friendName) + local label = g_ui.createWidget("PlayerName", playerListWindow.EnemyList) + label.remove.onClick = function(widget) + table.removevalue(storage[listPanelName].enemyList, label:getText()) + label:destroy() + end + label:setText(friendName) + playerListWindow.FriendName:setText('') + refreshStatus() + end + end + + if storage[listPanelName].friendList and #storage[listPanelName].friendList > 0 then + for _, name in ipairs(storage[listPanelName].friendList) do + local label = g_ui.createWidget("PlayerName", playerListWindow.FriendList) + label.remove.onClick = function(widget) + table.removevalue(storage[listPanelName].friendList, label:getText()) + label:destroy() + end + label:setText(name) + end + end + + playerListWindow.AddFriend.onClick = function(widget) + local friendName = playerListWindow.FriendName:getText() + if friendName:len() > 0 and not table.contains(storage[listPanelName].friendList, friendName, true) then + table.insert(storage[listPanelName].friendList, friendName) + local label = g_ui.createWidget("PlayerName", playerListWindow.FriendList) + label.remove.onClick = function(widget) + table.removevalue(storage[listPanelName].friendList, label:getText()) + label:destroy() + end + label:setText(friendName) + playerListWindow.FriendName:setText('') + refreshStatus() + end + end + + playerListWindow.AddEnemy.onClick = function(widget) + local enemyName = playerListWindow.EnemyName:getText() + if enemyName:len() > 0 and not table.contains(storage[listPanelName].enemyList, enemyName, true) then + table.insert(storage[listPanelName].enemyList, enemyName) + local label = g_ui.createWidget("PlayerName", playerListWindow.EnemyList) + label.remove.onClick = function(widget) + table.removevalue(storage[listPanelName].enemyList, label:getText()) + label:destroy() + end + label:setText(enemyName) + playerListWindow.EnemyName:setText('') + refreshStatus() + end + end + + playerListWindow.AddBlack.onClick = function(widget) + local blackName = playerListWindow.BlackName:getText() + if blackName:len() > 0 and not table.contains(storage[listPanelName].blackList, blackName, true) then + table.insert(storage[listPanelName].blackList, blackName) + local label = g_ui.createWidget("PlayerName", playerListWindow.BlackList) + label.remove.onClick = function(widget) + table.removevalue(storage[listPanelName].blackList, label:getText()) + label:destroy() + end + label:setText(blackName) + playerListWindow.BlackName:setText('') + refreshStatus() + end + end + + ui.editList.onClick = function(widget) + playerListWindow:show() + playerListWindow:raise() + playerListWindow:focus() + end + playerListWindow.closeButton.onClick = function(widget) + playerListWindow:hide() + end + +function refreshStatus() + for _, spec in ipairs(getSpectators()) do + if spec:isPlayer() and not spec:isLocalPlayer() then + if storage[listPanelName].outfits then + specOutfit = spec:getOutfit() + if isEnemy(spec:getName()) then + spec:setMarked('#FF0000') + specOutfit.head = 112 + specOutfit.body = 112 + specOutfit.legs = 112 + specOutfit.feet = 112 + spec:setOutfit(specOutfit) + elseif isFriend(spec:getName()) then + spec:setMarked('#0000FF') + specOutfit.head = 94 + specOutfit.body = 94 + specOutfit.legs = 94 + specOutfit.feet = 94 + spec:setOutfit(specOutfit) + end + end + end + end +end +refreshStatus() + +onCreatureAppear(function(creature) + if creature:isPlayer() then + refreshStatus() + end +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/pushmax.otui b/modules/game_bot/default_configs/vBot/pushmax.otui new file mode 100644 index 0000000..7f38084 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/pushmax.otui @@ -0,0 +1,97 @@ +PushMaxWindow < MainWindow + !text: tr('Pushmax Settings') + size: 200 240 + @onEscape: self:hide() + + BotLabel + id: delayText + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + text-align: center + + HorizontalScrollBar + id: delay + anchors.left: delayText.left + anchors.right: delayText.right + anchors.top: delayText.bottom + margin-top: 5 + minimum: 800 + maximum: 2000 + step: 10 + + Label + id: label2 + anchors.top: delay.bottom + anchors.left: parent.horizontalCenter + anchors.right: parent.right + text-align: center + text: Custom WallID + margin-top: 5 + + Label + id: label3 + anchors.top: delay.bottom + anchors.right: parent.horizontalCenter + anchors.left: parent.left + text-align: center + text: VS AntiPush + margin-top: 5 + + BotItem + id: runeId + anchors.horizontalCenter: label3.horizontalCenter + anchors.top: label3.bottom + margin-top: 5 + + BotItem + id: mwallId + anchors.horizontalCenter: label2.horizontalCenter + anchors.top: label2.bottom + margin-top: 5 + + Label + id: label1 + anchors.top: mwallId.bottom + anchors.left: parent.left + anchors.right: parent.right + margin-top: 10 + text-align: center + text: Hotkey for PUSHMAX + + TextEdit + id: hotkey + anchors.left: parent.left + anchors.right: parent.right + anchors.top: label1.bottom + margin-top: 5 + text-align: center + + Label + id: label + anchors.top: hotkey.bottom + anchors.horizontalCenter: parent.horizontalCenter + margin-top: 10 + text-align: center + text: Made by Frosty + font: cipsoftFont + image-source: /images/ui/window + image-border: 1 + width: 100 + + HorizontalSeparator + id: separator + anchors.right: parent.right + anchors.left: parent.left + anchors.bottom: closeButton.top + margin-bottom: 8 + + Button + id: closeButton + !text: tr('Close') + font: cipsoftFont + anchors.right: parent.right + anchors.bottom: parent.bottom + size: 45 21 + margin-top: 15 + margin-right: 5 \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/siolist.otui b/modules/game_bot/default_configs/vBot/siolist.otui new file mode 100644 index 0000000..79439d8 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/siolist.otui @@ -0,0 +1,107 @@ +SioListWindow < MainWindow + !text: tr('Healer Options') + size: 200 310 + @onEscape: self:hide() + + BotSwitch + id: spell + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + text: Spell Healing + text-align: center + + BotTextEdit + id: spellName + anchors.left: parent.left + anchors.right: parent.right + anchors.top: spell.bottom + margin-top: 3 + + BotItem + id: itemId + anchors.top: prev.bottom + anchors.left: parent.left + margin-top: 10 + + BotSwitch + id: item + anchors.top: prev.top + anchors.left: prev.right + anchors.right: parent.right + anchors.bottom: prev.verticalCenter + text-align: center + text: Item Healing + margin-left: 2 + + BotLabel + id: distText + anchors.top: itemId.verticalCenter + anchors.left: itemId.right + anchors.right: parent.right + anchors.bottom: itemId.bottom + text-align: center + text: Max Distance + + HorizontalScrollBar + id: Distance + anchors.left: parent.left + anchors.top: itemId.bottom + anchors.right: parent.right + margin-top: 3 + minimum: 1 + maximum: 10 + step: 1 + + BotLabel + id: manaInfo + anchors.left: parent.left + anchors.right: parent.right + anchors.top: Distance.bottom + text-align: center + margin-top: 15 + + HorizontalScrollBar + id: minMana + anchors.left: spellName.left + anchors.right: spellName.right + anchors.top: manaInfo.bottom + margin-top: 2 + minimum: 1 + maximum: 100 + step: 1 + + BotLabel + id: friendHp + anchors.left: spellName.left + anchors.right: spellName.right + anchors.top: prev.bottom + text-align: center + margin-top: 10 + + HorizontalScrollBar + id: minFriendHp + anchors.left: spellName.left + anchors.right: spellName.right + anchors.top: friendHp.bottom + margin-top: 2 + minimum: 1 + maximum: 100 + step: 1 + + HorizontalSeparator + id: separator + anchors.right: parent.right + anchors.left: parent.left + anchors.bottom: closeButton.top + margin-bottom: 8 + + Button + id: closeButton + !text: tr('Close') + font: cipsoftFont + anchors.right: parent.right + anchors.bottom: parent.bottom + size: 45 21 + margin-top: 15 + margin-right: 5 \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/spy_level.lua b/modules/game_bot/default_configs/vBot/spy_level.lua new file mode 100644 index 0000000..f225d76 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/spy_level.lua @@ -0,0 +1,24 @@ +-- config + +local keyUp = "=" +local keyDown = "-" +setDefaultTab("Tools") + +-- script + +local lockedLevel = pos().z + +onPlayerPositionChange(function(newPos, oldPos) + lockedLevel = pos().z + modules.game_interface.getMapPanel():unlockVisibleFloor() +end) + +onKeyPress(function(keys) + if keys == keyDown then + lockedLevel = lockedLevel + 1 + modules.game_interface.getMapPanel():lockVisibleFloor(lockedLevel) + elseif keys == keyUp then + lockedLevel = lockedLevel - 1 + modules.game_interface.getMapPanel():lockVisibleFloor(lockedLevel) + end +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/supplies.lua b/modules/game_bot/default_configs/vBot/supplies.lua new file mode 100644 index 0000000..446fed0 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/supplies.lua @@ -0,0 +1,348 @@ +function SuppliesPanel(parent) + suppliesPanelName = "supplies" + if not parent then + parent = panel + end + +local ui = setupUI([[ +Panel + height: 21 + + Button + id: supplies + anchors.left: parent.left + anchors.right: parent.right + text-align: center + !text: tr('Supplies') + +]]) +ui:setId(suppliesPanelName) + +if not storage[suppliesPanelName] then +storage[suppliesPanelName] = { + item1 = 0, + item2 = 0, + item3 = 0, + item4 = 0, + item5 = 0, + item6 = 0, + item7 = 0, + capValue = 0, + capSwitch = false, + SoftBoots = false, + staminaSwitch = false, + staminaValue = 900, + imbues = false, + item1Min = 0, + item1Max = 0, + item2Min = 0, + item2Max = 0, + item3Min = 0, + item3Max = 0, + item4Min = 0, + item4Max = 0, + item5Min = 0, + item5Max = 0, + item6Min = 0, + item6Max = 0, + item7Max = 0, + sortSupplies = false, + potionBp = 0, + runeBp = 0, + ammoBp = 0 +} +end + +rootWidget = g_ui.getRootWidget() +if rootWidget then + SuppliesWindow = g_ui.createWidget('SuppliesWindow', rootWidget) + SuppliesWindow:hide() + + SuppliesWindow.capSwitch:setOn(storage[suppliesPanelName].capSwitch) + SuppliesWindow.capSwitch.onClick = function(widget) + storage[suppliesPanelName].capSwitch = not storage[suppliesPanelName].capSwitch + widget:setOn(storage[suppliesPanelName].capSwitch) + end + + SuppliesWindow.SoftBoots:setOn(storage[suppliesPanelName].SoftBoots) + SuppliesWindow.SoftBoots.onClick = function(widget) + storage[suppliesPanelName].SoftBoots = not storage[suppliesPanelName].SoftBoots + widget:setOn(storage[suppliesPanelName].SoftBoots) + end + + SuppliesWindow.imbues:setOn(storage[suppliesPanelName].imbues) + SuppliesWindow.imbues.onClick = function(widget) + storage[suppliesPanelName].imbues = not storage[suppliesPanelName].imbues + widget:setOn(storage[suppliesPanelName].imbues) + end + + SuppliesWindow.staminaSwitch:setOn(storage[suppliesPanelName].staminaSwitch) + SuppliesWindow.staminaSwitch.onClick = function(widget) + storage[suppliesPanelName].staminaSwitch = not storage[suppliesPanelName].staminaSwitch + widget:setOn(storage[suppliesPanelName].staminaSwitch) + end + + SuppliesWindow.SortSupplies:setOn(storage[suppliesPanelName].sortSupplies) + SuppliesWindow.SortSupplies.onClick = function(widget) + storage[suppliesPanelName].sortSupplies = not storage[suppliesPanelName].sortSupplies + widget:setOn(storage[suppliesPanelName].sortSupplies) + end + + -- bot items + + SuppliesWindow.item1:setItemId(storage[suppliesPanelName].item1) + SuppliesWindow.item1.onItemChange = function(widget) + storage[suppliesPanelName].item1 = widget:getItemId() + end + + SuppliesWindow.item2:setItemId(storage[suppliesPanelName].item2) + SuppliesWindow.item2.onItemChange = function(widget) + storage[suppliesPanelName].item2 = widget:getItemId() + end + + SuppliesWindow.item3:setItemId(storage[suppliesPanelName].item3) + SuppliesWindow.item3.onItemChange = function(widget) + storage[suppliesPanelName].item3 = widget:getItemId() + end + + SuppliesWindow.item4:setItemId(storage[suppliesPanelName].item4) + SuppliesWindow.item4.onItemChange = function(widget) + storage[suppliesPanelName].item4 = widget:getItemId() + end + + SuppliesWindow.item5:setItemId(storage[suppliesPanelName].item5) + SuppliesWindow.item5.onItemChange = function(widget) + storage[suppliesPanelName].item5 = widget:getItemId() + end + + SuppliesWindow.item6:setItemId(storage[suppliesPanelName].item6) + SuppliesWindow.item6.onItemChange = function(widget) + storage[suppliesPanelName].item6 = widget:getItemId() + end + + SuppliesWindow.PotionBp:setItemId(storage[suppliesPanelName].potionBp) + SuppliesWindow.PotionBp.onItemChange = function(widget) + storage[suppliesPanelName].potionBp = widget:getItemId() + end + + SuppliesWindow.RuneBp:setItemId(storage[suppliesPanelName].runeBp) + SuppliesWindow.RuneBp.onItemChange = function(widget) + storage[suppliesPanelName].runeBp = widget:getItemId() + end + + SuppliesWindow.AmmoBp:setItemId(storage[suppliesPanelName].ammoBp) + SuppliesWindow.AmmoBp.onItemChange = function(widget) + storage[suppliesPanelName].ammoBp = widget:getItemId() + end + + -- text windows + SuppliesWindow.capValue:setText(storage[suppliesPanelName].capValue) + SuppliesWindow.capValue.onTextChange = function(widget, text) + local value = tonumber(SuppliesWindow.capValue:getText()) + if not value then + SuppliesWindow.capValue:setText(0) + end + storage[suppliesPanelName].capValue = text +end + + SuppliesWindow.item1Min:setText(storage[suppliesPanelName].item1Min) + SuppliesWindow.item1Min.onTextChange = function(widget, text) + local value = tonumber(SuppliesWindow.item1Min:getText()) + if not value then + SuppliesWindow.item1Min:setText(0) + end + storage[suppliesPanelName].item1Min = text +end + + SuppliesWindow.item1Max:setText(storage[suppliesPanelName].item1Max) + SuppliesWindow.item1Max.onTextChange = function(widget, text) + local value = tonumber(SuppliesWindow.item1Max:getText()) + if not value then + SuppliesWindow.item1Max:setText(0) + end + storage[suppliesPanelName].item1Max = text +end + + SuppliesWindow.item2Min:setText(storage[suppliesPanelName].item2Min) + SuppliesWindow.item2Min.onTextChange = function(widget, text) + local value = tonumber(SuppliesWindow.item2Min:getText()) + if not value then + SuppliesWindow.item2Min:setText(0) + end + storage[suppliesPanelName].item2Min = text +end + + SuppliesWindow.item2Max:setText(storage[suppliesPanelName].item2Max) + SuppliesWindow.item2Max.onTextChange = function(widget, text) + local value = tonumber(SuppliesWindow.item2Max:getText()) + if not value then + SuppliesWindow.item2Max:setText(0) + end + storage[suppliesPanelName].item2Max = text +end + + SuppliesWindow.item3Min:setText(storage[suppliesPanelName].item3Min) + SuppliesWindow.item3Min.onTextChange = function(widget, text) + local value = tonumber(SuppliesWindow.item3Min:getText()) + if not value then + SuppliesWindow.item3Min:setText(0) + end + storage[suppliesPanelName].item3Min = text +end + + SuppliesWindow.item3Max:setText(storage[suppliesPanelName].item3Max) + SuppliesWindow.item3Max.onTextChange = function(widget, text) + local value = tonumber(SuppliesWindow.item3Max:getText()) + if not value then + SuppliesWindow.item3Max:setText(0) + end + storage[suppliesPanelName].item3Max = text +end + + SuppliesWindow.item4Min:setText(storage[suppliesPanelName].item4Min) + SuppliesWindow.item4Min.onTextChange = function(widget, text) + local value = tonumber(SuppliesWindow.item4Min:getText()) + if not value then + SuppliesWindow.item4Min:setText(0) + end + storage[suppliesPanelName].item4Min = text +end + +SuppliesWindow.staminaValue:setText(storage[suppliesPanelName].staminaValue) +SuppliesWindow.staminaValue.onTextChange = function(widget, text) + local value = tonumber(SuppliesWindow.staminaValue:getText()) + if not value then + SuppliesWindow.staminaValue:setText(0) + end + storage[suppliesPanelName].staminaValue = text +end + + SuppliesWindow.item4Max:setText(storage[suppliesPanelName].item4Max) + SuppliesWindow.item4Max.onTextChange = function(widget, text) + local value = tonumber(SuppliesWindow.item4Max:getText()) + if not value then + SuppliesWindow.item4Max:setText(0) + end + storage[suppliesPanelName].item4Max = text +end + + SuppliesWindow.item5Min:setText(storage[suppliesPanelName].item5Min) + SuppliesWindow.item5Min.onTextChange = function(widget, text) + local value = tonumber(SuppliesWindow.item5Min:getText()) + if not value then + SuppliesWindow.item5Min:setText(0) + end + storage[suppliesPanelName].item5Min = text +end + + SuppliesWindow.item5Max:setText(storage[suppliesPanelName].item5Max) + SuppliesWindow.item5Max.onTextChange = function(widget, text) + local value = tonumber(SuppliesWindow.item5Max:getText()) + if not value then + SuppliesWindow.item5Max:setText(0) + end + storage[suppliesPanelName].item5Max = text +end + +SuppliesWindow.item6Min:setText(storage[suppliesPanelName].item6Min) +SuppliesWindow.item6Min.onTextChange = function(widget, text) + local value = tonumber(SuppliesWindow.item6Min:getText()) + if not value then + SuppliesWindow.item6Min:setText(0) + end + storage[suppliesPanelName].item6Min = text +end + +SuppliesWindow.item6Max:setText(storage[suppliesPanelName].item6Max) +SuppliesWindow.item6Max.onTextChange = function(widget, text) + local value = tonumber(SuppliesWindow.item6Max:getText()) + if not value then + SuppliesWindow.item6Max:setText(0) + end + storage[suppliesPanelName].item6Max = text +end + +end + +ui.supplies.onClick = function(widget) + SuppliesWindow:show() + SuppliesWindow:raise() + SuppliesWindow:focus() +end + +SuppliesWindow.close.onClick = function(widget) + SuppliesWindow:hide() +end +end + +local potions = {268, 237, 238, 23373, 266, 236, 239, 7643, 7642, 23374} +local runes = {3725, 3203, 3161, 3147, 3178, 3177, 3153, 3148, 3197, 3149, 3164, 3166, 3200, 3192, 3188, 3190, 3189, 3191, 3198, 3182, 3158, 3152, 3174, 3180, 3165, 3173, 3172, 3176, 3195, 3179, 3175, 3155, 3202, 3160, 3156} +local ammo = {23375, 3446, 16142, 6528, 7363, 3450, 16141, 25785, 14252, 3447, 3449, 15793, 25757, 774, 16143, 763, 761, 7365, 3448, 762, 21470, 7364, 14251, 7368, 25759, 3287, 7366, 3298, 25758} + +macro(250, function() + if not storage[suppliesPanelName].sortSupplies then return end + local sortPotions = storage[suppliesPanelName].potionBp > 100 + local sortRunes = storage[suppliesPanelName].runeBp > 100 + local sortAmmo = storage[suppliesPanelName].ammoBp > 100 + local potionsContainer = nil + local runesContainer = nil + local ammoContainer = nil + + -- set the containers + if not potionsContainer or not runesContainer or not ammoContainer then + for i, container in pairs(getContainers()) do + if not containerIsFull(container) then + if sortPotions and container:getContainerItem():getId() == storage[suppliesPanelName].potionBp then + potionsContainer = container + elseif sortRunes and container:getContainerItem():getId() == storage[suppliesPanelName].runeBp then + runesContainer = container + elseif sortAmmo and container:getContainerItem():getId() == storage[suppliesPanelName].ammoBp then + ammoContainer = container + end + end + end + end + + + -- potions + if potionsContainer then + for i, container in pairs(getContainers()) do + if (container:getContainerItem():getId() ~= storage[suppliesPanelName].potionBp and (string.find(container:getName(), "backpack") or string.find(container:getName(), "bag") or string.find(container:getName(), "chess"))) then + for j, item in pairs(container:getItems()) do + if table.find(potions, item:getId()) then + return g_game.move(item, potionsContainer:getSlotPosition(potionsContainer:getItemsCount()), item:getCount()) + end + end + end + end + end + + -- runes + if runesContainer then + for i, container in pairs(getContainers()) do + if (container:getContainerItem():getId() ~= storage[suppliesPanelName].runeBp and (string.find(container:getName(), "backpack") or string.find(container:getName(), "bag") or string.find(container:getName(), "chess"))) then + for j, item in pairs(container:getItems()) do + if table.find(runes, item:getId()) then + return g_game.move(item, runesContainer:getSlotPosition(runesContainer:getItemsCount()), item:getCount()) + end + end + end + end + end + + -- ammo + if ammoContainer then + for i, container in pairs(getContainers()) do + if (container:getContainerItem():getId() ~= storage[suppliesPanelName].ammoBp and (string.find(container:getName(), "backpack") or string.find(container:getName(), "bag") or string.find(container:getName(), "chess"))) and not string.find(container:getName():lower(), "loot") then + for j, item in pairs(container:getItems()) do + if table.find(ammo, item:getId()) then + return g_game.move(item, ammoContainer:getSlotPosition(ammoContainer:getItemsCount()), item:getCount()) + end + end + end + end + end +end) + +UI.Separator() +SuppliesPanel(setDefaultTab("Cave")) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/supplies.otui b/modules/game_bot/default_configs/vBot/supplies.otui new file mode 100644 index 0000000..0544051 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/supplies.otui @@ -0,0 +1,366 @@ +SuppliesWindow < MainWindow + !text: tr('Supplies') + size: 430 310 + @onEscape: self:hide() + + VerticalSeparator + id: sep + anchors.top: parent.top + anchors.left: item1Max.right + anchors.bottom: parent.bottom + margin-top: 3 + margin-bottom: 3 + margin-left: 10 + + Label + anchors.left: sep.right + anchors.right: parent.right + anchors.top: parent.top + margin-left: 10 + margin-top: 3 + text-align: center + text: Additional Conditions: + + HorizontalSeparator + anchors.top: prev.bottom + anchors.left: prev.left + anchors.right: prev.right + margin-top: 3 + + BotSwitch + id: SoftBoots + anchors.top: prev.bottom + anchors.left: sep.right + anchors.right: parent.right + margin-top: 10 + margin-left: 10 + text: No Soft + + BotSwitch + id: capSwitch + height: 20 + anchors.left: SoftBoots.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 5 + margin-right: 50 + text-align: center + text: Cap Below: + + TextEdit + id: capValue + size: 40 20 + anchors.left: prev.right + anchors.right: parent.right + anchors.top: prev.top + margin-left: 5 + + BotSwitch + id: staminaSwitch + height: 20 + anchors.left: SoftBoots.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 5 + margin-right: 50 + text-align: center + text: Stamina: + + TextEdit + id: staminaValue + size: 40 20 + anchors.left: prev.right + anchors.right: parent.right + anchors.top: prev.top + margin-left: 5 + + BotSwitch + id: imbues + anchors.top: prev.bottom + anchors.left: sep.right + anchors.right: parent.right + margin-top: 5 + margin-left: 10 + text: No Imbues + + HorizontalSeparator + anchors.top: prev.bottom + anchors.left: prev.left + anchors.right: prev.right + margin-top: 5 + + BotSwitch + id: SortSupplies + anchors.top: prev.bottom + anchors.left: prev.left + anchors.right: prev.right + margin-top: 5 + text: Sort Supplies + + BotItem + id: PotionBp + anchors.top: prev.bottom + anchors.left: prev.left + margin-top: 3 + + Label + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 5 + text: Potions + + BotItem + id: RuneBp + anchors.top: PotionBp.bottom + anchors.left: PotionBp.left + margin-top: 3 + + Label + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 5 + text: Runes + + BotItem + id: AmmoBp + anchors.top: RuneBp.bottom + anchors.left: RuneBp.left + margin-top: 3 + + Label + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + margin-left: 5 + text: Ammo + + BotItem + id: item1 + anchors.left: parent.left + anchors.top: parent.top + margin-top: 3 + + Label + id: MinLabel + !text: tr('Min Amount') + anchors.left: prev.right + anchors.top: prev.top + margin-left: 18 + + Label + id: MaxLabel + !text: tr('Max Amount') + anchors.left: prev.right + anchors.top: prev.top + margin-left: 35 + + TextEdit + id: item1Min + size: 100 20 + anchors.left: parent.left + anchors.top: prev.top + margin-top: 15 + margin-left: 40 + text-align: center + + TextEdit + id: item1Max + size: 100 20 + anchors.left: prev.right + anchors.top: prev.top + margin-left: 5 + text-align: center + + BotItem + id: item2 + anchors.left: parent.left + anchors.top: prev.top + margin-top: 30 + + Label + id: MinLabel + !text: tr('Min Amount') + anchors.left: prev.right + anchors.top: prev.top + margin-left: 18 + + Label + id: MaxLabel + !text: tr('Max Amount') + anchors.left: prev.right + anchors.top: prev.top + margin-left: 35 + + TextEdit + id: item2Min + size: 100 20 + anchors.left: parent.left + anchors.top: prev.top + margin-top: 15 + margin-left: 40 + text-align: center + + TextEdit + id: item2Max + size: 100 20 + anchors.left: prev.right + anchors.top: prev.top + margin-left: 5 + text-align: center + + BotItem + id: item3 + anchors.left: parent.left + anchors.top: prev.top + margin-top: 30 + + Label + id: MinLabel + !text: tr('Min Amount') + anchors.left: prev.right + anchors.top: prev.top + margin-left: 18 + + Label + id: MaxLabel + !text: tr('Max Amount') + anchors.left: prev.right + anchors.top: prev.top + margin-left: 35 + + TextEdit + id: item3Min + size: 100 20 + anchors.left: parent.left + anchors.top: prev.top + margin-top: 15 + margin-left: 40 + text-align: center + + TextEdit + id: item3Max + size: 100 20 + anchors.left: prev.right + anchors.top: prev.top + margin-left: 5 + text-align: center + + BotItem + id: item4 + anchors.left: parent.left + anchors.top: prev.top + margin-top: 30 + + Label + id: MinLabel + !text: tr('Min Amount') + anchors.left: prev.right + anchors.top: prev.top + margin-left: 18 + + Label + id: MaxLabel + !text: tr('Max Amount') + anchors.left: prev.right + anchors.top: prev.top + margin-left: 35 + + TextEdit + id: item4Min + size: 100 20 + anchors.left: parent.left + anchors.top: prev.top + margin-top: 15 + margin-left: 40 + text-align: center + + TextEdit + id: item4Max + size: 100 20 + anchors.left: prev.right + anchors.top: prev.top + margin-left: 5 + text-align: center + + BotItem + id: item5 + anchors.left: parent.left + anchors.top: prev.top + margin-top: 30 + + Label + id: MinLabel + !text: tr('Min Amount') + anchors.left: prev.right + anchors.top: prev.top + margin-left: 18 + + Label + id: MaxLabel + !text: tr('Max Amount') + anchors.left: prev.right + anchors.top: prev.top + margin-left: 35 + + TextEdit + id: item5Min + size: 100 20 + anchors.left: parent.left + anchors.top: prev.top + margin-top: 15 + margin-left: 40 + text-align: center + + TextEdit + id: item5Max + size: 100 20 + anchors.left: prev.right + anchors.top: prev.top + margin-left: 5 + text-align: center + + BotItem + id: item6 + anchors.left: parent.left + anchors.top: prev.top + margin-top: 30 + + Label + id: MinLabel + !text: tr('Min Amount') + anchors.left: prev.right + anchors.top: prev.top + margin-left: 18 + + Label + id: MaxLabel + !text: tr('Max Amount') + anchors.left: prev.right + anchors.top: prev.top + margin-left: 35 + + TextEdit + id: item6Min + size: 100 20 + anchors.left: parent.left + anchors.top: prev.top + margin-top: 15 + margin-left: 40 + text-align: center + + TextEdit + id: item6Max + size: 100 20 + anchors.left: prev.right + anchors.top: prev.top + margin-left: 5 + text-align: center + + Button + id: close + !text: tr('Close') + font: cipsoftFont + anchors.right: parent.right + anchors.bottom: parent.bottom + size: 45 21 + margin-top: 15 + margin-right: 5 \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/targetbot/creature.lua b/modules/game_bot/default_configs/vBot/targetbot/creature.lua new file mode 100644 index 0000000..d4dd545 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/targetbot/creature.lua @@ -0,0 +1,99 @@ + +TargetBot.Creature = {} +TargetBot.Creature.configsCache = {} +TargetBot.Creature.cached = 0 + +TargetBot.Creature.resetConfigs = function() + TargetBot.targetList:destroyChildren() + TargetBot.Creature.resetConfigsCache() +end + +TargetBot.Creature.resetConfigsCache = function() + TargetBot.Creature.configsCache = {} + TargetBot.Creature.cached = 0 +end + +TargetBot.Creature.addConfig = function(config, focus) + if type(config) ~= 'table' or type(config.name) ~= 'string' then + return error("Invalid targetbot creature config (missing name)") + end + TargetBot.Creature.resetConfigsCache() + + if not config.regex then + config.regex = "" + for part in string.gmatch(config.name, "[^,]+") do + if config.regex:len() > 0 then + config.regex = config.regex .. "|" + end + config.regex = config.regex .. "^" .. part:trim():lower():gsub("%*", ".*"):gsub("%?", ".?") .. "$" + end + end + + local widget = UI.createWidget("TargetBotEntry", TargetBot.targetList) + widget:setText(config.name) + widget.value = config + + widget.onDoubleClick = function(entry) -- edit on double click + schedule(20, function() -- schedule to have correct focus + TargetBot.Creature.edit(entry.value, function(newConfig) + entry:setText(newConfig.name) + entry.value = newConfig + TargetBot.Creature.resetConfigsCache() + TargetBot.save() + end) + end) + end + + if focus then + widget:focus() + TargetBot.targetList:ensureChildVisible(widget) + end + return widget +end + +TargetBot.Creature.getConfigs = function(creature) + if not creature then return {} end + local name = creature:getName():trim():lower() + -- this function may be slow, so it will be using cache + if TargetBot.Creature.configsCache[name] then + return TargetBot.Creature.configsCache[name] + end + local configs = {} + for _, config in ipairs(TargetBot.targetList:getChildren()) do + if regexMatch(name, config.value.regex)[1] then + table.insert(configs, config.value) + end + end + if TargetBot.Creature.cached > 1000 then + TargetBot.Creature.resetConfigsCache() -- too big cache size, reset + end + TargetBot.Creature.configsCache[name] = configs -- add to cache + TargetBot.Creature.cached = TargetBot.Creature.cached + 1 + return configs +end + +TargetBot.Creature.calculateParams = function(creature, path) + local configs = TargetBot.Creature.getConfigs(creature) + local priority = 0 + local danger = 0 + local selectedConfig = nil + for _, config in ipairs(configs) do + local config_priority = TargetBot.Creature.calculatePriority(creature, config, path) + if config_priority > priority then + priority = config_priority + danger = TargetBot.Creature.calculateDanger(creature, config, path) + selectedConfig = config + end + end + return { + config = selectedConfig, + creature = creature, + danger = danger, + priority = priority + } +end + +TargetBot.Creature.calculateDanger = function(creature, config, path) + -- config is based on creature_editor + return config.danger +end diff --git a/modules/game_bot/default_configs/vBot/targetbot/creature_attack.lua b/modules/game_bot/default_configs/vBot/targetbot/creature_attack.lua new file mode 100644 index 0000000..68a2c5d --- /dev/null +++ b/modules/game_bot/default_configs/vBot/targetbot/creature_attack.lua @@ -0,0 +1,182 @@ +TargetBot.Creature.attack = function(params, targets, isLooting) -- params {config, creature, danger, priority} + if player:isWalking() then + lastWalk = now + end + + local config = params.config + local creature = params.creature + + if g_game.getAttackingCreature() ~= creature then + g_game.attack(creature) + end + + if not isLooting then -- walk only when not looting + TargetBot.Creature.walk(creature, config, targets) + end + + -- attacks + local mana = player:getMana() + if config.useGroupAttack and config.groupAttackSpell:len() > 1 and mana > config.minManaGroup then + local creatures = g_map.getSpectatorsInRange(player:getPosition(), false, config.groupAttackRadius, config.groupAttackRadius) + local playersAround = false + local monsters = 0 + for _, creature in ipairs(creatures) do + if not creature:isLocalPlayer() and creature:isPlayer() and (not config.groupAttackIgnoreParty or creature:getShield() <= 2) then + playersAround = true + elseif creature:isMonster() then + monsters = monsters + 1 + end + end + if monsters >= config.groupAttackTargets and (not playersAround or config.groupAttackIgnorePlayers) then + if TargetBot.sayAttackSpell(config.groupAttackSpell, config.groupAttackDelay) then + return + end + end + end + + if config.useGroupAttackRune and config.groupAttackRune > 100 then + local creatures = g_map.getSpectatorsInRange(creature:getPosition(), false, config.groupRuneAttackRadius, config.groupRuneAttackRadius) + local playersAround = false + local monsters = 0 + for _, creature in ipairs(creatures) do + if not creature:isLocalPlayer() and creature:isPlayer() and (not config.groupAttackIgnoreParty or creature:getShield() <= 2) then + playersAround = true + elseif creature:isMonster() then + monsters = monsters + 1 + end + end + if monsters >= config.groupRuneAttackTargets and (not playersAround or config.groupAttackIgnorePlayers) then + if TargetBot.useAttackItem(config.groupAttackRune, 0, creature, config.groupRuneAttackDelay) then + return + end + end + end + if config.useSpellAttack and config.attackSpell:len() > 1 and mana > config.minMana then + if TargetBot.sayAttackSpell(config.attackSpell, config.attackSpellDelay) then + return + end + end + if config.useRuneAttack and config.attackRune > 100 then + if TargetBot.useAttackItem(config.attackRune, 0, creature, config.attackRuneDelay) then + return + end + end +end + +if not storage.targetBotTargets then + storage.targetBotTargets = 0 +end +TargetBot.Creature.walk = function(creature, config, targets) + local cpos = creature:getPosition() + local pos = player:getPosition() + + local isTrapped = true + local pos = player:getPosition() + local dirs = {{-1,1}, {0,1}, {1,1}, {-1, 0}, {1, 0}, {-1, -1}, {0, -1}, {1, -1}} + for i=1,#dirs do + local tile = g_map.getTile({x=pos.x-dirs[i][1],y=pos.y-dirs[i][2],z=pos.z}) + if tile and tile:isWalkable(false) then + isTrapped = false + end + end + + -- data for external dynamic lure + if config.lureMin and config.lureMax then + if config.lureMin >= targets then + storage.TargetBotLure = true + elseif targets >= config.lureMax then + storage.TargetBotLure = false + end + end + storage.targetBotTargets = targets + storage.targetBotDynamicLureDelayValue = config.lureDelay + + if not storage.targetBotLureMax then + storage.targetBotLureMax = 0 + end + if config.lureMax then + storage.targetBotLureMax = config.lureMax + end + + -- luring + if TargetBot.canLure() and (config.lure or config.lureCavebot or config.dynamicLure) and not (config.chase and creature:getHealthPercent() < 5) and not isTrapped then + local monsters = 0 + if storage.TargetBotLure then + return TargetBot.allowCaveBot(150) + else + if targets < config.lureCount then + if config.lureCavebot then + return TargetBot.allowCaveBot(150) + else + local path = findPath(pos, cpos, 5, {ignoreNonPathable=true, precision=2}) + if path then + return TargetBot.walkTo(cpos, 10, {marginMin=5, marginMax=6, ignoreNonPathable=true}) + end + end + end + end + end + + local currentDistance = findPath(pos, cpos, 10, {ignoreCreatures=true, ignoreNonPathable=true, ignoreCost=true}) + if config.chase and (creature:getHealthPercent() < 30 or not config.keepDistance) then + if #currentDistance > 1 then + return TargetBot.walkTo(cpos, 10, {ignoreNonPathable=true, precision=1}) + end + elseif config.keepDistance then + if #currentDistance ~= config.keepDistanceRange and #currentDistance ~= config.keepDistanceRange + 1 then + return TargetBot.walkTo(cpos, 10, {ignoreNonPathable=true, marginMin=config.keepDistanceRange, marginMax=config.keepDistanceRange + 1}) + end + end + + if config.avoidAttacks then + local diffx = cpos.x - pos.x + local diffy = cpos.y - pos.y + local candidates = {} + if math.abs(diffx) == 1 and diffy == 0 then + candidates = {{x=pos.x, y=pos.y-1, z=pos.z}, {x=pos.x, y=pos.y+1, z=pos.z}} + elseif diffx == 0 and math.abs(diffy) == 1 then + candidates = {{x=pos.x-1, y=pos.y, z=pos.z}, {x=pos.x+1, y=pos.y, z=pos.z}} + end + for _, candidate in ipairs(candidates) do + local tile = g_map.getTile(candidate) + if tile and tile:isWalkable() then + return TargetBot.walkTo(candidate, 2, {ignoreNonPathable=true}) + end + end + elseif config.faceMonster then + local diffx = cpos.x - pos.x + local diffy = cpos.y - pos.y + local candidates = {} + if diffx == 1 and diffy == 1 then + candidates = {{x=pos.x+1, y=pos.y, z=pos.z}, {x=pos.x, y=pos.y-1, z=pos.z}} + elseif diffx == -1 and diffy == 1 then + candidates = {{x=pos.x-1, y=pos.y, z=pos.z}, {x=pos.x, y=pos.y-1, z=pos.z}} + elseif diffx == -1 and diffy == -1 then + candidates = {{x=pos.x, y=pos.y-1, z=pos.z}, {x=pos.x-1, y=pos.y, z=pos.z}} + elseif diffx == 1 and diffy == -1 then + candidates = {{x=pos.x, y=pos.y-1, z=pos.z}, {x=pos.x+1, y=pos.y, z=pos.z}} + else + local dir = player:getDirection() + if diffx == 1 and dir ~= 1 then turn(1) + elseif diffx == -1 and dir ~= 3 then turn(3) + elseif diffy == 1 and dir ~= 2 then turn(2) + elseif diffy == -1 and dir ~= 0 then turn(0) + end + end + for _, candidate in ipairs(candidates) do + local tile = g_map.getTile(candidate) + if tile and tile:isWalkable() then + return TargetBot.walkTo(candidate, 2, {ignoreNonPathable=true}) + end + end + end +end + +onPlayerPositionChange(function(newPos, oldPos) + if CaveBot.isOff() then return end + if TargetBot.isOff() then return end + if not storage.targetBotLureMax then return end + if storage.targetBotTargets < storage.targetBotLureMax/2 or not target() then return end + + CaveBot.delay(storage.targetBotDynamicLureDelayValue or 0) +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/targetbot/creature_editor.lua b/modules/game_bot/default_configs/vBot/targetbot/creature_editor.lua new file mode 100644 index 0000000..b743f3e --- /dev/null +++ b/modules/game_bot/default_configs/vBot/targetbot/creature_editor.lua @@ -0,0 +1,97 @@ +TargetBot.Creature.edit = function(config, callback) -- callback = function(newConfig) + config = config or {} + + local editor = UI.createWindow('TargetBotCreatureEditorWindow') + local values = {} -- (key, function returning value of key) + + editor.name:setText(config.name or "") + table.insert(values, {"name", function() return editor.name:getText() end}) + + local addScrollBar = function(id, title, min, max, defaultValue) + local widget = UI.createWidget('TargetBotCreatureEditorScrollBar', editor.content.left) + widget.scroll.onValueChange = function(scroll, value) + widget.text:setText(title .. ": " .. value) + end + widget.scroll:setRange(min, max) + if max-min > 1000 then + widget.scroll:setStep(100) + elseif max-min > 100 then + widget.scroll:setStep(10) + end + widget.scroll:setValue(config[id] or defaultValue) + widget.scroll.onValueChange(widget.scroll, widget.scroll:getValue()) + table.insert(values, {id, function() return widget.scroll:getValue() end}) + end + + local addTextEdit = function(id, title, defaultValue) + local widget = UI.createWidget('TargetBotCreatureEditorTextEdit', editor.content.right) + widget.text:setText(title) + widget.textEdit:setText(config[id] or defaultValue or "") + table.insert(values, {id, function() return widget.textEdit:getText() end}) + end + + local addCheckBox = function(id, title, defaultValue) + local widget = UI.createWidget('TargetBotCreatureEditorCheckBox', editor.content.right) + widget.onClick = function() + widget:setOn(not widget:isOn()) + end + widget:setText(title) + if config[id] == nil then + widget:setOn(defaultValue) + else + widget:setOn(config[id]) + end + table.insert(values, {id, function() return widget:isOn() end}) + end + + local addItem = function(id, title, defaultItem) + local widget = UI.createWidget('TargetBotCreatureEditorItem', editor.content.right) + widget.text:setText(title) + widget.item:setItemId(config[id] or defaultItem) + table.insert(values, {id, function() return widget.item:getItemId() end}) + end + + editor.cancel.onClick = function() + editor:destroy() + end + editor.onEscape = editor.cancel.onClick + + editor.ok.onClick = function() + local newConfig = {} + for _, value in ipairs(values) do + newConfig[value[1]] = value[2]() + end + if newConfig.name:len() < 1 then return end + + newConfig.regex = "" + for part in string.gmatch(newConfig.name, "[^,]+") do + if newConfig.regex:len() > 0 then + newConfig.regex = newConfig.regex .. "|" + end + newConfig.regex = newConfig.regex .. "^" .. part:trim():lower():gsub("%*", ".*"):gsub("%?", ".?") .. "$" + end + + editor:destroy() + callback(newConfig) + end + + -- values + addScrollBar("priority", "Priority", 0, 10, 1) + addScrollBar("danger", "Danger", 0, 10, 1) + addScrollBar("maxDistance", "Max distance", 1, 10, 10) + addScrollBar("keepDistanceRange", "Keep distance", 1, 5, 1) + addScrollBar("lureCount", "Classic Lure", 0, 5, 1) + addScrollBar("lureMin", "Dynamic lure min", 0, 9, 1) + addScrollBar("lureMax", "Dynamic lure max", 1, 9, 3) + addScrollBar("lureDelay", "Dynamic lure delay", 100, 1000, 250) + + addCheckBox("chase", "Chase", true) + addCheckBox("keepDistance", "Keep Distance", false) + addCheckBox("dontLoot", "Don't loot", false) + addCheckBox("lure", "Lure", false) + addCheckBox("lureCavebot", "Lure using cavebot", false) + addCheckBox("faceMonster", "Face monsters", false) + addCheckBox("avoidAttacks", "Avoid wave attacks", false) + addCheckBox("dynamicLure", "Dynamic lure", false) + addCheckBox("dynamicLureDelay", "Dynamic lure delay", false) +end diff --git a/modules/game_bot/default_configs/vBot/targetbot/creature_editor.otui b/modules/game_bot/default_configs/vBot/targetbot/creature_editor.otui new file mode 100644 index 0000000..82ae3ec --- /dev/null +++ b/modules/game_bot/default_configs/vBot/targetbot/creature_editor.otui @@ -0,0 +1,164 @@ +TargetBotCreatureEditorScrollBar < Panel + height: 28 + margin-top: 3 + + Label + id: text + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + text-align: center + + HorizontalScrollBar + id: scroll + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + minimum: 0 + maximum: 10 + step: 1 + +TargetBotCreatureEditorTextEdit < Panel + height: 40 + margin-top: 7 + + Label + id: text + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + text-align: center + + TextEdit + id: textEdit + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 5 + minimum: 0 + maximum: 10 + step: 1 + +TargetBotCreatureEditorItem < Panel + height: 34 + margin-top: 7 + margin-left: 25 + margin-right: 25 + + Label + id: text + anchors.left: parent.left + anchors.verticalCenter: next.verticalCenter + + BotItem + id: item + anchors.top: parent.top + anchors.right: parent.right + + +TargetBotCreatureEditorCheckBox < BotSwitch + height: 20 + margin-top: 7 + +TargetBotCreatureEditorWindow < MainWindow + text: TargetBot creature editor + width: 500 + height: 400 + + $mobile: + height: 300 + + Label + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + text-align: center + !text: tr('You can use * (any characters) and ? (any character) in target name') + + Label + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + text-align: center + !text: tr('You can also enter multiple targets, separate them by ,') + + TextEdit + id: name + anchors.top: prev.bottom + anchors.left: parent.left + anchors.right: parent.right + margin-left: 90 + margin-top: 5 + + Label + anchors.verticalCenter: prev.verticalCenter + anchors.left: parent.left + text: Target name: + + VerticalScrollBar + id: contentScroll + anchors.top: name.bottom + anchors.right: parent.right + anchors.bottom: help.top + step: 28 + pixels-scroll: true + margin-right: -10 + margin-top: 5 + margin-bottom: 5 + + ScrollablePanel + id: content + anchors.top: name.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: help.top + vertical-scrollbar: contentScroll + margin-bottom: 10 + + Panel + id: left + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.horizontalCenter + margin-top: 5 + margin-left: 10 + margin-right: 10 + layout: + type: verticalBox + fit-children: true + + Panel + id: right + anchors.top: parent.top + anchors.left: parent.horizontalCenter + anchors.right: parent.right + margin-top: 5 + margin-left: 10 + margin-right: 10 + layout: + type: verticalBox + fit-children: true + + Button + id: help + !text: tr('Help & Tutorials') + anchors.bottom: parent.bottom + anchors.left: parent.left + width: 150 + @onClick: g_platform.openUrl("http://bot.otclient.ovh/") + + Button + id: ok + !text: tr('Ok') + anchors.bottom: parent.bottom + anchors.right: next.left + margin-right: 10 + width: 60 + + Button + id: cancel + !text: tr('Cancel') + anchors.bottom: parent.bottom + anchors.right: parent.right + width: 60 diff --git a/modules/game_bot/default_configs/vBot/targetbot/creature_priority.lua b/modules/game_bot/default_configs/vBot/targetbot/creature_priority.lua new file mode 100644 index 0000000..dcc2f81 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/targetbot/creature_priority.lua @@ -0,0 +1,40 @@ +TargetBot.Creature.calculatePriority = function(creature, config, path) + -- config is based on creature_editor + local priority = 0 + + -- extra priority if it's current target + if g_game.getAttackingCreature() == creature then + priority = priority + 1 + end + + -- check if distance is fine, if not then attack only if already attacked + if #path > config.maxDistance then + return priority + end + + -- add config priority + priority = priority + config.priority + + -- extra priority for close distance + local path_length = #path + if path_length == 1 then + priority = priority + 3 + elseif path_length <= 3 then + priority = priority + 1 + end + + -- extra priority for low health + if config.chase and creature:getHealthPercent() < 30 then + priority = priority + 5 + elseif creature:getHealthPercent() < 20 then + priority = priority + 2.5 + elseif creature:getHealthPercent() < 40 then + priority = priority + 1.5 + elseif creature:getHealthPercent() < 60 then + priority = priority + 0.5 + elseif creature:getHealthPercent() < 80 then + priority = priority + 0.2 + end + + return priority +end \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/targetbot/looting.lua b/modules/game_bot/default_configs/vBot/targetbot/looting.lua new file mode 100644 index 0000000..49c090b --- /dev/null +++ b/modules/game_bot/default_configs/vBot/targetbot/looting.lua @@ -0,0 +1,308 @@ +TargetBot.Looting = {} +TargetBot.Looting.list = {} -- list of containers to loot + +local ui +local items = {} +local containers = {} +local itemsById = {} +local containersById = {} +local dontSave = false + +TargetBot.Looting.setup = function() + ui = UI.createWidget("TargetBotLootingPanel") + UI.Container(TargetBot.Looting.onItemsUpdate, true, nil, ui.items) + UI.Container(TargetBot.Looting.onContainersUpdate, true, nil, ui.containers) + ui.everyItem.onClick = function() + ui.everyItem:setOn(not ui.everyItem:isOn()) + TargetBot.save() + end + ui.maxDangerPanel.value.onTextChange = function() + local value = tonumber(ui.maxDangerPanel.value:getText()) + if not value then + ui.maxDangerPanel.value:setText(0) + end + if dontSave then return end + TargetBot.save() + end + ui.minCapacityPanel.value.onTextChange = function() + local value = tonumber(ui.minCapacityPanel.value:getText()) + if not value then + ui.minCapacityPanel.value:setText(0) + end + if dontSave then return end + TargetBot.save() + end +end + +TargetBot.Looting.onItemsUpdate = function() + if dontSave then return end + TargetBot.save() + TargetBot.Looting.updateItemsAndContainers() +end + +TargetBot.Looting.onContainersUpdate = function() + if dontSave then return end + TargetBot.save() + TargetBot.Looting.updateItemsAndContainers() +end + +TargetBot.Looting.update = function(data) + dontSave = true + TargetBot.Looting.list = {} + ui.items:setItems(data['items'] or {}) + ui.containers:setItems(data['containers'] or {}) + ui.everyItem:setOn(data['everyItem']) + ui.maxDangerPanel.value:setText(data['maxDanger'] or 10) + ui.minCapacityPanel.value:setText(data['minCapacity'] or 100) + TargetBot.Looting.updateItemsAndContainers() + dontSave = false +end + +TargetBot.Looting.save = function(data) + data['items'] = ui.items:getItems() + data['containers'] = ui.containers:getItems() + data['maxDanger'] = tonumber(ui.maxDangerPanel.value:getText()) + data['minCapacity'] = tonumber(ui.minCapacityPanel.value:getText()) + data['everyItem'] = ui.everyItem:isOn() +end + +TargetBot.Looting.updateItemsAndContainers = function() + items = ui.items:getItems() + containers = ui.containers:getItems() + itemsById = {} + containersById = {} + for i, item in ipairs(items) do + itemsById[item.id] = 1 + end + for i, container in ipairs(containers) do + containersById[container.id] = 1 + end +end + +local waitTill = 0 +local waitingForContainer = nil +local status = "" +local lastFoodConsumption = 0 + +TargetBot.Looting.getStatus = function() + return status +end + +TargetBot.Looting.process = function(targets, dangerLevel) + if (not items[1] and not ui.everyItem:isOn()) or not containers[1] then + status = "" + return false + end + if dangerLevel > tonumber(ui.maxDangerPanel.value:getText()) then + status = "High danger" + return false + end + if player:getFreeCapacity() < tonumber(ui.minCapacityPanel.value:getText()) then + status = "No cap" + TargetBot.Looting.list = {} + return false + end + local loot = TargetBot.Looting.list[1] + if loot == nil then + status = "" + return false + end + + if waitTill > now then + return true + end + local containers = g_game.getContainers() + local lootContainers = TargetBot.Looting.getLootContainers(containers) + + -- check if there's container for loot and has empty space for it + if not lootContainers[1] then + -- there's no space, don't loot + status = "No space" + return false + end + + status = "Looting" + + for index, container in pairs(containers) do + if container.lootContainer then + TargetBot.Looting.lootContainer(lootContainers, container) + return true + end + end + + local pos = player:getPosition() + local dist = math.max(math.abs(pos.x-loot.pos.x), math.abs(pos.y-loot.pos.y)) + if loot.tries > 30 or loot.pos.z ~= pos.z or dist > 20 then + table.remove(TargetBot.Looting.list, 1) + return true + end + + local tile = g_map.getTile(loot.pos) + if dist >= 3 or not tile then + loot.tries = loot.tries + 1 + TargetBot.walkTo(loot.pos, 20, { ignoreNonPathable = true, precision = 2 }) + return true + end + + local container = tile:getTopUseThing() + if not container or not container:isContainer() then + table.remove(TargetBot.Looting.list, 1) + return true + end + + g_game.open(container) + waitTill = now + 1000 -- give it 1s to open + waitingForContainer = container:getId() + loot.tries = loot.tries + 10 + + return true +end + +TargetBot.Looting.getLootContainers = function(containers) + local lootContainers = {} + local openedContainersById = {} + local toOpen = nil + for index, container in pairs(containers) do + openedContainersById[container:getContainerItem():getId()] = 1 + if containersById[container:getContainerItem():getId()] and not container.lootContainer then + if container:getItemsCount() < container:getCapacity() then + table.insert(lootContainers, container) + else -- it's full, open next container if possible + for slot, item in ipairs(container:getItems()) do + if item:isContainer() and containersById[item:getId()] then + toOpen = {item, container} + break + end + end + end + end + end + if not lootContainers[1] then + if toOpen then + g_game.open(toOpen[1], toOpen[2]) + waitTill = now + 500 -- wait 0.5s + return lootContainers + end + -- check containers one more time, maybe there's any loot container + for index, container in pairs(containers) do + if not containersById[container:getContainerItem():getId()] and not container.lootContainer then + for slot, item in ipairs(container:getItems()) do + if item:isContainer() and containersById[item:getId()] then + g_game.open(item) + waitTill = now + 500 -- wait 0.5s + return lootContainers + end + end + end + end + -- can't find any lootContainer, let's check slots, maybe there's one + for slot = InventorySlotFirst, InventorySlotLast do + local item = getInventoryItem(slot) + if item and item:isContainer() and not openedContainersById[item:getId()] then + -- container which is not opened yet, let's open it + g_game.open(item) + waitTill = now + 500 -- wait 0.5s + return lootContainers + end + end + end + return lootContainers +end + +TargetBot.Looting.lootContainer = function(lootContainers, container) + -- loot items + local nextContainer = nil + for i, item in ipairs(container:getItems()) do + if item:isContainer() and not itemsById[item:getId()] then + nextContainer = item + elseif itemsById[item:getId()] or (ui.everyItem:isOn() and not item:isContainer()) then + item.lootTries = (item.lootTries or 0) + 1 + if item.lootTries < 5 then -- if can't be looted within 0.5s then skip it + return TargetBot.Looting.lootItem(lootContainers, item) + end + elseif storage.foodItems and storage.foodItems[1] and lastFoodConsumption + 5000 < now then + for _, food in ipairs(storage.foodItems) do + if item:getId() == food.id then + g_game.use(item) + lastFoodConsumption = now + return + end + end + end + end + + -- no more items to loot, open next container + if nextContainer then + nextContainer.lootTries = (nextContainer.lootTries or 0) + 1 + if nextContainer.lootTries < 2 then -- max 0.6s to open it + g_game.open(nextContainer, container) + waitTill = now + 300 -- give it 0.3s to open + waitingForContainer = nextContainer:getId() + return + end + end + + -- looting finished, remove container from list + container.lootContainer = false + g_game.close(container) + table.remove(TargetBot.Looting.list, 1) +end + +onTextMessage(function(mode, text) + if TargetBot.isOff() then return end + if #TargetBot.Looting.list == 0 then return end + if string.find(text:lower(), "you are not the owner") then -- if we are not the owners of corpse then its a waste of time to try to loot it + table.remove(TargetBot.Looting.list, 1) + end +end) + +TargetBot.Looting.lootItem = function(lootContainers, item) + if item:isStackable() then + local count = item:getCount() + for _, container in ipairs(lootContainers) do + for slot, citem in ipairs(container:getItems()) do + if item:getId() == citem:getId() and citem:getCount() < 100 then + g_game.move(item, container:getSlotPosition(slot - 1), count) + waitTill = now + 300 -- give it 0.3s to move item + return + end + end + end + end + + local container = lootContainers[1] + g_game.move(item, container:getSlotPosition(container:getItemsCount()), 1) + waitTill = now + 300 -- give it 0.3s to move item +end + +onContainerOpen(function(container, previousContainer) + if container:getContainerItem():getId() == waitingForContainer then + container.lootContainer = true + waitingForContainer = nil + end +end) + +onCreatureDisappear(function(creature) + if isInPz() then return end + if not TargetBot.isOn() then return end + if not creature:isMonster() then return end + local config = TargetBot.Creature.calculateParams(creature, {}) -- return {craeture, config, danger, priority} + if not config.config or config.config.dontLoot then + return + end + local pos = player:getPosition() + local mpos = creature:getPosition() + local name = creature:getName() + if pos.z ~= mpos.z or math.max(math.abs(pos.x-mpos.x), math.abs(pos.y-mpos.y)) > 6 then return end + schedule(20, function() -- check in 20ms if there's container (dead body) on that tile + if not containers[1] then return end + if TargetBot.Looting.list[20] then return end -- too many items to loot + local tile = g_map.getTile(mpos) + if not tile then return end + local container = tile:getTopUseThing() + if not container or not container:isContainer() then return end + if not findPath(player:getPosition(), mpos, 6, {ignoreNonPathable=true, ignoreCreatures=true, ignoreCost=true}) then return end + table.insert(TargetBot.Looting.list, {pos=mpos, creature=name, container=container:getId(), added=now, tries=0}) + container:setMarked('#000088') + end) +end) diff --git a/modules/game_bot/default_configs/vBot/targetbot/looting.otui b/modules/game_bot/default_configs/vBot/targetbot/looting.otui new file mode 100644 index 0000000..97cb351 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/targetbot/looting.otui @@ -0,0 +1,83 @@ +TargetBotLootingPanel < Panel + layout: + type: verticalBox + fit-children: true + + HorizontalSeparator + margin-top: 5 + + Label + margin-top: 5 + text: Items to loot + text-align: center + + BotContainer + id: items + margin-top: 3 + + BotSwitch + id: everyItem + !text: tr("Loot every item") + margin-top: 2 + + Label + margin-top: 5 + text: Containers for loot + text-align: center + + BotContainer + id: containers + margin-top: 3 + height: 45 + + Panel + id: maxDangerPanel + height: 20 + margin-top: 5 + + BotTextEdit + id: value + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + margin-right: 6 + width: 80 + + Label + anchors.left: parent.left + anchors.verticalCenter: prev.verticalCenter + text: Max. danger: + margin-left: 5 + + Panel + id: minCapacityPanel + height: 20 + margin-top: 3 + + BotTextEdit + id: value + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + margin-right: 6 + width: 80 + + Label + anchors.left: parent.left + anchors.verticalCenter: prev.verticalCenter + text: Min. capacity: + margin-left: 5 + + Label + margin-top: 3 + margin-left: 20 + margin-right: 20 + !text: tr("Drag item or click on any of empty slot") + text-align: center + text-wrap: true + text-auto-resize: true + + BotButton + margin-top: 3 + text: Help & Tutorials + @onClick: g_platform.openUrl("http://bot.otclient.ovh/") diff --git a/modules/game_bot/default_configs/vBot/targetbot/target.lua b/modules/game_bot/default_configs/vBot/targetbot/target.lua new file mode 100644 index 0000000..ab29fcb --- /dev/null +++ b/modules/game_bot/default_configs/vBot/targetbot/target.lua @@ -0,0 +1,298 @@ +local targetbotMacro = nil +local config = nil +local lastAction = 0 +local cavebotAllowance = 0 +local lureEnabled = true +storage.targebotDanger = 0 + +-- ui +local configWidget = UI.Config() +local ui = UI.createWidget("TargetBotPanel") + +ui.list = ui.listPanel.list -- shortcut +TargetBot.targetList = ui.list +TargetBot.Looting.setup() + +ui.status.left:setText("Status:") +ui.status.right:setText("Off") +ui.target.left:setText("Target:") +ui.target.right:setText("-") +ui.config.left:setText("Config:") +ui.config.right:setText("-") +ui.danger.left:setText("Danger:") +ui.danger.right:setText("0") + +ui.editor.debug.onClick = function() + local on = ui.editor.debug:isOn() + ui.editor.debug:setOn(not on) + if on then + for _, spec in ipairs(getSpectators()) do + spec:clearText() + end + end +end + +local oldTibia = g_game.getClientVersion() < 960 + +-- main loop, controlled by config +targetbotMacro = macro(100, function() + local pos = player:getPosition() + local creatures = g_map.getSpectatorsInRange(pos, false, 6, 6) -- 12x12 area + if #creatures > 10 then -- if there are too many monsters around, limit area + creatures = g_map.getSpectatorsInRange(pos, false, 3, 3) -- 6x6 area + end + local highestPriority = 0 + local dangerLevel = 0 + local targets = 0 + local highestPriorityParams = nil + for i, creature in ipairs(creatures) do + local path = findPath(player:getPosition(), creature:getPosition(), 7, {ignoreLastCreature=true, ignoreNonPathable=true, ignoreCost=true}) + if creature:isMonster() and (oldTibia or creature:getType() < 3) and path then + local params = TargetBot.Creature.calculateParams(creature, path) -- return {craeture, config, danger, priority} + dangerLevel = dangerLevel + params.danger + if params.priority > 0 then + targets = targets + 1 + if params.priority > highestPriority then + highestPriority = params.priority + highestPriorityParams = params + end + if ui.editor.debug:isOn() then + creature:setText(params.config.name .. "\n" .. params.priority) + end + end + end + end + + -- reset walking + TargetBot.walkTo(nil) + + -- looting + local looting = TargetBot.Looting.process(targets, dangerLevel) + local lootingStatus = TargetBot.Looting.getStatus() + storage.lootStatus = TargetBot.Looting.getStatus() + storage.targebotDanger = dangerLevel + + ui.danger.right:setText(dangerLevel) + if highestPriorityParams and not isInPz() then + ui.target.right:setText(highestPriorityParams.creature:getName()) + ui.config.right:setText(highestPriorityParams.config.name) + TargetBot.Creature.attack(highestPriorityParams, targets, looting) + if lootingStatus:len() > 0 then + TargetBot.setStatus("Attack & " .. lootingStatus) + elseif cavebotAllowance > now then + TargetBot.setStatus("Luring using CaveBot") + else + TargetBot.setStatus("Attacking") + if not lureEnabled then + TargetBot.setStatus("Attacking (luring off)") + end + end + TargetBot.walk() + lastAction = now + return + end + + ui.target.right:setText("-") + ui.config.right:setText("-") + if looting then + TargetBot.walk() + lastAction = now + end + if lootingStatus:len() > 0 then + TargetBot.setStatus(lootingStatus) + else + TargetBot.setStatus("Waiting") + end +end) + +-- config, its callback is called immediately, data can be nil +config = Config.setup("targetbot_configs", configWidget, "json", function(name, enabled, data) + if not data then + ui.status.right:setText("Off") + return targetbotMacro.setOff() + end + TargetBot.Creature.resetConfigs() + for _, value in ipairs(data["targeting"] or {}) do + TargetBot.Creature.addConfig(value) + end + TargetBot.Looting.update(data["looting"] or {}) + + -- add configs + if enabled then + ui.status.right:setText("On") + else + ui.status.right:setText("Off") + end + + targetbotMacro.setOn(enabled) + targetbotMacro.delay = nil + lureEnabled = true +end) + +-- setup ui +ui.editor.buttons.add.onClick = function() + TargetBot.Creature.edit(nil, function(newConfig) + TargetBot.Creature.addConfig(newConfig, true) + TargetBot.save() + end) +end + +ui.editor.buttons.edit.onClick = function() + local entry = ui.list:getFocusedChild() + if not entry then return end + TargetBot.Creature.edit(entry.value, function(newConfig) + entry:setText(newConfig.name) + entry.value = newConfig + TargetBot.Creature.resetConfigsCache() + TargetBot.save() + end) +end + +ui.editor.buttons.remove.onClick = function() + local entry = ui.list:getFocusedChild() + if not entry then return end + entry:destroy() + TargetBot.Creature.resetConfigsCache() + TargetBot.save() +end + +-- public function, you can use them in your scripts +TargetBot.isActive = function() -- return true if attacking or looting takes place + return lastAction + 300 > now +end + +TargetBot.isCaveBotActionAllowed = function() + return cavebotAllowance > now +end + +TargetBot.setStatus = function(text) + return ui.status.right:setText(text) +end + +TargetBot.isOn = function() + return config.isOn() +end + +TargetBot.isOff = function() + return config.isOff() +end + +TargetBot.setOn = function(val) + if val == false then + return TargetBot.setOff(true) + end + config.setOn() +end + +TargetBot.setOff = function(val) + if val == false then + return TargetBot.setOn(true) + end + config.setOff() +end + +TargetBot.delay = function(value) + targetbotMacro.delay = now + value +end + +TargetBot.save = function() + local data = {targeting={}, looting={}} + for _, entry in ipairs(ui.list:getChildren()) do + table.insert(data.targeting, entry.value) + end + TargetBot.Looting.save(data.looting) + config.save(data) +end + +TargetBot.allowCaveBot = function(time) + cavebotAllowance = now + time +end + +TargetBot.disableLuring = function() + lureEnabled = false +end + +TargetBot.enableLuring = function() + lureEnabled = true +end + +TargetBot.Danger = function() + return storage.dangerLevel or 0 +end + +TargetBot.lootStatus = function() + return storage.lootStatus or "" +end + + +-- attacks +local lastSpell = 0 +local lastAttackSpell = 0 + +TargetBot.saySpell = function(text, delay) + if type(text) ~= 'string' or text:len() < 1 then return end + if not delay then delay = 500 end + if g_game.getProtocolVersion() < 1090 then + lastAttackSpell = now -- pause attack spells, healing spells are more important + end + if lastSpell + delay < now then + say(text) + lastSpell = now + return true + end + return false +end + +TargetBot.sayAttackSpell = function(text, delay) + if type(text) ~= 'string' or text:len() < 1 then return end + if not delay then delay = 2000 end + if lastAttackSpell + delay < now then + say(text) + lastAttackSpell = now + return true + end + return false +end + +local lastItemUse = 0 +local lastRuneAttack = 0 + +TargetBot.useItem = function(item, subType, target, delay) + if not delay then delay = 200 end + if lastItemUse + delay < now then + local thing = g_things.getThingType(item) + if not thing or not thing:isFluidContainer() then + subType = g_game.getClientVersion() >= 860 and 0 or 1 + end + if g_game.getClientVersion() < 780 then + local tmpItem = g_game.findPlayerItem(item, subType) + if not tmpItem then return end + g_game.useWith(tmpItem, target, subType) -- using item from bp + else + g_game.useInventoryItemWith(item, target, subType) -- hotkey + end + lastItemUse = now + end +end + +TargetBot.useAttackItem = function(item, subType, target, delay) + if not delay then delay = 2000 end + if lastRuneAttack + delay < now then + local thing = g_things.getThingType(item) + if not thing or not thing:isFluidContainer() then + subType = g_game.getClientVersion() >= 860 and 0 or 1 + end + if g_game.getClientVersion() < 780 then + local tmpItem = g_game.findPlayerItem(item, subType) + if not tmpItem then return end + g_game.useWith(tmpItem, target, subType) -- using item from bp + else + g_game.useInventoryItemWith(item, target, subType) -- hotkey + end + lastRuneAttack = now + end +end + +TargetBot.canLure = function() + return lureEnabled +end \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/targetbot/target.otui b/modules/game_bot/default_configs/vBot/targetbot/target.otui new file mode 100644 index 0000000..6e0e4ea --- /dev/null +++ b/modules/game_bot/default_configs/vBot/targetbot/target.otui @@ -0,0 +1,115 @@ +TargetBotEntry < Label + background-color: alpha + text-offset: 2 0 + focusable: true + + $focus: + background-color: #00000055 + +TargetBotDualLabel < Panel + height: 18 + margin-left: 3 + margin-right: 4 + + Label + id: left + anchors.top: parent.top + anchors.left: parent.left + text-auto-resize: true + + Label + id: right + anchors.top: parent.top + anchors.right: parent.right + text-auto-resize: true + +TargetBotPanel < Panel + layout: + type: verticalBox + fit-children: true + + HorizontalSeparator + margin-top: 2 + margin-bottom: 5 + + TargetBotDualLabel + id: status + TargetBotDualLabel + id: target + TargetBotDualLabel + id: config + TargetBotDualLabel + id: danger + + Panel + id: listPanel + height: 40 + + 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: configButton + @onClick: | + self:setOn(not self:isOn()) + self:getParent().listPanel:setHeight(self:isOn() and 100 or 40) + self:getParent().editor:setVisible(self:isOn()) + + $on: + text: Hide target editor + + $!on: + text: Show target editor + + Panel + id: editor + visible: false + layout: + type: verticalBox + fit-children: true + + Panel + id: buttons + height: 20 + margin-top: 2 + + Button + id: add + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + text: Add + width: 56 + + Button + id: edit + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + text: Edit + width: 56 + + Button + id: remove + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + text: Remove + width: 56 + + BotSwitch + id: debug + text: Show target priority diff --git a/modules/game_bot/default_configs/vBot/targetbot/walking.lua b/modules/game_bot/default_configs/vBot/targetbot/walking.lua new file mode 100644 index 0000000..b256d6a --- /dev/null +++ b/modules/game_bot/default_configs/vBot/targetbot/walking.lua @@ -0,0 +1,28 @@ +local dest +local maxDist +local params + +TargetBot.walkTo = function(_dest, _maxDist, _params) + dest = _dest + maxDist = _maxDist + params = _params +end + +-- called every 100ms if targeting or looting is active +TargetBot.walk = function() + if not dest then return end + if player:isWalking() then return end + local pos = player:getPosition() + if pos.z ~= dest.z then return end + local dist = math.max(math.abs(pos.x-dest.x), math.abs(pos.y-dest.y)) + if params.precision and params.precision >= dist then return end + if params.marginMin and params.marginMax then + if dist >= params.marginMin and dist <= params.marginMax then + return + end + end + local path = getPath(pos, dest, maxDist, params) + if path then + walk(path[1]) + end +end diff --git a/modules/game_bot/default_configs/vBot/test.lua b/modules/game_bot/default_configs/vBot/test.lua new file mode 100644 index 0000000..91d8d0e --- /dev/null +++ b/modules/game_bot/default_configs/vBot/test.lua @@ -0,0 +1,9 @@ +local m = macro(1000, "Floor Change Delay", function() end) + +onPlayerPositionChange(function(x,y) + if m.isOff() then return end + if CaveBot.isOff() then return end + if x.z ~= y.z then + TargetBot.delay(500) + end +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/tools.lua b/modules/game_bot/default_configs/vBot/tools.lua new file mode 100644 index 0000000..5f7524e --- /dev/null +++ b/modules/game_bot/default_configs/vBot/tools.lua @@ -0,0 +1,60 @@ +-- tools tab +setDefaultTab("Tools") + +-- allows to test/edit bot lua scripts ingame, you can have multiple scripts like this, just change storage.ingame_lua +UI.Button("Ingame hotkey editor", function(newText) + UI.MultilineEditorWindow(storage.ingame_hotkeys or "", {title="Hotkeys editor", description="You can add your custom hotkeys/singlehotkeys here"}, function(text) + storage.ingame_hotkeys = text + reload() + end) +end) + +UI.Separator() + +for _, scripts in pairs({storage.ingame_hotkeys}) do + if type(scripts) == "string" and scripts:len() > 3 then + local status, result = pcall(function() + assert(load(scripts, "ingame_editor"))() + end) + if not status then + error("Ingame edior error:\n" .. result) + end + end +end + +UI.Separator() + +local moneyIds = {3031, 3035} -- gold coin, platinium coin +macro(1000, "Exchange money", function() + local containers = g_game.getContainers() + for index, container in pairs(containers) do + if not container.lootContainer then -- ignore monster containers + for i, item in ipairs(container:getItems()) do + if item:getCount() == 100 then + for m, moneyId in ipairs(moneyIds) do + if item:getId() == moneyId then + return g_game.use(item) + end + end + end + end + end + end +end) + +UI.Separator() + +macro(60000, "Send message on trade", function() + local trade = getChannelId("advertising") + if not trade then + trade = getChannelId("trade") + end + if trade and storage.autoTradeMessage:len() > 0 then + sayChannel(trade, storage.autoTradeMessage) + end +end) +UI.TextEdit(storage.autoTradeMessage or "I'm using OTClientV8!", function(widget, text) + storage.autoTradeMessage = text +end) + +UI.Separator() diff --git a/modules/game_bot/default_configs/vBot/use_all.lua b/modules/game_bot/default_configs/vBot/use_all.lua new file mode 100644 index 0000000..3491198 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/use_all.lua @@ -0,0 +1,40 @@ +-- config +storage.shovel = 9596 +storage.rope = 9596 +storage.machete = 9596 +storage.scythe = 9596 + +local useId = {34847, 1764, 21051, 30823, 6264, 5282, 20453, 20454, 20474, 11708, 11705, 6257, 6256, 2772, 27260, 2773, 1632, 1633, 1948, 435, 6252, 6253, 5007, 4911, 1629, 1630, 5108, 5107, 5281, 1968, 435, 1948, 5542, 31116, 31120, 30742, 31115, 31118, 20474, 5737, 5736, 5734, 5733, 31202, 31228, 31199, 31200, 33262, 30824, 5125, 5126, 5116, 5117, 8257, 8258, 8255, 8256} +local shovelId = {606, 593, 867} +local ropeId = {17238, 12202, 12935, 386, 421, 21966, 14238} +local macheteId = {2130, 3696} +local scytheId = {3653} + +setDefaultTab("Tools") +-- script +hotkey("space", "Use All", function() + if not modules.game_walking.wsadWalking then return end + for _, tile in pairs(g_map.getTiles(posz())) do + if distanceFromPlayer(tile:getPosition()) < 2 then + for _, item in pairs(tile:getItems()) do + -- use + if table.find(useId, item:getId()) then + use(item) + return + elseif table.find(shovelId, item:getId()) then + useWith(storage.shovel, item) + return + elseif table.find(ropeId, item:getId()) then + useWith(storage.rope, item) + return + elseif table.find(macheteId, item:getId()) then + useWith(storage.machete, item) + return + elseif table.find(scytheId, item:getId()) then + useWith(storage.scythe, item) + return + end + end + end + end +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/z_antiRs.lua b/modules/game_bot/default_configs/vBot/z_antiRs.lua new file mode 100644 index 0000000..d4c24d8 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/z_antiRs.lua @@ -0,0 +1,14 @@ +setDefaultTab("Tools") +local m = macro(1000, "AntiRS & Msg", function() end) + +local frags = 0 +onTextMessage(function(mode, text) + if not m.isOn() then return end + if not text:lower():find("warning! the murder of") then return end + info(text) + say("Don't bother, I have anti-rs and shit EQ. Don't waste our time.") + frags = frags + 1 + if killsToRs() < 6 or frags > 1 then + modules.game_interface.forceExit() + end +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/z_click_reuse.lua b/modules/game_bot/default_configs/vBot/z_click_reuse.lua new file mode 100644 index 0000000..680ca7b --- /dev/null +++ b/modules/game_bot/default_configs/vBot/z_click_reuse.lua @@ -0,0 +1,15 @@ +setDefaultTab("Tools") + +local reUseToggle = macro(1000, "Click ReUse", "`", function() end) +local excluded = {268, 237, 238, 23373, 266, 236, 239, 7643, 23375, 7642, 23374, 5908, 5942, storage.shovel, storage.rope, storage.machete} + +onUseWith(function(pos, itemId, target, subType) + if reUseToggle.isOn() and not table.find(excluded, itemId) then + schedule(50, function() + item = findItem(itemId) + if item then + modules.game_interface.startUseWith(item) + end + end) + end +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/z_depot_withdraw.lua b/modules/game_bot/default_configs/vBot/z_depot_withdraw.lua new file mode 100644 index 0000000..8323f71 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/z_depot_withdraw.lua @@ -0,0 +1,76 @@ +-- config +setDefaultTab("Tools") +local defaultBp = "shopping bag" +local id = 21411 + +-- script + +local playerContainer = nil +local depotContainer = nil +local mailContainer = nil + +function reopenLootContainer() + for _, container in pairs(getContainers()) do + if container:getName():lower() == defaultBp:lower() then + g_game.close(container) + end + end + + local lootItem = findItem(id) + if lootItem then + schedule(500, function() g_game.open(lootItem) end) + end + +end + +macro(50, "Depot Withdraw", function() + + -- set the containers + if not potionsContainer or not runesContainer or not ammoContainer then + for i, container in pairs(getContainers()) do + if container:getName() == defaultBp then + playerContainer = container + elseif string.find(container:getName(), "Depot") then + depotContainer = container + elseif string.find(container:getName(), "your inbox") then + mailContainer = container + end + end + end + + if playerContainer and #playerContainer:getItems() == 20 then + for j, item in pairs(playerContainer:getItems()) do + if item:getId() == id then + g_game.open(item, playerContainer) + return + end + end + end + + +if playerContainer and freecap() >= 200 then + local time = 500 + if depotContainer then + for i, container in pairs(getContainers()) do + if string.find(container:getName(), "Depot") then + for j, item in pairs(container:getItems()) do + g_game.move(item, playerContainer:getSlotPosition(playerContainer:getItemsCount()), item:getCount()) + return + end + end + end + end + + if mailContainer then + for i, container in pairs(getContainers()) do + if string.find(container:getName(), "your inbox") then + for j, item in pairs(container:getItems()) do + g_game.move(item, playerContainer:getSlotPosition(playerContainer:getItemsCount()), item:getCount()) + return + end + end + end + end +end + +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/z_hold_mwall.lua b/modules/game_bot/default_configs/vBot/z_hold_mwall.lua new file mode 100644 index 0000000..43c5c67 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/z_hold_mwall.lua @@ -0,0 +1,48 @@ +setDefaultTab("Tools") +local hotkey = "PageUp" + +local candidates = {} + +local m = macro(20, "Hold Mwall", function() + if #candidates == 0 then return end + + for _, tile in pairs(candidates) do + if tile:canShoot() then + useWith(3180, tile:getTopUseThing()) + end + end +end) + +onRemoveThing(function(tile, thing) + if m.isOff() then return end + if thing:getId() ~= 2129 then return end + if tile:getText():len() > 0 then + table.insert(candidates, tile) + useWith(3180, tile:getTopUseThing()) + end +end) + +onAddThing(function(tile, thing) + if m.isOff() then return end + if thing:getId() ~= 2129 then return end + if tile:getText():len() > 0 then + table.remove(candidates, table.find(candidates,tile)) + end +end) + +onKeyPress(function(keys) + if m.isOff() then return end + if keys ~= hotkey then return end + + local tile = getTileUnderCursor() + if not tile then return end + + if tile:getText():len() > 0 then + tile:setText("") + else + tile:setText("MARKED") + table.insert(candidates, tile) + end +end) + + diff --git a/modules/game_bot/default_configs/vBot/z_info.lua b/modules/game_bot/default_configs/vBot/z_info.lua new file mode 100644 index 0000000..8fca82f --- /dev/null +++ b/modules/game_bot/default_configs/vBot/z_info.lua @@ -0,0 +1,449 @@ +setDefaultTab("Main") + +-- first, the variables +local launchTime = now +local startExp = exp() +local dmgTable = {} +local healTable = {} +local expTable = {} +local totalDmg = 0 +local totalHeal = 0 +local dmgDistribution = {} +local first = "-" +local second = "-" +local third = "-" + +if not storage.bestHit or type(storage.bestHit) ~= "number" then + storage.bestHit = 0 +end +if not storage.bestHeal or type(storage.bestHeal) ~= "number" then + storage.bestHeal = 0 +end + +local resetSessionData = function() + launchTime = now + startExp = exp() + dmgTable = {} + healTable = {} + expTable = {} + totalDmg = 0 + totalHeal = 0 + dmgDistribution = {} + first = "-" + second = "-" + third = "-" +end + +function format_thousand(v) + if not v then return 0 end + local s = string.format("%d", math.floor(v)) + local pos = string.len(s) % 3 + if pos == 0 then pos = 3 end + return string.sub(s, 1, pos) + .. string.gsub(string.sub(s, pos+1), "(...)", ".%1") + end + +local expGained = function() + return exp() - startExp +end +local expLeft = function() + local level = lvl()+1 + return math.floor((50*level*level*level)/3 - 100*level*level + (850*level)/3 - 200) - exp() +end + +local niceTimeFormat = function(v) -- v in seconds + local hours = string.format("%02.f", math.floor(v/3600)) + local mins = string.format("%02.f", math.floor(v/60 - (hours*60))) + return hours .. ":" .. mins .. "h" +end +local sessionTime = function() + uptime = math.floor((now - launchTime)/1000) + return niceTimeFormat(uptime) +end + +local expPerHour = function(calculation) + local r = 0 + if #expTable > 0 then + r = exp() - expTable[1] + else + return "-" + end + + if uptime < 15*60 then + r = math.ceil((r/uptime)*60*60) + else + r = math.ceil(r*8) + end + if calculation then + return r + else + return format_thousand(r) + end +end + +local timeToLevel = function() + local t = 0 + if expPerHour(true) == 0 or expPerHour() == "-" then + return "-" + else + t = expLeft()/expPerHour(true) + return niceTimeFormat(math.ceil(t*60*60)) + end +end + +local sumT = function(t) + local s = 0 + for i,v in pairs(t) do + s = s + v.d + end + return s +end + +local valueInSeconds = function(t) + local d = 0 + local time = 0 + if #t > 0 then + for i, v in ipairs(t) do + if now - v.t <= 3000 then + if time == 0 then + time = v.t + end + d = d + v.d + else + table.remove(t, 1) + end + end + end + return math.ceil(d/((now-time)/1000)) +end + +local regex = "You lose ([0-9]*) hitpoints due to an attack by ([a-z*]) ([a-z A-z-]*)" +onTextMessage(function(mode, text) + if mode == 21 then -- damage dealt + totalDmg = totalDmg + getFirstNumberInText(text) + table.insert(dmgTable, {d = getFirstNumberInText(text), t = now}) + if getFirstNumberInText(text) > storage.bestHit then + storage.bestHit = getFirstNumberInText(text) + end + end + if mode == 23 then -- healing + totalHeal = totalHeal + getFirstNumberInText(text) + table.insert(healTable, {d = getFirstNumberInText(text), t = now}) + if getFirstNumberInText(text) > storage.bestHeal then + storage.bestHeal = getFirstNumberInText(text) + end + end + + -- damage distribution part + if text:find("You lose") then + local data = regexMatch(text, regex)[1] + if data then + local monster = data[4] + local val = data[2] + table.insert(dmgDistribution, {v=val,m=monster,t=now}) + end + end +end) + + +-- tables maintance +macro(500, function() + local dmgFinal = {} + local labelTable = {} + local dmgSum = 0 + table.insert(expTable, exp()) + if #expTable > 15*60 then + for i,v in pairs(expTable) do + if i == 1 then + table.remove(expTable, i) + end + end + end + + for i,v in pairs(dmgDistribution) do + if now - v.t > 60*1000*10 then + table.remove(dmgDistribution, i) + else + dmgSum = dmgSum + v.v + if not dmgFinal[v.m] then + dmgFinal[v.m] = v.v + else + dmgFinal[v.m] = dmgFinal[v.m] + v.v + end + end + end + + if not dmgFinal[1] then + first = "-" + end + if not dmgFinal[2] then + second = "-" + end + if not dmgFinal[3] then + third = "-" + end + + local iter = 0 + for k,v in pairs(dmgFinal) do + table.insert(labelTable, {m=k, d=tonumber(v)}) + end + + table.sort(labelTable, function(a,b) return a.d > b.d end) + + for i,v in pairs(labelTable) do + local label = v.m .. ": " .. math.floor((v.d/dmgSum)*100) .. "%" + if i == 1 then + first = label + elseif i == 2 then + second = label + elseif i == 3 then + third = label + end + end +end) + +UI.Label("Session Analyzers") +UI.Separator() +UI.Button("Reset Session", function() resetSessionData() end) +UI.Separator() + +-- visuals +local ui = setupUI([[ +Panel + height: 270 + padding: 5 + + Label + id: SessionLabel + anchors.top: parent.top + anchors.left: parent.left + text: Session: + + Label + id: XpGainLabel + anchors.top: prev.bottom + anchors.left: parent.left + margin-top: 5 + text: XP Gain: + + Label + id: XpHourLabel + anchors.top: prev.bottom + anchors.left: parent.left + margin-top: 5 + text: XP/h: + + Label + id: NextLevelLabel + anchors.top: prev.bottom + anchors.left: parent.left + margin-top: 5 + text: Next Level: + + Label + id: BurstDamageLabel + anchors.top: prev.bottom + anchors.left: parent.left + margin-top: 5 + text: Burst Damage: + + Label + id: DamageDealtLabel + anchors.top: prev.bottom + anchors.left: parent.left + margin-top: 5 + text: Damage Dealt: + + Label + id: DPSLabel + anchors.top: prev.bottom + anchors.left: parent.left + margin-top: 5 + text: DPS: + + Label + id: BestHitLabel + anchors.top: prev.bottom + anchors.left: parent.left + margin-top: 5 + text: Best Hit: + + Label + id: HealingDoneLabel + anchors.top: prev.bottom + anchors.left: parent.left + margin-top: 5 + text: Healing Done: + + Label + id: HPSLabel + anchors.top: prev.bottom + anchors.left: parent.left + margin-top: 5 + text: HPS: + + Label + id: BestHealLabel + anchors.top: prev.bottom + anchors.left: parent.left + margin-top: 5 + text: Best Heal: + + Label + id: one + anchors.right: parent.right + anchors.verticalCenter: SessionLabel.verticalCenter + text-align: right + text: 00:00h + width: 150 + + Label + id: two + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 5 + text-align: right + text: 0 + width: 150 + + Label + id: three + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 5 + text-align: right + text: - + width: 150 + + Label + id: four + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 5 + text-align: right + text: - + width: 150 + + Label + id: five + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 5 + text-align: right + text: 0 + width: 150 + + Label + id: six + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 5 + text-align: right + text: - + width: 150 + + Label + id: seven + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 5 + text-align: right + text: 0 + width: 150 + + Label + id: eight + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 5 + text-align: right + text: 0 + width: 150 + + Label + id: nine + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 5 + text-align: right + text: 0 + width: 150 + + Label + id: ten + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 5 + text-align: right + text: 0 + width: 150 + + Label + id: eleven + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 5 + text-align: right + text: 0 + width: 150 + + HorizontalSeparator + anchors.top: prev.bottom + anchors.left: parent.left + anchors.right: parent.right + margin-top: 3 + + Label + anchors.top: prev.bottom + anchors.left: parent.left + anchors.right: parent.right + margin-top: 3 + text-align: center + text: Damage Distribution + + Label + id: dOne + anchors.top: prev.bottom + anchors.left: parent.left + anchors.right: parent.right + margin-top: 5 + text-align: center + text: - + + Label + id: dTwo + anchors.top: prev.bottom + anchors.left: parent.left + anchors.right: parent.right + margin-top: 5 + text-align: center + text: - + + Label + id: dThree + anchors.top: prev.bottom + anchors.left: parent.left + anchors.right: parent.right + margin-top: 5 + text-align: center + text: - +]]) +ui:setId("analyzers") + +macro(500, function() + -- refresh part + ui.one:setText(sessionTime()) + ui.two:setText(format_thousand(expGained())) + ui.three:setText(expPerHour()) + ui.four:setText(timeToLevel()) + ui.five:setText(format_thousand(burstDamageValue())) + ui.six:setText(format_thousand(totalDmg)) + ui.seven:setText(format_thousand(valueInSeconds(dmgTable))) + ui.eight:setText(format_thousand(storage.bestHit)) + ui.nine:setText(format_thousand(totalHeal)) + ui.ten:setText(format_thousand(valueInSeconds(healTable))) + ui.eleven:setText(format_thousand(storage.bestHeal)) + ui.dOne:setText(first) + ui.dTwo:setText(second) + ui.dThree:setText(third) +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/z_items_management.lua b/modules/game_bot/default_configs/vBot/z_items_management.lua new file mode 100644 index 0000000..a8704fa --- /dev/null +++ b/modules/game_bot/default_configs/vBot/z_items_management.lua @@ -0,0 +1,79 @@ +setDefaultTab("Tools") +UI.Separator() +UI.Label("Items Management") +UI.Separator() + +UI.Label("Trash items:") +if type(storage.trashItems) ~= "table" or not storage.trashItems then + storage.trashItems = {283, 284, 285} +end + +local dropContainer = UI.Container(function(widget, items) + storage.trashItems = items +end, true) +dropContainer:setHeight(35) +dropContainer:setItems(storage.trashItems) + +macro(200, "Drop Items", function() + if not storage.trashItems[1] then return end + for _, container in pairs(g_game.getContainers()) do + for __, item in ipairs(container:getItems()) do + for i, trashItem in ipairs(storage.trashItems) do + if item:getId() == trashItem.id then + return g_game.move(item, pos(), item:getCount()) + end + end + end + end +end) + +UI.Label("Items to use:") +if type(storage.useItems) ~= "table" or not storage.useItems then + storage.useItems = {21203, 14758} +end + +local useContainer = UI.Container(function(widget, items) + storage.useItems = items +end, true) +useContainer:setHeight(35) +useContainer:setItems(storage.useItems) + +macro(200, "Use Items", function() + if not storage.useItems[1] then return end + for _, container in pairs(g_game.getContainers()) do + for __, item in ipairs(container:getItems()) do + for i, useItem in ipairs(storage.useItems) do + if item:getId() == useItem.id then + return use(item) + end + end + end + end +end) + +UI.Label("Items to drop below 150 cap:") +if type(storage.lowCapDrop) ~= "table" or not storage.lowCapDrop then + storage.lowCapDrop = {21175} +end + +local useContainer = UI.Container(function(widget, items) + storage.lowCapDrop = items +end, true) +useContainer:setHeight(35) +useContainer:setItems(storage.lowCapDrop) + +macro(200, "Drop Items", function() + if not storage.lowCapDrop[1] then return end + if freecap() > 150 then return end + for _, container in pairs(g_game.getContainers()) do + for __, item in ipairs(container:getItems()) do + for i, dropItem in ipairs(storage.lowCapDrop) do + if item:getId() == dropItem.id then + return g_game.move(item, pos(), item:getCount()) + end + end + end + end +end) + +UI.Separator() \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/z_mwalls.lua b/modules/game_bot/default_configs/vBot/z_mwalls.lua new file mode 100644 index 0000000..b86310e --- /dev/null +++ b/modules/game_bot/default_configs/vBot/z_mwalls.lua @@ -0,0 +1,27 @@ +setDefaultTab("Tools") +local toggle = macro(1000, "mwall step", "F12",function() end) + +onPlayerPositionChange(function(newPos, oldPos) + if oldPos.z ~= posz() then return end + if oldPos then + local tile = g_map.getTile(oldPos) + if toggle.isOn() and tile:isWalkable() then + useWith(3180, tile:getTopUseThing()) + toggle.setOff() + end + end +end) + +local toggle2 = macro(1000, "mwall on target", "F11",function() end) + +onCreaturePositionChange(function(creature, newPos, oldPos) + if creature == target() or creature == g_game.getFollowingCreature() then + if oldPos and oldPos.z == posz() then + local tile2 = g_map.getTile(oldPos) + if toggle2.isOn() and tile2:isWalkable() then + useWith(3180, tile2:getTopUseThing()) + toggle2.setOff() + end + end + end +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/z_npc_talk.lua b/modules/game_bot/default_configs/vBot/z_npc_talk.lua new file mode 100644 index 0000000..c07f112 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/z_npc_talk.lua @@ -0,0 +1,10 @@ +macro(50, function() + if not g_game.isAttacking() then return end + + if target() and target():isNpc() then + NPC.say("hi") + NPC.say("trade") + end + delay(950) + +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/z_open_doors.lua b/modules/game_bot/default_configs/vBot/z_open_doors.lua new file mode 100644 index 0000000..ea01675 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/z_open_doors.lua @@ -0,0 +1,46 @@ +-- [[ script made by Ruu ]] -- +-- [[ http://otclient.net/showthread.php?tid=358 ]] -- +-- [[ small mod, added many doors id's and diagonal walking and switch ]] -- + +local wsadWalking = modules.game_walking.wsadWalking +local doorsIds = { 5007, 8265, 1629, 1632, 5129, 6252, 6249, 7715, 7712, 7714, 7719, 6256, 1669, 1672, 5125, 5115, 5124, 17701, 17710, 1642, 6260, 5107, 4912, 6251, 5291, 1683, 1696, 1692, 5006, 2179, 5116, 11705, 30772, 30774 } + +setDefaultTab("Tools") +local m = macro(1000, "Auto open doors", function() end) + +function checkForDoors(pos) + local tile = g_map.getTile(pos) + if tile then + local useThing = tile:getTopUseThing() + if useThing and table.find(doorsIds, useThing:getId()) then + g_game.use(useThing) + end + end +end + +onKeyPress(function(keys) + if m.isOff() then return end + local pos = player:getPosition() + if keys == 'Up' or (wsadWalking and keys == 'W') then + pos.y = pos.y - 1 + elseif keys == 'Down' or (wsadWalking and keys == 'S') then + pos.y = pos.y + 1 + elseif keys == 'Left' or (wsadWalking and keys == 'A') then + pos.x = pos.x - 1 + elseif keys == 'Right' or (wsadWalking and keys == 'D') then + pos.x = pos.x + 1 + elseif wsadWalking and keys == "Q" then + pos.y = pos.y - 1 + pos.x = pos.x - 1 + elseif wsadWalking and keys == "E" then + pos.y = pos.y - 1 + pos.x = pos.x + 1 + elseif wsadWalking and keys == "Z" then + pos.y = pos.y + 1 + pos.x = pos.x - 1 + elseif wsadWalking and keys == "C" then + pos.y = pos.y + 1 + pos.x = pos.x + 1 + end + checkForDoors(pos) +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/z_quiver_manager.lua b/modules/game_bot/default_configs/vBot/z_quiver_manager.lua new file mode 100644 index 0000000..57f46a1 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/z_quiver_manager.lua @@ -0,0 +1,115 @@ +setDefaultTab("Tools") +function quiverManager() + quiverPanelName = "quiverManager" + + local ui = setupUI([[ +Panel + height: 33 + margin-top: 2 + + BotItem + id: BoltsID + anchors.left: parent.left + anchors.top: parent.top + + BotItem + id: ArrowsID + anchors.left: prev.right + anchors.verticalCenter: prev.verticalCenter + + BotSwitch + id: BoltsSwitch + anchors.top: parent.top + anchors.bottom: prev.verticalCenter + anchors.right: parent.right + text: Sort Bolts + + BotSwitch + id: ArrowsSwitch + anchors.top: prev.bottom + anchors.bottom: ArrowsID.bottom + anchors.right: parent.right + text: Sort Arrows + + ]]) + ui:setId(quiverPanelName) + + if not storage[quiverPanelName] then + storage[quiverPanelName] = { + arrowsId = 35848, + boltsId = 35849, + bolts = false, + arrows = false + } + end + + ui.BoltsSwitch:setOn(storage[quiverPanelName].bolts) + ui.BoltsSwitch.onClick = function(widget) + storage[quiverPanelName].bolts = not storage[quiverPanelName].bolts + widget:setOn(storage[quiverPanelName].bolts) + end + ui.ArrowsSwitch:setOn(storage[quiverPanelName].arrows) + ui.ArrowsSwitch.onClick = function(widget) + storage[quiverPanelName].arrows = not storage[quiverPanelName].arrows + widget:setOn(storage[quiverPanelName].arrows) + end + ui.BoltsID:setItemId(storage[quiverPanelName].boltsId) + ui.BoltsID.onItemChange = function(widget) + storage[quiverPanelName].boltsId = widget:getItemId() + end + ui.ArrowsID:setItemId(storage[quiverPanelName].arrowsId) + ui.ArrowsID.onItemChange = function(widget) + storage[quiverPanelName].arrowsId = widget:getItemId() + end + + local arrows = {16143, 763, 761, 7365, 3448, 762, 21470, 7364, 14251, 3447, 3449, 15793, 25757, 774} + local bolts = {6528, 7363, 3450, 16141, 25758, 14252, 3446, 16142} + + macro(200, function() + local dArrow + local dBolt + for _, c in pairs(getContainers()) do + if not containerIsFull(c) then + if c:getContainerItem():getId() == storage[quiverPanelName].arrowsId and storage[quiverPanelName].arrows then + dArrow = c + elseif c:getContainerItem():getId() == storage[quiverPanelName].boltsId and storage[quiverPanelName].bolts then + dBolt = c + end + end + end + + if dArrow and storage[quiverPanelName].arrows then + for _, c in pairs(getContainers()) do + if c:getName():lower():find("backpack") or c:getName():lower():find("bag") or c:getName():lower():find("chess") then + for _, i in pairs(c:getItems()) do + if table.find(arrows, i:getId()) then + return g_game.move(i, dArrow:getSlotPosition(dArrow:getItemsCount()), i:getCount()) + end + end + end + end + end + + if dBolt and storage[quiverPanelName].bolts then + for _, c in pairs(getContainers()) do + if c:getName():lower():find("backpack") or c:getName():lower():find("bag") or c:getName():lower():find("chess") then + for _, i in pairs(c:getItems()) do + if table.find(bolts, i:getId()) then + return g_game.move(i, dBolt:getSlotPosition(dBolt:getItemsCount()), i:getCount()) + end + end + end + end + end + + end) + +end + + +if voc() == 2 or voc() == 12 then +addSeparator() +UI.Label("[[ Quiver Manager ]]") +addSeparator() +quiverManager() +end \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/z_stake_knife.lua b/modules/game_bot/default_configs/vBot/z_stake_knife.lua new file mode 100644 index 0000000..217d383 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/z_stake_knife.lua @@ -0,0 +1,31 @@ +setDefaultTab("Cave") + +UI.Separator() +local knifeBodies = {4272, 4173, 4011, 4025, 4047, 4052, 4057, 4062, 4112, 4212, 4321, 4324, 4327, 10352, 10356, 10360, 10364} +local stakeBodies = {4097, 4137, 8738, 18958} +local fishingBodies = {9582} + + +macro(500,"Stake Bodies", function() + if not CaveBot.isOn() then return end + for i, tile in ipairs(g_map.getTiles(posz())) do + for u,item in ipairs(tile:getItems()) do + if table.find(knifeBodies, item:getId()) and findItem(5908) then + CaveBot.delay(550) + useWith(5908, item) + return + end + if table.find(stakeBodies, item:getId()) and findItem(5942) then + CaveBot.delay(550) + useWith(5942, item) + return + end + if table.find(fishingBodies, item:getId()) and findItem(3483) then + CaveBot.delay(550) + useWith(3483, item) + return + end + end + end + +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vBot/z_suppliesControl.lua b/modules/game_bot/default_configs/vBot/z_suppliesControl.lua new file mode 100644 index 0000000..a8c4bd8 --- /dev/null +++ b/modules/game_bot/default_configs/vBot/z_suppliesControl.lua @@ -0,0 +1,9 @@ +setDefaultTab("Cave") + +macro(500, "TargetBot off if low supply", function() + if TargetBot.isOff() then return end + if CaveBot.isOff() then return end + if not hasSupplies() then + TargetBot.setOff() + end +end) \ No newline at end of file diff --git a/otclient_dx.exe b/otclient_dx.exe index 98af80a..d1a395e 100644 Binary files a/otclient_dx.exe and b/otclient_dx.exe differ diff --git a/otclient_gl.exe b/otclient_gl.exe index e6cc8bf..2567183 100644 Binary files a/otclient_gl.exe and b/otclient_gl.exe differ diff --git a/otclientv8.apk b/otclientv8.apk index f555e46..ba81e45 100644 Binary files a/otclientv8.apk and b/otclientv8.apk differ