diff --git a/data/sounds/Creature_Detected.ogg b/data/sounds/Creature_Detected.ogg new file mode 100644 index 0000000..fd36978 Binary files /dev/null and b/data/sounds/Creature_Detected.ogg differ diff --git a/data/sounds/Low_Health.ogg b/data/sounds/Low_Health.ogg new file mode 100644 index 0000000..d4b1062 Binary files /dev/null and b/data/sounds/Low_Health.ogg differ diff --git a/data/sounds/Low_Mana.ogg b/data/sounds/Low_Mana.ogg new file mode 100644 index 0000000..e2d7e1d Binary files /dev/null and b/data/sounds/Low_Mana.ogg differ diff --git a/data/sounds/Player_Attack.ogg b/data/sounds/Player_Attack.ogg new file mode 100644 index 0000000..84e9ef4 Binary files /dev/null and b/data/sounds/Player_Attack.ogg differ diff --git a/data/sounds/Player_Detected.ogg b/data/sounds/Player_Detected.ogg new file mode 100644 index 0000000..34de63e Binary files /dev/null and b/data/sounds/Player_Detected.ogg differ diff --git a/data/sounds/Private_Message.ogg b/data/sounds/Private_Message.ogg new file mode 100644 index 0000000..f3e5984 Binary files /dev/null and b/data/sounds/Private_Message.ogg differ diff --git a/data/styles/40-container.otui b/data/styles/40-container.otui index b4afdf9..66f5da8 100644 --- a/data/styles/40-container.otui +++ b/data/styles/40-container.otui @@ -5,7 +5,8 @@ PageButton < Button ContainerWindow < MiniWindow height: 150 - + &save: true + &containerWindow: true UIItem id: containerItemWidget diff --git a/init.lua b/init.lua index b1f1bb4..ee47767 100644 --- a/init.lua +++ b/init.lua @@ -1,6 +1,6 @@ -- CONFIG APP_NAME = "otclientv8" -- important, change it, it's name for config dir and files in appdata -APP_VERSION = 1342 -- client version for updater and login to identify outdated client +APP_VERSION = 1343 -- client version for updater and login to identify outdated client DEFAULT_LAYOUT = "retro" -- on android it's forced to "mobile", check code bellow -- If you don't use updater or other service, set it to updater = "" diff --git a/modules/client_entergame/entergame.lua b/modules/client_entergame/entergame.lua index 5de6488..c46ede7 100644 --- a/modules/client_entergame/entergame.lua +++ b/modules/client_entergame/entergame.lua @@ -15,9 +15,10 @@ local serverSelector local clientVersionSelector local serverHostTextEdit local rememberPasswordBox -local protos = {"740", "760", "772", "792", "800", "810", "854", "860", "870", "961", "1000", "1077", "1090", "1096", "1098", "1099", "1100", "1200", "1220"} +local protos = {"740", "760", "772", "792", "800", "810", "854", "860", "870", "910", "961", "1000", "1077", "1090", "1096", "1098", "1099", "1100", "1200", "1220", "1230", "1240", "1250", "1252"} local checkedByUpdater = {} +local waitingForHttpResults = 0 -- private functions local function onProtocolError(protocol, message, errorCode) @@ -194,10 +195,20 @@ local function onTibia12HTTPResult(session, playdata) onCharacterList(nil, characters, account, nil) end -local function onHTTPResult(data, err) +local function onHTTPResult(data, err) + if waitingForHttpResults == 0 then + return + end + + waitingForHttpResults = waitingForHttpResults - 1 + if err and waitingForHttpResults > 0 then + return -- ignore, wait for other requests + end + if err then return EnterGame.onError(err) end + waitingForHttpResults = 0 if data['error'] and data['error']:len() > 0 then return EnterGame.onLoginError(data['error']) elseif data['errorMessage'] and data['errorMessage']:len() > 0 then @@ -396,7 +407,11 @@ function EnterGame.onServerChange() customServerSelectorPanel:setOn(false) end if Servers and Servers[server] ~= nil then - serverHostTextEdit:setText(Servers[server]) + if type(Servers[server]) == "table" then + serverHostTextEdit:setText(Servers[server][1]) + else + serverHostTextEdit:setText(Servers[server]) + end end end @@ -541,7 +556,19 @@ function EnterGame.doLoginHttp() stayloggedin = true } - HTTP.postJSON(G.host, data, onHTTPResult) + local server = serverSelector:getText() + if Servers and Servers[server] ~= nil then + if type(Servers[server]) == "table" then + local urls = Servers[server] + waitingForHttpResults = #urls + for _, url in ipairs(urls) do + HTTP.postJSON(url, data, onHTTPResult) + end + else + waitingForHttpResults = 1 + HTTP.postJSON(G.host, data, onHTTPResult) + end + end EnterGame.hide() end diff --git a/modules/client_stats/stats.lua b/modules/client_stats/stats.lua index 5cd985e..92af48a 100644 --- a/modules/client_stats/stats.lua +++ b/modules/client_stats/stats.lua @@ -11,6 +11,8 @@ local adaptiveRender = nil local slowMain = nil local slowRender = nil local widgetsInfo = nil +local packets +local slowPackets local updateEvent = nil local monitorEvent = nil @@ -36,9 +38,11 @@ function init() dispatcherStats = statsWindow:recursiveGetChildById('dispatcherStats') render = statsWindow:recursiveGetChildById('render') atlas = statsWindow:recursiveGetChildById('atlas') + packets = statsWindow:recursiveGetChildById('packets') adaptiveRender = statsWindow:recursiveGetChildById('adaptiveRender') slowMain = statsWindow:recursiveGetChildById('slowMain') slowRender = statsWindow:recursiveGetChildById('slowRender') + slowPackets = statsWindow:recursiveGetChildById('slowPackets') widgetsInfo = statsWindow:recursiveGetChildById('widgetsInfo') lastSend = os.time() @@ -177,7 +181,7 @@ function update() return end - iter = (iter + 1) % 8 -- some functions are slow (~5ms), it will avoid lags + iter = (iter + 1) % 9 -- some functions are slow (~5ms), it will avoid lags if iter == 0 then statsWindow.debugPanel.sleepTime:setText("GFPS: " .. g_app.getGraphicsFps() .. " PFPS: " .. g_app.getProcessingFps() .. " Packets: " .. g_game.getRecivedPacketsCount() .. " , " .. (g_game.getRecivedPacketsSize() / 1024) .. " KB") statsWindow.debugPanel.luaRamUsage:setText("Ram usage by lua: " .. gcinfo() .. " kb") @@ -200,6 +204,9 @@ function update() --disabled because takes a lot of cpu --widgetsInfo:setText(g_stats.getWidgetsInfo(10, true)) elseif iter == 7 then + packets:setText(g_stats.get(6, 10, true)) + slowPackets:setText(g_stats.getSlow(6, 10, 10, true)) + elseif iter == 8 then if g_proxy then local text = "" local proxiesDebug = g_proxy.getProxiesDebugInfo() diff --git a/modules/client_stats/stats.otui b/modules/client_stats/stats.otui index a347375..af1a036 100644 --- a/modules/client_stats/stats.otui +++ b/modules/client_stats/stats.otui @@ -104,6 +104,13 @@ MainWindow id: widgetsInfo text: Disabled, edit stats.lua to enable + DebugLabel + !text: tr('Packets') + + DebugText + id: packets + text: - + DebugLabel !text: tr('Slow main functions') @@ -117,6 +124,13 @@ MainWindow DebugText id: slowRender text: - + + DebugLabel + !text: tr('Slow packets') + + DebugText + id: slowPackets + text: - VerticalScrollBar id: debugScroll diff --git a/modules/corelib/ui/uiminiwindow.lua b/modules/corelib/ui/uiminiwindow.lua index d8c9639..6872dde 100644 --- a/modules/corelib/ui/uiminiwindow.lua +++ b/modules/corelib/ui/uiminiwindow.lua @@ -165,8 +165,7 @@ function UIMiniWindow:setup() self:eraseSettings({height = true}) end end - - if selfSettings.closed and not self.forceOpen then + if selfSettings.closed and not self.forceOpen and not self.containerWindow then self:close(true) end @@ -174,7 +173,7 @@ function UIMiniWindow:setup() self:lock(true) end else - if not self.forceOpen and self.autoOpen ~= nil and (self.autoOpen == 0 or self.autoOpen == false) then + if not self.forceOpen and self.autoOpen ~= nil and (self.autoOpen == 0 or self.autoOpen == false) and not self.containerWindow then self:close(true) end end @@ -185,7 +184,7 @@ function UIMiniWindow:setup() self.miniLoaded = true if self.save then - if oldParent and oldParent:getClassName() == 'UIMiniWindowContainer' then + if oldParent and oldParent:getClassName() == 'UIMiniWindowContainer' and not self.containerWindow then addEvent(function() oldParent:order() end) end if newParent and newParent:getClassName() == 'UIMiniWindowContainer' and newParent ~= oldParent then @@ -350,6 +349,20 @@ function UIMiniWindow:eraseSettings(data) g_settings.setNode('MiniWindows', settings) end +function UIMiniWindow:clearSettings() + if not self.save then return end + + local settings = g_settings.getNode('MiniWindows') + if not settings then + settings = {} + end + + local id = self:getId() + settings[id] = {} + + g_settings.setNode('MiniWindows', settings) +end + function UIMiniWindow:saveParent(parent) local parent = self:getParent() if parent then diff --git a/modules/corelib/ui/uiminiwindowcontainer.lua b/modules/corelib/ui/uiminiwindowcontainer.lua index f9e4c00..514ed05 100644 --- a/modules/corelib/ui/uiminiwindowcontainer.lua +++ b/modules/corelib/ui/uiminiwindowcontainer.lua @@ -168,7 +168,15 @@ function UIMiniWindowContainer:scheduleInsert(widget, index) local placed = false for nIndex,nWidget in pairs(self.scheduledWidgets) do if nIndex - 1 <= self:getChildCount() then - self:insertChild(nIndex, nWidget) + local oldParent = nWidget:getParent() + if oldParent ~= self then + if oldParent then + oldParent:removeChild(nWidget) + end + self:insertChild(nIndex, nWidget) + else + self:moveChildToIndex(nWidget, nIndex) + end self.scheduledWidgets[nIndex] = nil placed = true break @@ -176,7 +184,6 @@ function UIMiniWindowContainer:scheduleInsert(widget, index) end if not placed then break end end - end end end diff --git a/modules/game_bot/bot.lua b/modules/game_bot/bot.lua index 3809080..d64b604 100644 --- a/modules/game_bot/bot.lua +++ b/modules/game_bot/bot.lua @@ -285,30 +285,30 @@ function createDefaultConfigs() if not g_resources.directoryExists("/bot/" .. config_name) then return onError("Can't create /bot/" .. config_name .. " directory in " .. g_resources.getWriteDir()) end - end - local defaultConfigFiles = g_resources.listDirectoryFiles("default_configs/" .. config_name, true, false) - for i, file in ipairs(defaultConfigFiles) do - local baseName = file:split("/") - baseName = baseName[#baseName] - if g_resources.directoryExists(file) then - g_resources.makeDir("/bot/" .. config_name .. "/" .. baseName) - if not g_resources.directoryExists("/bot/" .. config_name .. "/" .. baseName) then - return onError("Can't create /bot/" .. config_name .. "/" .. baseName .. " directory in " .. g_resources.getWriteDir()) - end - local defaultConfigFiles2 = g_resources.listDirectoryFiles("default_configs/" .. config_name .. "/" .. baseName, true, false) - for i, file in ipairs(defaultConfigFiles2) do - local baseName2 = file:split("/") - baseName2 = baseName2[#baseName2] + local defaultConfigFiles = g_resources.listDirectoryFiles("default_configs/" .. config_name, true, false) + for i, file in ipairs(defaultConfigFiles) do + local baseName = file:split("/") + baseName = baseName[#baseName] + if g_resources.directoryExists(file) then + g_resources.makeDir("/bot/" .. config_name .. "/" .. baseName) + if not g_resources.directoryExists("/bot/" .. config_name .. "/" .. baseName) then + return onError("Can't create /bot/" .. config_name .. "/" .. baseName .. " directory in " .. g_resources.getWriteDir()) + end + local defaultConfigFiles2 = g_resources.listDirectoryFiles("default_configs/" .. config_name .. "/" .. baseName, true, false) + for i, file in ipairs(defaultConfigFiles2) do + local baseName2 = file:split("/") + baseName2 = baseName2[#baseName2] + local contents = g_resources.fileExists(file) and g_resources.readFileContents(file) or "" + if contents:len() > 0 then + g_resources.writeFileContents("/bot/" .. config_name .. "/" .. baseName .. "/" .. baseName2, contents) + end + end + else local contents = g_resources.fileExists(file) and g_resources.readFileContents(file) or "" if contents:len() > 0 then - g_resources.writeFileContents("/bot/" .. config_name .. "/" .. baseName .. "/" .. baseName2, contents) - end - end - else - local contents = g_resources.fileExists(file) and g_resources.readFileContents(file) or "" - if contents:len() > 0 then - g_resources.writeFileContents("/bot/" .. config_name .. "/" .. baseName, contents) + g_resources.writeFileContents("/bot/" .. config_name .. "/" .. baseName, contents) + end end end end @@ -321,8 +321,8 @@ function uploadConfig() if not archive then return displayErrorBox(tr("Config upload failed"), tr("Config %s is invalid (can't be compressed)", config)) end - if archive:len() > 64 * 1024 then - return displayErrorBox(tr("Config upload failed"), tr("Config %s is too big, maximum size is 64KB. Now it has %s KB.", config, math.floor(archive / 1024))) + if archive:len() > 1024 * 1024 then + return displayErrorBox(tr("Config upload failed"), tr("Config %s is too big, maximum size is 1024KB. Now it has %s KB.", config, math.floor(archive:len() / 1024))) end local infoBox = displayInfoBox(tr("Uploading config"), tr("Uploading config %s. Please wait.", config)) @@ -468,6 +468,7 @@ function initCallbacks() connect(g_game, { onTalk = botOnTalk, onTextMessage = botOnTextMessage, + onLoginAdvice = botOnLoginAdvice, onUse = botOnUse, onUseWith = botOnUseWith, onChannelList = botChannelList, @@ -486,12 +487,15 @@ function initCallbacks() onDisappear = botCreatureDisappear, onPositionChange = botCreaturePositionChange, onHealthPercentChange = botCraetureHealthPercentChange, - onTurn = botCreatureTurn - }) + onTurn = botCreatureTurn, + onWalk = botCreatureWalk, + }) connect(LocalPlayer, { onPositionChange = botCreaturePositionChange, - onHealthPercentChange = botCraetureHealthPercentChange + onHealthPercentChange = botCraetureHealthPercentChange, + onTurn = botCreatureTurn, + onWalk = botCreatureWalk, }) connect(Container, { @@ -517,6 +521,7 @@ function terminateCallbacks() disconnect(g_game, { onTalk = botOnTalk, onTextMessage = botOnTextMessage, + onLoginAdvice = botOnLoginAdvice, onUse = botOnUse, onUseWith = botOnUseWith, onChannelList = botChannelList, @@ -535,12 +540,15 @@ function terminateCallbacks() onDisappear = botCreatureDisappear, onPositionChange = botCreaturePositionChange, onHealthPercentChange = botCraetureHealthPercentChange, - onTurn = botCreatureTurn + onTurn = botCreatureTurn, + onWalk = botCreatureWalk, }) disconnect(LocalPlayer, { onPositionChange = botCreaturePositionChange, - onHealthPercentChange = botCraetureHealthPercentChange + onHealthPercentChange = botCraetureHealthPercentChange, + onTurn = botCreatureTurn, + onWalk = botCreatureWalk, }) disconnect(Container, { @@ -591,6 +599,11 @@ function botOnTextMessage(mode, text) safeBotCall(function() botExecutor.callbacks.onTextMessage(mode, text) end) end +function botOnLoginAdvice(message) + if botExecutor == nil then return false end + safeBotCall(function() botExecutor.callbacks.onLoginAdvice(message) end) +end + function botAddThing(tile, thing) if botExecutor == nil then return false end safeBotCall(function() botExecutor.callbacks.onAddThing(tile, thing) end) @@ -684,4 +697,9 @@ end function botCreatureTurn(creature, direction) if botExecutor == nil then return false end safeBotCall(function() botExecutor.callbacks.onTurn(creature, direction) end) +end + +function botCreatureWalk(creature, oldPos, newPos) + if botExecutor == nil then return false end + safeBotCall(function() botExecutor.callbacks.onWalk(creature, oldPos, newPos) end) end \ No newline at end of file diff --git a/modules/game_bot/default_configs/cavebot_1.2/cavebot.lua b/modules/game_bot/default_configs/cavebot_1.3/cavebot.lua similarity index 92% rename from modules/game_bot/default_configs/cavebot_1.2/cavebot.lua rename to modules/game_bot/default_configs/cavebot_1.3/cavebot.lua index c395ef4..a325693 100644 --- a/modules/game_bot/default_configs/cavebot_1.2/cavebot.lua +++ b/modules/game_bot/default_configs/cavebot_1.3/cavebot.lua @@ -8,12 +8,15 @@ 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/depositer.lua") diff --git a/modules/game_bot/default_configs/cavebot_1.2/cavebot/actions.lua b/modules/game_bot/default_configs/cavebot_1.3/cavebot/actions.lua similarity index 87% rename from modules/game_bot/default_configs/cavebot_1.2/cavebot/actions.lua rename to modules/game_bot/default_configs/cavebot_1.3/cavebot/actions.lua index ae42fa3..64d7288 100644 --- a/modules/game_bot/default_configs/cavebot_1.2/cavebot/actions.lua +++ b/modules/game_bot/default_configs/cavebot_1.3/cavebot/actions.lua @@ -107,16 +107,23 @@ CaveBot.registerAction("function", "red", function(value, retries, prev) end) CaveBot.registerAction("goto", "green", function(value, retries, prev) - local pos = regexMatch(value, "\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)") + local pos = regexMatch(value, "\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+),?\\s*([0-9]?)") if not pos[1] then error("Invalid cavebot goto action value. It should be position (x,y,z), is: " .. value) return false end - if retries >= 5 then - return false -- tried 5 times, can't get there + 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 @@ -134,7 +141,7 @@ CaveBot.registerAction("goto", "green", function(value, retries, prev) 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) <= 1 then + 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 @@ -142,17 +149,14 @@ CaveBot.registerAction("goto", "green", function(value, retries, prev) if not path then return false -- there's no way end - - -- walk will be executed, but it will take some time to get response from server, wait 300ms after autowalk - CaveBot.delay(300) - + -- try to find path, don't ignore creatures, don't ignore fields - if autoWalk(pos, 40) then + 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 autoWalk(pos, 40, { ignoreNonPathable = true }) then + if CaveBot.walkTo(pos, 40, { ignoreNonPathable = true }) then return "retry" end @@ -162,12 +166,21 @@ CaveBot.registerAction("goto", "green", function(value, retries, prev) if stairs then precison = 0 end - if autoWalk(pos, 50, { ignoreNonPathable = true, precision = precison }) then + if CaveBot.walkTo(pos, 50, { ignoreNonPathable = true, precision = precison }) then return "retry" end end - autoWalk(path) -- everything else failed, try to walk ignoring creatures, maybe will work + 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) @@ -204,7 +217,7 @@ CaveBot.registerAction("use", "#FFB272", function(value, retries, prev) end use(topThing) - CaveBot.delay(400) + CaveBot.delay(CaveBot.Config.get("useDelay") + CaveBot.Config.get("ping")) return true end) @@ -241,11 +254,11 @@ CaveBot.registerAction("usewith", "#EEB292", function(value, retries, prev) end usewith(itemid, topThing) - CaveBot.delay(400) + 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) \ No newline at end of file +end) diff --git a/modules/game_bot/default_configs/cavebot_1.2/cavebot/cavebot.lua b/modules/game_bot/default_configs/cavebot_1.3/cavebot/cavebot.lua similarity index 82% rename from modules/game_bot/default_configs/cavebot_1.2/cavebot/cavebot.lua rename to modules/game_bot/default_configs/cavebot_1.3/cavebot/cavebot.lua index 910776a..a00ee71 100644 --- a/modules/game_bot/default_configs/cavebot_1.2/cavebot/cavebot.lua +++ b/modules/game_bot/default_configs/cavebot_1.3/cavebot/cavebot.lua @@ -11,6 +11,9 @@ 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() @@ -22,9 +25,14 @@ 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() @@ -36,6 +44,7 @@ cavebotMacro = macro(20, function() local retry = false if action then local status, result = pcall(function() + CaveBot.resetWalking() return action.callback(value, actionRetries, prevActionResult) end) if status then @@ -72,11 +81,6 @@ cavebotMacro = macro(20, function() ui.list:focusChild(ui.list:getChildByIndex(nextAction)) end) -onPlayerPositionChange(function() - local delayAfterPositionChange = math.max(player:getStepDuration() + 100, 200) - cavebotMacro.delay = math.max(cavebotMacro.delay or 0, now + delayAfterPositionChange) -end) - -- config, its callback is called immediately, data can be nil local lastConfig = "" config = Config.setup("cavebot_configs", configWidget, "cfg", function(name, enabled, data) @@ -90,9 +94,19 @@ config = Config.setup("cavebot_configs", configWidget, "cfg", function(name, ena 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] == "extensions" then + if v[1] == "config" then + local status, result = pcall(function() + return json.decode(v[2]) + end) + if not status then + error("Error while parsing CaveBot extensions from config:\n" .. result) + else + cavebotConfig = result + end + elseif v[1] == "extensions" then local status, result = pcall(function() return json.decode(v[2]) end) @@ -110,8 +124,11 @@ config = Config.setup("cavebot_configs", configWidget, "cfg", function(name, ena end end end + + CaveBot.Config.onConfigChange(name, enabled, cavebotConfig) actionRetries = 0 + CaveBot.resetWalking() prevActionResult = true cavebotMacro.setOn(enabled) cavebotMacro.delay = nil @@ -134,6 +151,16 @@ ui.showEditor.onClick = function() 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() @@ -159,7 +186,7 @@ CaveBot.setOff = function(val) end CaveBot.delay = function(value) - cavebotMacro.delay = now + value + cavebotMacro.delay = math.max(cavebotMacro.delay or 0, now + value) end CaveBot.gotoLabel = function(label) @@ -178,6 +205,11 @@ CaveBot.save = function() 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 diff --git a/modules/game_bot/default_configs/cavebot_1.2/cavebot/cavebot.otui b/modules/game_bot/default_configs/cavebot_1.3/cavebot/cavebot.otui similarity index 86% rename from modules/game_bot/default_configs/cavebot_1.2/cavebot/cavebot.otui rename to modules/game_bot/default_configs/cavebot_1.3/cavebot/cavebot.otui index 12e54d4..b92ed05 100644 --- a/modules/game_bot/default_configs/cavebot_1.2/cavebot/cavebot.otui +++ b/modules/game_bot/default_configs/cavebot_1.3/cavebot/cavebot.otui @@ -46,3 +46,13 @@ CaveBotPanel < Panel $!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/cavebot_1.3/cavebot/config.lua b/modules/game_bot/default_configs/cavebot_1.3/cavebot/config.lua new file mode 100644 index 0000000..549f663 --- /dev/null +++ b/modules/game_bot/default_configs/cavebot_1.3/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 error("Duplicated config key: " .. id) + end + + local panel + local setter -- sets value + if type(defaultValue) == "number" then + panel = UI.createWidget("CaveBotConfigNumberValuePanel", CaveBot.Config.ui) + setter = function(value) + CaveBot.Config.values[id] = value + panel.value:setText(value, true) + end + setter(defaultValue) + panel.value.onTextChange = function(widget, newValue) + newValue = tonumber(newValue) + if newValue then + CaveBot.Config.values[id] = newValue + CaveBot.save() + end + end + elseif type(defaultValue) == "boolean" then + panel = UI.createWidget("CaveBotConfigBooleanValuePanel", CaveBot.Config.ui) + setter = function(value) + CaveBot.Config.values[id] = value + panel.value:setOn(value, true) + end + setter(defaultValue) + panel.value.onClick = function(widget) + widget:setOn(not widget:isOn()) + CaveBot.Config.values[id] = widget:isOn() + CaveBot.save() + end + else + return error("Invalid default value of config for key " .. id .. ", should be number or boolean") + end + + panel.title:setText(tr(title) .. ":") + + CaveBot.Config.value_setters[id] = setter + CaveBot.Config.values[id] = defaultValue + CaveBot.Config.default_values[id] = defaultValue +end + +CaveBot.Config.get = function(id) + if CaveBot.Config.values[id] == nil then + return error("Invalid CaveBot.Config.get, id: " .. id) + end + return CaveBot.Config.values[id] +end \ No newline at end of file diff --git a/modules/game_bot/default_configs/cavebot_1.3/cavebot/config.otui b/modules/game_bot/default_configs/cavebot_1.3/cavebot/config.otui new file mode 100644 index 0000000..21d479d --- /dev/null +++ b/modules/game_bot/default_configs/cavebot_1.3/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/cavebot_1.2/cavebot/depositer.lua b/modules/game_bot/default_configs/cavebot_1.3/cavebot/depositer.lua similarity index 100% rename from modules/game_bot/default_configs/cavebot_1.2/cavebot/depositer.lua rename to modules/game_bot/default_configs/cavebot_1.3/cavebot/depositer.lua diff --git a/modules/game_bot/default_configs/cavebot_1.2/cavebot/editor.lua b/modules/game_bot/default_configs/cavebot_1.3/cavebot/editor.lua similarity index 98% rename from modules/game_bot/default_configs/cavebot_1.2/cavebot/editor.lua rename to modules/game_bot/default_configs/cavebot_1.3/cavebot/editor.lua index 1fb4e76..48f7925 100644 --- a/modules/game_bot/default_configs/cavebot_1.2/cavebot/editor.lua +++ b/modules/game_bot/default_configs/cavebot_1.3/cavebot/editor.lua @@ -104,7 +104,7 @@ CaveBot.Editor.setup = function() 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]+)$" + validation="^\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+),?\\s*([0-9]?)$" }) registerAction("use", { value=function() return posx() .. "," .. posy() .. "," .. posz() end, diff --git a/modules/game_bot/default_configs/cavebot_1.2/cavebot/editor.otui b/modules/game_bot/default_configs/cavebot_1.3/cavebot/editor.otui similarity index 100% rename from modules/game_bot/default_configs/cavebot_1.2/cavebot/editor.otui rename to modules/game_bot/default_configs/cavebot_1.3/cavebot/editor.otui diff --git a/modules/game_bot/default_configs/cavebot_1.2/cavebot/example_functions.lua b/modules/game_bot/default_configs/cavebot_1.3/cavebot/example_functions.lua similarity index 80% rename from modules/game_bot/default_configs/cavebot_1.2/cavebot/example_functions.lua rename to modules/game_bot/default_configs/cavebot_1.3/cavebot/example_functions.lua index 2e5b0fb..556129c 100644 --- a/modules/game_bot/default_configs/cavebot_1.2/cavebot/example_functions.lua +++ b/modules/game_bot/default_configs/cavebot_1.3/cavebot/example_functions.lua @@ -63,3 +63,28 @@ 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/cavebot_1.2/cavebot/extension_template.lua b/modules/game_bot/default_configs/cavebot_1.3/cavebot/extension_template.lua similarity index 100% rename from modules/game_bot/default_configs/cavebot_1.2/cavebot/extension_template.lua rename to modules/game_bot/default_configs/cavebot_1.3/cavebot/extension_template.lua diff --git a/modules/game_bot/default_configs/cavebot_1.2/cavebot/recorder.lua b/modules/game_bot/default_configs/cavebot_1.3/cavebot/recorder.lua similarity index 100% rename from modules/game_bot/default_configs/cavebot_1.2/cavebot/recorder.lua rename to modules/game_bot/default_configs/cavebot_1.3/cavebot/recorder.lua diff --git a/modules/game_bot/default_configs/cavebot_1.2/cavebot/supply.lua b/modules/game_bot/default_configs/cavebot_1.3/cavebot/supply.lua similarity index 100% rename from modules/game_bot/default_configs/cavebot_1.2/cavebot/supply.lua rename to modules/game_bot/default_configs/cavebot_1.3/cavebot/supply.lua diff --git a/modules/game_bot/default_configs/cavebot_1.2/cavebot/supply.otui b/modules/game_bot/default_configs/cavebot_1.3/cavebot/supply.otui similarity index 100% rename from modules/game_bot/default_configs/cavebot_1.2/cavebot/supply.otui rename to modules/game_bot/default_configs/cavebot_1.3/cavebot/supply.otui diff --git a/modules/game_bot/default_configs/cavebot_1.3/cavebot/walking.lua b/modules/game_bot/default_configs/cavebot_1.3/cavebot/walking.lua new file mode 100644 index 0000000..c8a7133 --- /dev/null +++ b/modules/game_bot/default_configs/cavebot_1.3/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/cavebot_1.2/hp.lua b/modules/game_bot/default_configs/cavebot_1.3/hp.lua similarity index 100% rename from modules/game_bot/default_configs/cavebot_1.2/hp.lua rename to modules/game_bot/default_configs/cavebot_1.3/hp.lua diff --git a/modules/game_bot/default_configs/cavebot_1.2/main.lua b/modules/game_bot/default_configs/cavebot_1.3/main.lua similarity index 95% rename from modules/game_bot/default_configs/cavebot_1.2/main.lua rename to modules/game_bot/default_configs/cavebot_1.3/main.lua index 5b21125..57b7ca6 100644 --- a/modules/game_bot/default_configs/cavebot_1.2/main.lua +++ b/modules/game_bot/default_configs/cavebot_1.3/main.lua @@ -1,5 +1,5 @@ -- main tab -VERSION = "1.2" +VERSION = "1.3" UI.Label("Config version: " .. VERSION) diff --git a/modules/game_bot/default_configs/cavebot_1.2/mwall_timer.lua b/modules/game_bot/default_configs/cavebot_1.3/mwall_timer.lua similarity index 100% rename from modules/game_bot/default_configs/cavebot_1.2/mwall_timer.lua rename to modules/game_bot/default_configs/cavebot_1.3/mwall_timer.lua diff --git a/modules/game_bot/default_configs/cavebot_1.2/targetbot/creature.lua b/modules/game_bot/default_configs/cavebot_1.3/targetbot/creature.lua similarity index 90% rename from modules/game_bot/default_configs/cavebot_1.2/targetbot/creature.lua rename to modules/game_bot/default_configs/cavebot_1.3/targetbot/creature.lua index 84a8836..d4dd545 100644 --- a/modules/game_bot/default_configs/cavebot_1.2/targetbot/creature.lua +++ b/modules/game_bot/default_configs/cavebot_1.3/targetbot/creature.lua @@ -20,7 +20,13 @@ TargetBot.Creature.addConfig = function(config, focus) TargetBot.Creature.resetConfigsCache() if not config.regex then - config.regex = "^" .. config.name:trim():lower():gsub("%*", ".*"):gsub("%?", ".?") .. "$" + 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) diff --git a/modules/game_bot/default_configs/cavebot_1.2/targetbot/creature_attack.lua b/modules/game_bot/default_configs/cavebot_1.3/targetbot/creature_attack.lua similarity index 90% rename from modules/game_bot/default_configs/cavebot_1.2/targetbot/creature_attack.lua rename to modules/game_bot/default_configs/cavebot_1.3/targetbot/creature_attack.lua index 6d6a8f2..048c07c 100644 --- a/modules/game_bot/default_configs/cavebot_1.2/targetbot/creature_attack.lua +++ b/modules/game_bot/default_configs/cavebot_1.3/targetbot/creature_attack.lua @@ -67,8 +67,18 @@ 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 + -- luring - if (config.lure or config.lureCavebot) and not (config.chase and creature:getHealthPercent() < 30) then + if TargetBot.canLure() and (config.lure or config.lureCavebot) and not (config.chase and creature:getHealthPercent() < 30) and not isTrapped then local monsters = 0 if targets < config.lureCount then if config.lureCavebot then diff --git a/modules/game_bot/default_configs/cavebot_1.2/targetbot/creature_editor.lua b/modules/game_bot/default_configs/cavebot_1.3/targetbot/creature_editor.lua similarity index 90% rename from modules/game_bot/default_configs/cavebot_1.2/targetbot/creature_editor.lua rename to modules/game_bot/default_configs/cavebot_1.3/targetbot/creature_editor.lua index 2931c2e..8d92db0 100644 --- a/modules/game_bot/default_configs/cavebot_1.2/targetbot/creature_editor.lua +++ b/modules/game_bot/default_configs/cavebot_1.3/targetbot/creature_editor.lua @@ -8,7 +8,7 @@ TargetBot.Creature.edit = function(config, callback) -- callback = function(newC table.insert(values, {"name", function() return editor.name:getText() end}) local addScrollBar = function(id, title, min, max, defaultValue) - local widget = UI.createWidget('TargetBotCreatureEditorScrollBar', editor.left) + local widget = UI.createWidget('TargetBotCreatureEditorScrollBar', editor.content.left) widget.scroll.onValueChange = function(scroll, value) widget.text:setText(title .. ": " .. value) end @@ -24,14 +24,14 @@ TargetBot.Creature.edit = function(config, callback) -- callback = function(newC end local addTextEdit = function(id, title, defaultValue) - local widget = UI.createWidget('TargetBotCreatureEditorTextEdit', editor.right) + 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.right) + local widget = UI.createWidget('TargetBotCreatureEditorCheckBox', editor.content.right) widget.onClick = function() widget:setOn(not widget:isOn()) end @@ -45,7 +45,7 @@ TargetBot.Creature.edit = function(config, callback) -- callback = function(newC end local addItem = function(id, title, defaultItem) - local widget = UI.createWidget('TargetBotCreatureEditorItem', editor.right) + 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}) @@ -62,7 +62,14 @@ TargetBot.Creature.edit = function(config, callback) -- callback = function(newC newConfig[value[1]] = value[2]() end if newConfig.name:len() < 1 then return end - newConfig.regex = "^" .. newConfig.name:trim():lower():gsub("%*", ".*"):gsub("%?", ".?") .. "$" + + 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) @@ -88,6 +95,7 @@ TargetBot.Creature.edit = function(config, callback) -- callback = function(newC 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("avoidAttacks", "Avoid wave attacks", false) diff --git a/modules/game_bot/default_configs/cavebot_1.2/targetbot/creature_editor.otui b/modules/game_bot/default_configs/cavebot_1.3/targetbot/creature_editor.otui similarity index 65% rename from modules/game_bot/default_configs/cavebot_1.2/targetbot/creature_editor.otui rename to modules/game_bot/default_configs/cavebot_1.3/targetbot/creature_editor.otui index 59b9cc6..24f3da6 100644 --- a/modules/game_bot/default_configs/cavebot_1.2/targetbot/creature_editor.otui +++ b/modules/game_bot/default_configs/cavebot_1.3/targetbot/creature_editor.otui @@ -64,14 +64,24 @@ TargetBotCreatureEditorCheckBox < BotSwitch TargetBotCreatureEditorWindow < MainWindow text: TargetBot creature editor width: 500 - height: 600 + height: 630 + + $mobile: + height: 300 Label anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top text-align: center - text: You can use * (any characters) and ? (any character) in target name + !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 @@ -86,29 +96,49 @@ TargetBotCreatureEditorWindow < MainWindow anchors.left: parent.left text: Target name: - Panel - id: left + 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.horizontalCenter - margin-top: 5 - margin-left: 10 - margin-right: 10 - layout: - type: verticalBox - fit-children: true - - Panel - id: right - anchors.top: name.bottom - anchors.left: parent.horizontalCenter anchors.right: parent.right - margin-top: 5 - margin-left: 10 - margin-right: 10 - layout: - type: verticalBox - fit-children: true + 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 diff --git a/modules/game_bot/default_configs/cavebot_1.2/targetbot/creature_priority.lua b/modules/game_bot/default_configs/cavebot_1.3/targetbot/creature_priority.lua similarity index 100% rename from modules/game_bot/default_configs/cavebot_1.2/targetbot/creature_priority.lua rename to modules/game_bot/default_configs/cavebot_1.3/targetbot/creature_priority.lua diff --git a/modules/game_bot/default_configs/cavebot_1.2/targetbot/looting.lua b/modules/game_bot/default_configs/cavebot_1.3/targetbot/looting.lua similarity index 98% rename from modules/game_bot/default_configs/cavebot_1.2/targetbot/looting.lua rename to modules/game_bot/default_configs/cavebot_1.3/targetbot/looting.lua index c1d687e..451450f 100644 --- a/modules/game_bot/default_configs/cavebot_1.2/targetbot/looting.lua +++ b/modules/game_bot/default_configs/cavebot_1.3/targetbot/looting.lua @@ -277,6 +277,10 @@ end) onCreatureDisappear(function(creature) 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() diff --git a/modules/game_bot/default_configs/cavebot_1.2/targetbot/looting.otui b/modules/game_bot/default_configs/cavebot_1.3/targetbot/looting.otui similarity index 100% rename from modules/game_bot/default_configs/cavebot_1.2/targetbot/looting.otui rename to modules/game_bot/default_configs/cavebot_1.3/targetbot/looting.otui diff --git a/modules/game_bot/default_configs/cavebot_1.2/targetbot/target.lua b/modules/game_bot/default_configs/cavebot_1.3/targetbot/target.lua similarity index 95% rename from modules/game_bot/default_configs/cavebot_1.2/targetbot/target.lua rename to modules/game_bot/default_configs/cavebot_1.3/targetbot/target.lua index c8e8516..adcd20e 100644 --- a/modules/game_bot/default_configs/cavebot_1.2/targetbot/target.lua +++ b/modules/game_bot/default_configs/cavebot_1.3/targetbot/target.lua @@ -2,6 +2,7 @@ local targetbotMacro = nil local config = nil local lastAction = 0 local cavebotAllowance = 0 +local lureEnabled = true -- ui local configWidget = UI.Config() @@ -77,6 +78,9 @@ targetbotMacro = macro(100, function() TargetBot.setStatus("Luring using CaveBot") else TargetBot.setStatus("Attacking") + if not lureEnabled then + TargetBot.setStatus("Attacking (luring off)") + end end TargetBot.walk() lastAction = now @@ -117,6 +121,7 @@ config = Config.setup("targetbot_configs", configWidget, "json", function(name, targetbotMacro.setOn(enabled) targetbotMacro.delay = nil + lureEnabled = true end) -- setup ui @@ -198,6 +203,15 @@ TargetBot.allowCaveBot = function(time) cavebotAllowance = now + time end +TargetBot.disableLuring = function() + lureEnabled = false +end + +TargetBot.enableLuring = function() + lureEnabled = true +end + + -- attacks local lastSpell = 0 local lastAttackSpell = 0 @@ -265,3 +279,7 @@ TargetBot.useAttackItem = function(item, subType, target, delay) lastRuneAttack = now end end + +TargetBot.canLure = function() + return lureEnabled +end \ No newline at end of file diff --git a/modules/game_bot/default_configs/cavebot_1.2/targetbot/target.otui b/modules/game_bot/default_configs/cavebot_1.3/targetbot/target.otui similarity index 100% rename from modules/game_bot/default_configs/cavebot_1.2/targetbot/target.otui rename to modules/game_bot/default_configs/cavebot_1.3/targetbot/target.otui diff --git a/modules/game_bot/default_configs/cavebot_1.2/targetbot/walking.lua b/modules/game_bot/default_configs/cavebot_1.3/targetbot/walking.lua similarity index 100% rename from modules/game_bot/default_configs/cavebot_1.2/targetbot/walking.lua rename to modules/game_bot/default_configs/cavebot_1.3/targetbot/walking.lua diff --git a/modules/game_bot/default_configs/cavebot_1.2/tools.lua b/modules/game_bot/default_configs/cavebot_1.3/tools.lua similarity index 100% rename from modules/game_bot/default_configs/cavebot_1.2/tools.lua rename to modules/game_bot/default_configs/cavebot_1.3/tools.lua diff --git a/modules/game_bot/default_configs/vithrax_1.1/# Conditions.lua b/modules/game_bot/default_configs/vithrax_1.1/# Conditions.lua new file mode 100644 index 0000000..8e357f7 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/# Conditions.lua @@ -0,0 +1,235 @@ +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 + } + 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 + + -- 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) 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/vithrax_1.1/# tools.lua b/modules/game_bot/default_configs/vithrax_1.1/# tools.lua new file mode 100644 index 0000000..5f7524e --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/# 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/vithrax_1.1/#cavebot.lua b/modules/game_bot/default_configs/vithrax_1.1/#cavebot.lua new file mode 100644 index 0000000..ea77134 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/#cavebot.lua @@ -0,0 +1,53 @@ +-- 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") +-- 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/vithrax_1.1/#main.lua b/modules/game_bot/default_configs/vithrax_1.1/#main.lua new file mode 100644 index 0000000..9c0b26f --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/#main.lua @@ -0,0 +1,7 @@ +-- main tab +UI.Label("Vithrax CFG v1.1 \n \n Scripting service: \n Vithrax#5814") + +UI.Separator() + + + diff --git a/modules/game_bot/default_configs/vithrax_1.1/#vlib.lua b/modules/game_bot/default_configs/vithrax_1.1/#vlib.lua new file mode 100644 index 0000000..873882e --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/#vlib.lua @@ -0,0 +1,874 @@ +-- lib ver 1.4 +-- Author: Vithrax +-- contains mostly basic function shortcuts and code shorteners + +function isBuffed() + if (4*(player:getSkillLevel(2) - player:getSkillBaseLevel(2))) < player:getSkillLevel(2) then + return false + else + return true + end +end + +function killsToRs() + return math.min(g_game.getUnjustifiedPoints().killsDayRemaining, g_game.getUnjustifiedPoints().killsWeekRemaining, g_game.getUnjustifiedPoints().killsMonthRemaining) +end + +function canCast(spell) + if not spell then return end + if not getSpellData(spell) then return true end + + if not getSpellCoolDown(spell) and mana() >= getSpellData(spell).manaCost and level() >= getSpellData(spell).level then + return true + else + return false + end +end + +function getSpellData(spell) + if not spell then return false end + if Spells[spell] then + return Spells[spell] + else + return false + end +end + +Spells = { + ["adana ani"] = {level = 54, manaCost = 1400}, + ["adana mort"] = {level = 27, manaCost = 600}, + ["adana pox"] = {level = 15, manaCost = 200}, + ["adeta sio"] = {level = 16, manaCost = 200}, + ["adevo grav flam"] = {level = 15, manaCost = 240}, + ["adevo grav pox"] = {level = 14, manaCost = 200}, + ["adevo grav tera"] = {level = 32, manaCost = 750}, + ["adevo grav vis"] = {level = 18, manaCost = 320}, + ["adevo grav vita"] = {level = 27, manaCost = 600}, + ["adevo ina"] = {level = 27, manaCost = 600}, + ["adevo mas flam"] = {level = 27, manaCost = 600}, + ["adevo mas grav flam"] = {level = 33, manaCost = 780}, + ["adevo mas grav pox"] = {level = 29, manaCost = 640}, + ["adevo mas grav vis"] = {level = 41, manaCost = 1000}, + ["adevo mas hur"] = {level = 31, manaCost = 570}, + ["adevo mas pox"] = {level = 25, manaCost = 520}, + ["adevo mas vis"] = {level = 37, manaCost = 880}, + ["adevo res flam"] = {level = 27, manaCost = 420}, + ["adito grav"] = {level = 17, manaCost = 120}, + ["adito tera"] = {level = 21, manaCost = 200}, + ["adori dis min vis"] = {level = 1, manaCost = 5}, + ["adori flam"] = {level = 27, manaCost = 460}, + ["adori frigo"] = {level = 28, manaCost = 460}, + ["adori gran mort"] = {level = 45, manaCost = 985}, + ["adori mas flam"] = {level = 30, manaCost = 530}, + ["adori mas frigo"] = {level = 30, manaCost = 530}, + ["adori mas tera"] = {level = 28, manaCost = 430}, + ["adori mas vis"] = {level = 28, manaCost = 430}, + ["adori min vis"] = {level = 15, manaCost = 120}, + ["adori san"] = {level = 27, manaCost = 300}, + ["adori tera"] = {level = 24, manaCost = 350}, + ["adori vis"] = {level = 25, manaCost = 350}, + ["adura gran"] = {level = 15, manaCost = 120}, + ["adura vita"] = {level = 24, manaCost = 400}, + ["exana flam"] = {level = 30, manaCost = 30}, + ["exana ina"] = {level = 26, manaCost = 200}, + ["exana kor"] = {level = 45, manaCost = 30}, + ["exana mort"] = {level = 80, manaCost = 40}, + ["exana pox"] = {level = 10, manaCost = 30}, + ["exana vis"] = {level = 22, manaCost = 30}, + ["exani tera"] = {level = 9, manaCost = 20}, + ["exeta con"] = {level = 45, manaCost = 350}, + ["exeta res"] = {level = 20, manaCost = 40}, + ["exevo con"] = {level = 13, manaCost = 100}, + ["exevo con flam"] = {level = 25, manaCost = 290}, + ["exevo dis flam hur"] = {level = 1, manaCost = 5}, + ["exevo flam hur"] = {level = 18, manaCost = 25}, + ["exevo frigo hur"] = {level = 18, manaCost = 25}, + ["exevo gran con hur"] = {level = 150, manaCost = 1000}, + ["exevo gran con vis"] = {level = 150, manaCost = 1000}, + ["exevo gran frigo hur"] = {level = 40, manaCost = 170}, + ["exevo gran mas flam"] = {level = 60, manaCost = 1100}, + ["exevo gran mas frigo"] = {level = 60, manaCost = 1050}, + ["exevo gran mas tera"] = {level = 55, manaCost = 700}, + ["exevo gran mas vis"] = {level = 55, manaCost = 600}, + ["exevo gran mort"] = {level = 41, manaCost = 250}, + ["exevo gran vis lux"] = {level = 29, manaCost = 110}, + ["exevo infir con"] = {level = 1, manaCost = 10}, + ["exevo infir flam hur"] = {level = 1, manaCost = 8}, + ["exevo infir frigo hur"] = {level = 1, manaCost = 8}, + ["exevo mas san"] = {level = 50, manaCost = 160}, + ["exevo pan"] = {level = 14, manaCost = 120}, + ["exevo tera hur"] = {level = 38, manaCost = 210}, + ["exevo vis hur"] = {level = 38, manaCost = 170}, + ["exevo vis lux"] = {level = 23, manaCost = 40}, + ["exori"] = {level = 35, manaCost = 115}, + ["exori amp vis"] = {level = 55, manaCost = 60}, + ["exori con"] = {level = 23, manaCost = 25}, + ["exori flam"] = {level = 14, manaCost = 20}, + ["exori frigo"] = {level = 15, manaCost = 20}, + ["exori gran"] = {level = 90, manaCost = 340}, + ["exori gran con"] = {level = 90, manaCost = 55}, + ["exori gran flam"] = {level = 70, manaCost = 60}, + ["exori gran frigo"] = {level = 80, manaCost = 60}, + ["exori gran ico"] = {level = 110, manaCost = 300}, + ["exori gran tera"] = {level = 70, manaCost = 60}, + ["exori gran vis"] = {level = 80, manaCost = 60}, + ["exori hur"] = {level = 28, manaCost = 40}, + ["exori ico"] = {level = 16, manaCost = 30}, + ["exori infir tera"] = {level = 1, manaCost = 6}, + ["exori infir vis"] = {level = 1, manaCost = 6}, + ["exori mas"] = {level = 33, manaCost = 160}, + ["exori max flam"] = {level = 90, manaCost = 100}, + ["exori max frigo"] = {level = 100, manaCost = 100}, + ["exori max tera"] = {level = 90, manaCost = 100}, + ["exori max vis"] = {level = 100, manaCost = 100}, + ["exori min"] = {level = 70, manaCost = 200}, + ["exori min flam"] = {level = 8, manaCost = 6}, + ["exori moe ico"] = {level = 16, manaCost = 20}, + ["exori mort"] = {level = 16, manaCost = 20}, + ["exori san"] = {level = 40, manaCost = 20}, + ["exori tera"] = {level = 13, manaCost = 20}, + ["exori vis"] = {level = 12, manaCost = 20}, + ["exura"] = {level = 8, manaCost = 20}, + ["exura dis"] = {level = 1, manaCost = 5}, + ["exura gran"] = {level = 20, manaCost = 70}, + ["exura gran ico"] = {level = 80, manaCost = 200}, + ["exura gran mas res"] = {level = 36, manaCost = 150}, + ["exura gran san"] = {level = 60, manaCost = 210}, + ["exura ico"] = {level = 8, manaCost = 40}, + ["exura infir"] = {level = 1, manaCost = 6}, + ["exura infir ico"] = {level = 1, manaCost = 10}, + ["exura san"] = {level = 35, manaCost = 160}, + ["exura vita"] = {level = 30, manaCost = 160}, + ["utamo mas sio"] = {level = 32, manaCost = 0}, + ["utamo tempo"] = {level = 55, manaCost = 200}, + ["utamo tempo san"] = {level = 55, manaCost = 400}, + ["utamo vita"] = {level = 14, manaCost = 50}, + ["utana vid"] = {level = 35, manaCost = 440}, + ["utani gran hur"] = {level = 20, manaCost = 100}, + ["utani hur"] = {level = 14, manaCost = 60}, + ["utani tempo hur"] = {level = 25, manaCost = 100}, + ["utevo gran lux"] = {level = 13, manaCost = 60}, + ["utevo gran res dru"] = {level = 200, manaCost = 3000}, + ["utevo gran res eq"] = {level = 200, manaCost = 1000}, + ["utevo gran res sac"] = {level = 200, manaCost = 2000}, + ["utevo gran res ven"] = {level = 200, manaCost = 3000}, + ["utevo lux"] = {level = 8, manaCost = 20}, + ["utevo vis lux"] = {level = 26, manaCost = 140}, + ["utito mas sio"] = {level = 32, manaCost = 0}, + ["utito tempo"] = {level = 60, manaCost = 290}, + ["utito tempo san"] = {level = 60, manaCost = 450}, + ["utori flam"] = {level = 26, manaCost = 30}, + ["utori kor"] = {level = 40, manaCost = 30}, + ["utori mas sio"] = {level = 32, manaCost = 0}, + ["utori mort"] = {level = 75, manaCost = 30}, + ["utori pox"] = {level = 50, manaCost = 30}, + ["utori san"] = {level = 70, manaCost = 30}, + ["utori vis"] = {level = 34, manaCost = 30}, + ["utura"] = {level = 50, manaCost = 75}, + ["utura gran"] = {level = 100, manaCost = 165}, + ["utura mas sio"] = {level = 32, manaCost = 0} +} + +function getSpellCoolDown(text) + if not text then return false end + if text:lower() == "exura" then + return modules.game_cooldown.isCooldownIconActive(1) + elseif text:lower() == "exura gran" then + return modules.game_cooldown.isCooldownIconActive(2) + elseif text:lower() == "exura vita" then + return modules.game_cooldown.isCooldownIconActive(3) + elseif text:lower() == "exura gran mas res" then + return modules.game_cooldown.isCooldownIconActive(82) + elseif string.find(text:lower(), "exura sio") then + return modules.game_cooldown.isCooldownIconActive(84) + elseif string.find(text:lower(), "exiva") then + return modules.game_cooldown.isCooldownIconActive(20) + elseif string.find(text:lower(), "exani hur") then + return modules.game_cooldown.isCooldownIconActive(81) + elseif string.find(text:lower(), "utevo res ina") then + return modules.game_cooldown.isCooldownIconActive(38) + elseif string.find(text:lower(), 'utevo res "' ) then + return modules.game_cooldown.isCooldownIconActive(9) + elseif text:lower() == "exana pox" then + return modules.game_cooldown.isCooldownIconActive(29) + elseif text:lower() == "utevo lux" then + return modules.game_cooldown.isCooldownIconActive(10) + elseif text:lower() == "exani tera" then + return modules.game_cooldown.isCooldownIconActive(76) + elseif text:lower() == "exori vis" then + return modules.game_cooldown.isCooldownIconActive(88) + elseif text:lower() == "utevo gran lux" then + return modules.game_cooldown.isCooldownIconActive(11) + elseif text:lower() == "utani hur" then + return modules.game_cooldown.isCooldownIconActive(6) + elseif text:lower() == "exori tera" then + return modules.game_cooldown.isCooldownIconActive(113) + elseif text:lower() == "exevo pan" then + return modules.game_cooldown.isCooldownIconActive(42) + elseif text:lower() == "utamo vita" then + return modules.game_cooldown.isCooldownIconActive(44) + elseif text:lower() == "exori flam" then + return modules.game_cooldown.isCooldownIconActive(89) + elseif text:lower() == "exori frigo" then + return modules.game_cooldown.isCooldownIconActive(112) + elseif text:lower() == "exori moe ico" then + return modules.game_cooldown.isCooldownIconActive(148) + elseif text:lower() == "exevo frigo hur" then + return modules.game_cooldown.isCooldownIconActive(121) + elseif text:lower() == "utani gran hur" then + return modules.game_cooldown.isCooldownIconActive(39) + elseif text:lower() == "exana vis" then + return modules.game_cooldown.isCooldownIconActive(146) + elseif text:lower() == "utevo vis lux" then + return modules.game_cooldown.isCooldownIconActive(75) + elseif text:lower() == "exana flam" then + return modules.game_cooldown.isCooldownIconActive(145) + elseif text:lower() == "utana vid" then + return modules.game_cooldown.isCooldownIconActive(45) + elseif text:lower() == "exevo tera hur" then + return modules.game_cooldown.isCooldownIconActive(120) + elseif text:lower() == "exevo gran frigo hur" then + return modules.game_cooldown.isCooldownIconActive(43) + elseif text:lower() == "exana kor" then + return modules.game_cooldown.isCooldownIconActive(144) + elseif text:lower() == "utori pox" then + return modules.game_cooldown.isCooldownIconActive(142) + elseif text:lower() == "exevo gran mas tera" then + return modules.game_cooldown.isCooldownIconActive(56) + elseif text:lower() == "exevo gran mas frigo" then + return modules.game_cooldown.isCooldownIconActive(118) + elseif text:lower() == "exevo gran mas tera" then + return modules.game_cooldown.isCooldownIconActive(56) + elseif text:lower() == "exori gran tera" then + return modules.game_cooldown.isCooldownIconActive(153) + elseif text:lower() == "exori max tera" then + return modules.game_cooldown.isCooldownIconActive(157) + elseif text:lower() == "exori gran frigo" then + return modules.game_cooldown.isCooldownIconActive(152) + elseif text:lower() == "exori max frigo" then + return modules.game_cooldown.isCooldownIconActive(156) + elseif text:lower() == "exori max tera" then + return modules.game_cooldown.isCooldownIconActive(157) + elseif text:lower() == "exori con" then + return modules.game_cooldown.isCooldownIconActive(111) + elseif text:lower() == "exura san" then + return modules.game_cooldown.isCooldownIconActive(125) + elseif text:lower() == "exevo mas san" then + return modules.game_cooldown.isCooldownIconActive(124) + elseif text:lower() == "utura" then + return modules.game_cooldown.isCooldownIconActive(159) + elseif text:lower() == "utura gran" then + return modules.game_cooldown.isCooldownIconActive(160) + elseif text:lower() == "utamo tempo san" then + return modules.game_cooldown.isCooldownIconActive(134) + elseif text:lower() == "utito tempo san" then + return modules.game_cooldown.isCooldownIconActive(135) + elseif text:lower() == "exura gran san" then + return modules.game_cooldown.isCooldownIconActive(36) + elseif text:lower() == "utori san" then + return modules.game_cooldown.isCooldownIconActive(143) + elseif text:lower() == "exana mort" then + return modules.game_cooldown.isCooldownIconActive(147) + elseif text:lower() == "exori gran con" then + return modules.game_cooldown.isCooldownIconActive(57) + elseif text:lower() == "exura ico" then + return modules.game_cooldown.isCooldownIconActive(123) + elseif text:lower() == "exeta res" then + return modules.game_cooldown.isCooldownIconActive(93) + elseif text:lower() == "utani tempo hur" then + return modules.game_cooldown.isCooldownIconActive(131) + elseif text:lower() == "utamo tempo" then + return modules.game_cooldown.isCooldownIconActive(132) + elseif text:lower() == "utito tempo" then + return modules.game_cooldown.isCooldownIconActive(133) + elseif text:lower() == "exura gran ico" then + return modules.game_cooldown.isCooldownIconActive(158) + elseif text:lower() == "exori hur" then + return modules.game_cooldown.isCooldownIconActive(107) + elseif text:lower() == "exori ico" then + return modules.game_cooldown.isCooldownIconActive(61) + elseif text:lower() == "exori" then + return modules.game_cooldown.isCooldownIconActive(80) + elseif text:lower() == "exori mas" then + return modules.game_cooldown.isCooldownIconActive(106) + elseif text:lower() == "exori gran" then + return modules.game_cooldown.isCooldownIconActive(105) + elseif text:lower() == "exori gran ico" then + return modules.game_cooldown.isCooldownIconActive(62) + elseif text:lower() == "exori min" then + return modules.game_cooldown.isCooldownIconActive(59) + elseif text:lower() == "exevo gran mas flam" then + return modules.game_cooldown.isCooldownIconActive(24) + elseif text:lower() == "exevo gran mas vis" then + return modules.game_cooldown.isCooldownIconActive(119) + elseif text:lower() == "exevo vis hur" then + return modules.game_cooldown.isCooldownIconActive(13) + elseif text:lower() == "exevo vis lux" then + return modules.game_cooldown.isCooldownIconActive(22) + elseif text:lower() == "exevo gran vis lux" then + return modules.game_cooldown.isCooldownIconActive(23) + elseif text:lower() == "exori amp vis" then + return modules.game_cooldown.isCooldownIconActive(149) + elseif text:lower() == "exori gran vis" then + return modules.game_cooldown.isCooldownIconActive(151) + elseif text:lower() == "exori gran flam" then + return modules.game_cooldown.isCooldownIconActive(150) + elseif text:lower() == "exori max vis" then + return modules.game_cooldown.isCooldownIconActive(155) + elseif text:lower() == "exori max flam" then + return modules.game_cooldown.isCooldownIconActive(154) + elseif text:lower() == "exevo gran flam hur" then + return modules.game_cooldown.isCooldownIconActive(150) + else + return false + end +end + +storage.isUsing = false + +onUse(function(pos, itemId, stackPos, subType) + if pos.x < 65000 then + storage.isUsing = true + end + schedule(1500, function() storage.isUsing = false end) +end) + +function string.starts(String,Start) + return string.sub(String,1,string.len(Start))==Start +end + +function isFriend(name) + if not name then return false end + + if getCreatureByName(name, true):isPlayer() and not getCreatureByName(name, true):isLocalPlayer() and table.find(storage.playerList.friendList, name) or string.find(storage.serverMembers, name) or table.find(storage.playerList.friendList, name:lower()) or (storage.playerList.groupMembers and ((getCreatureByName(name, true):getShield() >= 3 and getCreatureByName(name, true):getShield() <= 10) or getCreatureByName(name, true):getEmblem() == 2)) then + return true + else + return false + end +end + +function isEnemy(name) + if not name then return false end + + if getCreatureByName(name, true):isPlayer() and not getCreatureByName(name, true):isLocalPlayer() and table.find(storage.playerList.enemyList, name) or table.find(storage.playerList.enemyList, name:lower()) 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 getPlayerByName(name) + if not name then + return false + end + + local creature + for i, spec in pairs(getSpectators()) do + if spec:isPlayer() and spec:getName():lower() == name:lower() then + creature = spec + end + end + + if creature then + return creature + 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 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 = 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 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(g_map.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(g_map.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 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) + local targetTile + for _, tile in ipairs(g_map.getTiles(posz())) do + if tile:getTopUseThing():getId() == id then + targetTile = tile:getPosition() + end + end + if distanceFromPlayer(targetTile) > 1 then + if autoWalk(targetTile, 10, {ignoreNonPathable = true, precision=1}) then + delay(200) + end + else + return true + end +end + +function useGroundItem(id) + if not id then + return false + 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 + if distanceFromPlayer(targetTile) > 1 then + if autoWalk(targetTile, 20, {ignoreNonWalkable = true, ignoreNonPathable = true, precision=1}) then + delay(200) + end + else + g_game.use(g_map.getTile(targetTile):getTopUseThing()) + return true + end + else + return "retry" + 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() + schedule(100, function() g_game.open(findItem(23721)) return true end) + schedule(1400, function() g_game.open(findItem(23721)) return true end) + CaveBot.delay(1500) + return true +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() 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 + if not safe then safe = false end + + local fieldList = {} + local bestTile = nil + -- best area tile to use + for _, tile in pairs(g_map.getTiles(posz())) do + if tile:canShoot() and distanceFromPlayer(tile:getPosition()) <= maxDist and tile:isWalkable() and getCreaturesInArea(tile:getPosition(), pattern, specType) > 0 and (not safe or getCreaturesInArea(tile:getPosition(), pattern, 3) == 0) then + table.insert(fieldList, {pos = tile, count = getCreaturesInArea(tile:getPosition(), pattern, specType)}) + end + end + table.sort(fieldList, function(a,b) return a.count > b.count end) + + bestTile = fieldList[1] + + if bestTile then + return bestTile + else + return false + end +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/vithrax_1.1/0 BotSever.lua b/modules/game_bot/default_configs/vithrax_1.1/0 BotSever.lua new file mode 100644 index 0000000..55e1604 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/1 alarms.lua b/modules/game_bot/default_configs/vithrax_1.1/1 alarms.lua new file mode 100644 index 0000000..27182ca --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/1 combo.lua b/modules/game_bot/default_configs/vithrax_1.1/1 combo.lua new file mode 100644 index 0000000..966d717 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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 autoWalk(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/vithrax_1.1/1 pushmax.lua b/modules/game_bot/default_configs/vithrax_1.1/1 pushmax.lua new file mode 100644 index 0000000..f4ff8df --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/1 pushmax.lua @@ -0,0 +1,183 @@ +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 getTarget() then + target = getTarget() + else + target = g_game.getFollowingCreature() + 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 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 + useWith(tonumber(storage[pushPanelName].pushMaxRuneId), target) -- 3197 desintigrate rune / 3188 firebomb rune + delay(10) + g_game.move(target, targetTile:getPosition()) + tile:setText("") + targetTile:setText("") + target = nil + targetTile = nil + end + else + if tile:getTopUseThing():isPickupable() or not tile:getTopUseThing():isNotMoveable() then + useWith(tonumber(storage[pushPanelName].pushMaxRuneId), target) + delay(10) + g_game.move(target, targetTile:getPosition()) + delay(1250) + else + g_game.move(target, targetTile:getPosition()) + delay(1250) + end + 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 target or not storage[pushPanelName].enabled then return end + if keys == storage[pushPanelName].pushMaxKey and resetTimer == 0 then + local tile = getTileUnderCursor() + if tile and not tile:getCreatures()[1] then + targetTile = tile + tile:setText("DESTINATION") + end + end + resetTimer = now +end) +onKeyPress(function(keys) + if not target or not storage[pushPanelName].enabled then return end + if keys == storage[pushPanelName].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 target:isPlayer() and storage[pushPanelName].enabled then + if creature:getName() == target:getName() then + 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/vithrax_1.1/2HealBot.lua b/modules/game_bot/default_configs/vithrax_1.1/2HealBot.lua new file mode 100644 index 0000000..655c8dd --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/2HealBot.lua @@ -0,0 +1,293 @@ +setDefaultTab("HP") +healPanelName = "healbot" +local ui = setupUI([[ +Panel + height: 19 + + BotSwitch + id: title + anchors.top: parent.top + anchors.left: parent.left + text-align: center + width: 130 + !text: tr('HealBot') + + Button + id: combos + anchors.top: prev.top + anchors.left: prev.right + anchors.right: parent.right + margin-left: 3 + height: 17 + text: Setup + +]]) +ui:setId(healPanelName) + +if not storage[healPanelName] or not storage[healPanelName].spellTable or not storage[healPanelName].itemTable then + storage[healPanelName] = { + enabled = false, + spellTable = {}, + itemTable = {} + } +end + +ui.title:setOn(storage[healPanelName].enabled) +ui.title.onClick = function(widget) +storage[healPanelName].enabled = not storage[healPanelName].enabled +widget:setOn(storage[healPanelName].enabled) +end + +ui.combos.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() + + 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%" + else + source = "HP%" + end + + if spellEquasion == "Above" then + equasion = ">" + elseif spellEquasion == "Below" then + equasion = "<" + else + equasion = "=" + end + + if spellFormula:len() > 0 then + table.insert(storage[healPanelName].spellTable, {spell = spellFormula, sign = equasion, origin = source, cost = manaCost, value = spellTrigger}) + local label = g_ui.createWidget("SpellEntry", healWindow.spells.spellList) + label.remove.onClick = function(widget) + table.removevalue(storage[healPanelName].spellTable, label:getText()) + label:destroy() + end + label:setText("(MP>" .. manaCost .. ") " .. source .. equasion .. spellTrigger .. ":" .. spellFormula) + healWindow.spells.spellFormula:setText('') + healWindow.spells.spellValue:setText('') + healWindow.spells.manaCost:setText('') + end + 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.id:setItemId(0) + healWindow.items.trigger:setText('') + return + end + + + if src == "Current Mana" then + source = "MP" + elseif src == "Current Health" then + source = "HP" + elseif src == "Mana Percent" then + source = "MP%" + else + source = "HP%" + end + + if eq == "Above" then + equasion = ">" + elseif eq == "Below" then + equasion = "<" + else + equasion = "=" + end + + if id > 100 then + table.insert(storage[healPanelName].itemTable, {item = id, sign = equasion, origin = source, value = trigger}) + local label = g_ui.createWidget("SpellEntry", healWindow.items.itemList) + label.remove.onClick = function(widget) + table.removevalue(storage[healPanelName].itemTable, label:getText()) + label:destroy() + end + label:setText(source .. equasion .. trigger .. ":" .. id) + healWindow.items.id:setItemId(0) + healWindow.items.trigger:setText('') + end + end + + if storage[healPanelName].itemTable and #storage[healPanelName].itemTable > 0 then + for _, entry in pairs(storage[healPanelName].itemTable) do + local label = g_ui.createWidget("SpellEntry", healWindow.items.itemList) + label.remove.onClick = function(widget) + table.removevalue(storage[healPanelName].itemTable, entry) + label:destroy() + end + label:setText(entry.origin .. entry.sign .. entry.value .. ":" .. entry.item) + end + end + + if storage[healPanelName].spellTable and #storage[healPanelName].spellTable > 0 then + for _, entry in pairs(storage[healPanelName].spellTable) do + local label = g_ui.createWidget("SpellEntry", healWindow.spells.spellList) + label.remove.onClick = function(widget) + table.removevalue(storage[healPanelName].spellTable, entry) + label:destroy() + end + label:setText("(MP>" .. entry.cost .. ") " .. entry.origin .. entry.sign .. entry.value .. ":" .. entry.spell) + end + end + + healWindow.closeButton.onClick = function(widget) + healWindow:hide() + end +end + +-- spells +macro(100, function() + if not storage[healPanelName].enabled or modules.game_cooldown.isGroupCooldownIconActive(2) or #storage[healPanelName].spellTable == 0 then return end + + for _, entry in pairs(storage[healPanelName].spellTable) do + if mana() >= tonumber(entry.cost) and not getSpellCoolDown(entry.spell) 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 + end + end + end +end) + +-- items +macro(500, function() + if not storage[healPanelName].enabled or storage.isUsing or #storage[healPanelName].itemTable == 0 then return end + + for _, entry in pairs(storage[healPanelName].itemTable) do + local item = findItem(entry.item) + if item then + if entry.origin == "HP%" then + if entry.sign == "=" and hppercent() == entry.value then + useWith(entry.item, player) + return + elseif entry.sign == ">" and hppercent() >= entry.value then + useWith(entry.item, player) + return + elseif entry.sign == "<" and hppercent() <= entry.value then + useWith(entry.item, player) + return + end + elseif entry.origin == "HP" then + if entry.sign == "=" and hp() == tonumberentry.value then + useWith(entry.item, player) + return + elseif entry.sign == ">" and hp() >= entry.value then + useWith(entry.item, player) + return + elseif entry.sign == "<" and hp() <= entry.value then + useWith(entry.item, player) + return + end + elseif entry.origin == "MP%" then + if entry.sign == "=" and manapercent() == entry.value then + useWith(entry.item, player) + return + elseif entry.sign == ">" and manapercent() >= entry.value then + useWith(entry.item, player) + return + elseif entry.sign == "<" and manapercent() <= entry.value then + useWith(entry.item, player) + return + end + elseif entry.origin == "MP" then + if entry.sign == "=" and mana() == entry.value then + useWith(entry.item, player) + return + elseif entry.sign == ">" and mana() >= entry.value then + useWith(entry.item, player) + return + elseif entry.sign == "<" and mana() <= entry.value then + useWith(entry.item, player) + return + end + end + end + end +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/3 Sio.lua b/modules/game_bot/default_configs/vithrax_1.1/3 Sio.lua new file mode 100644 index 0000000..e469bfb --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/3 Sio.lua @@ -0,0 +1,121 @@ +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 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) + 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) + delay(300) + end + end + end + end + end) +addSeparator() \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/3 player list.lua b/modules/game_bot/default_configs/vithrax_1.1/3 player list.lua new file mode 100644 index 0000000..b9fceeb --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/3 player list.lua @@ -0,0 +1,150 @@ + 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 = {}, + groupMembers = true, + outfits = false, + marks = false + } + 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 + + playerListWindow.AddFriend.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('') + 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('') + 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('') + 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 + specOutfit.head = 112 + specOutfit.body = 112 + specOutfit.legs = 112 + specOutfit.feet = 112 + spec:setOutfit(specOutfit) + elseif isFriend(spec:getName()) then + specOutfit.head = 88 + specOutfit.body = 88 + specOutfit.legs = 88 + specOutfit.feet = 88 + spec:setOutfit(specOutfit) + end + end + end + end +end +refreshStatus() + +onCreatureAppear(function(creature) + if creature:isPlayer() then + refreshStatus() + end +end) + +addSeparator() \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/AttackBot.lua b/modules/game_bot/default_configs/vithrax_1.1/AttackBot.lua new file mode 100644 index 0000000..5fe4abf --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/AttackBot.lua @@ -0,0 +1,691 @@ +-- 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: mode + anchors.top: prev.bottom + anchors.left: parent.left + anchors.right: parent.horizontalCenter + text: Mode: PVP + margin-right: 2 + margin-top: 4 + font: cipsoftFont + height: 17 + + Button + id: safe + anchors.top: settings.bottom + anchors.left: parent.horizontalCenter + anchors.right: parent.right + text: PVP Safe + margin-left: 2 + margin-top: 4 + height: 17 + font:cipsoftFont +]]) +ui:setId(attackPanelName) + +local i = 1 +local j = 1 +local k = 1 +local pvpDedicated = false +local item = false + +UI.Separator() + +if not storage[attackPanelName] or not storage[attackPanelName].attackTable then + storage[attackPanelName] = { + pvpMode = false, + pvpSafe = true, + enabled = false, + attackTable = {} + } +end + +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.)" +} + +local labels = { + "", + "Area Spell", + "Adjacent", + "Front Sweep", + "Wave", + "Targeted Spell", + "Targeted Rune", + "Area Rune", +} + +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)" +} + +local updateModeText = function() + local text + if storage[attackPanelName].pvpMode then + text = "PVP" + ui.mode:setColor("yellow") + else + text = "HUNT" + ui.mode:setColor("green") + end + ui.mode:setText("MODE: " .. text) +end +updateModeText() + +local updatePvpColor = function() + if storage[attackPanelName].pvpSafe then + ui.safe:setColor("green") + else + ui.safe:setColor("white") + end +end +updatePvpColor() + +ui.title:setOn(storage[attackPanelName].enabled) +ui.title.onClick = function(widget) +storage[attackPanelName].enabled = not storage[attackPanelName].enabled +widget:setOn(storage[attackPanelName].enabled) +end + +ui.mode.onClick = function(widget) +storage[attackPanelName].pvpMode = not storage[attackPanelName].pvpMode +updateModeText() +end + +ui.safe.onClick = function(widget) +storage[attackPanelName].pvpSafe = not storage[attackPanelName].pvpSafe +updatePvpColor() +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 + updateCategoryText() + local updateParameter1Text = function() + attackWindow.parameter1:setText(pattern[k]) + end + updateParameter1Text() + local updateParameter2Text = function() + attackWindow.parameter2:setText(range[j]) + end + updateParameter2Text() + + -- checkbox + attackWindow.pvpSpell.onClick = function(widget) + pvpDedicated = not pvpDedicated + attackWindow.pvpSpell:setChecked(pvpDedicated) + 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 + inputTypeToggle() + + attackWindow.categoryNext.onClick = function(widget) + if i == #categories then + i = 1 + else + i = i + 1 + end + updateCategoryText() + inputTypeToggle() + end + + attackWindow.categoryPrev.onClick = function(widget) + if i == 1 then + i = #categories + else + i = i - 1 + end + 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("") + attackWindow.minMonsters:setText("") + attackWindow.itemId:setItemId(0) + pvpDedicated = false + item = false + attackWindow.pvpSpell:setChecked(false) + i = 1 + j = 1 + k = 1 + updateParameter1Text() + updateParameter2Text() + updateCategoryText() + inputTypeToggle() + 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 + local pvpText + table.insert(storage[attackPanelName].attackTable, {attack = val, manaCost = tonumber(attackWindow.minMana:getText()), minMonsters = tonumber(attackWindow.minMonsters:getText()), pvp = pvpDedicated, dist = j-1, model = k, category = i}) + local label = g_ui.createWidget("AttackEntry", attackWindow.attackList) + if pvpDedicated then + label:setText("(" .. tonumber(attackWindow.minMana:getText()) .. "% MP) " .. labels[i] .. ": " .. val .. " (Range: ".. j-1 .. ")") + label:setColor("yellow") + else + label:setText("(" .. tonumber(attackWindow.minMana:getText()) .. "% MP & mob >= " .. tonumber(attackWindow.minMonsters:getText()) .. ") " .. labels[i] .. ": " .. val .. " (Range: ".. j-1 .. ")") + label:setColor("green") + end + clearValues() + end + end + + if storage[attackPanelName].attackTable and #storage[attackPanelName].attackTable > 0 then + for _, entry in pairs(storage[attackPanelName].attackTable) do + local label = g_ui.createWidget("AttackEntry", attackWindow.attackList) + label.remove.onClick = function(widget) + table.removevalue(storage[attackPanelName].attackTable, entry) + label:destroy() + end + if entry.pvp then + label:setText("(" .. entry.manaCost .. "% MP) " .. labels[entry.category] .. ": " .. entry.attack .. " (Range: ".. j-1 .. ")") + label:setColor("yellow") + else + label:setText("(" .. entry.manaCost .. "% MP & mob >= " .. entry.minMonsters .. ") " .. labels[entry.category] .. ": " .. entry.attack .. " (Range: ".. j-1 .. ")") + label:setColor("green") + end + 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 +]] + +macro(1000, function() + if not storage[attackPanelName].enabled then return end + if #storage[attackPanelName].attackTable == 0 or isInPz() or not target() or modules.game_cooldown.isGroupCooldownIconActive(1) or modules.game_cooldown.isGroupCooldownIconActive(4) then return 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(), posN, 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 player:getDirection() ~= bestDir and bestSide > 0 and CaveBot.isOn() then + turn(bestDir) + end + + for _, entry in pairs(storage[attackPanelName].attackTable) do + if (type(entry.attack) == "string" and canCast(entry.attack)) or (type(entry.attack) == "number" and findItem(entry.attack)) then + if manapercent() >= entry.manaCost and distanceFromPlayer(target():getPosition()) <= entry.dist then + if storage[attackPanelName].pvpMode then + if entry.pvp and target():canShoot() then + if type(entry.attack) == "string" then + say(entry.attack) + return + else + if not storage.isUsing then + useWith(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 + useWith(entry.attack, target()) + return + end + else + say(entry.attack) + return + end + end + else + if killsToRs() > 2 then + local areaTile = getBestTileByPatern(patterns[4], 2, entry.dist, storage[attackPanelName].pvpSafe) + if entry.category == 4 and (not storage[attackPanelName].pvpSafe or isSafe(2, false)) and bestSide >= entry.minMonsters then + say(entry.attack) + return + elseif entry.category == 3 and (not storage[attackPanelName].pvpSafe or isSafe(2, false)) and getMonsters(1) >= entry.minMonsters then + say(entry.attack) + return + elseif entry.category == 5 and getCreaturesInArea(player, patterns[entry.model], 2) >= entry.minMonsters and (not storage[attackPanelName].pvpSafe or getCreaturesInArea(player, safePatterns[entry.model], 3) == 0) then + say(entry.attack) + return + elseif entry.category == 2 and getCreaturesInArea(pos(), patterns[entry.model], 2) >= entry.minMonsters and (not storage[attackPanelName].pvpSafe or getCreaturesInArea(pos(), safePatterns[entry.model], 3) == 0) then + say(entry.attack) + return + elseif entry.category == 8 and areaTile and areaTile.count >= entry.minMonsters then + if not storage.isUsing then + useWith(entry.attack, areaTile.pos:getTopUseThing()) + end + 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 + useWith(entry.attack, target()) + return + end + else + say(entry.attack) + 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 + useWith(entry.attack, target()) + return + end + else + say(entry.attack) + return + end + end + end + end + end + end + end + end + end +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/AttackBot.otui b/modules/game_bot/default_configs/vithrax_1.1/AttackBot.otui new file mode 100644 index 0000000..be03d32 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/AttackBot.otui @@ -0,0 +1,207 @@ +AttackEntry < 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 + +AttackWindow < MainWindow + !text: tr('AttackBot') + size: 490 350 + @onEscape: self:hide() + + TextList + id: attackList + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + padding: 1 + size: 470 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: 27 + margin-left: 5 + 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: 20 + margin-left: 5 + + Label + id: itemDescription + anchors.left: itemId.right + margin-left: 5 + anchors.verticalCenter: itemId.verticalCenter + text: < insert id or drag item here + + Label + anchors.left: parameter2Prev.left + anchors.top: parameter2Prev.bottom + margin-top: 17 + text-align: center + text: Min Monsters: + + TextEdit + id: minMonsters + anchors.left: prev.right + anchors.verticalCenter: prev.verticalCenter + margin-left: 5 + width: 30 + + Label + anchors.left: parameter2Prev.left + anchors.top: prev.bottom + margin-top: 10 + text-align: center + text: Min Mana%: + + TextEdit + id: minMana + anchors.left: minMonsters.left + anchors.verticalCenter: prev.verticalCenter + width: 30 + + CheckBox + id: pvpSpell + anchors.left: minMonsters.right + width: 100 + margin-left: 10 + anchors.verticalCenter: minMonsters.verticalCenter + text: Spell for PVP + + Button + id: addButton + anchors.horizontalCenter: pvpSpell.horizontalCenter + anchors.verticalCenter: minMana.verticalCenter + text-align: center + text: Add + margin-left: 5 + margin-left: 5 + size: 45 21 + + 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/vithrax_1.1/BotServer.otui b/modules/game_bot/default_configs/vithrax_1.1/BotServer.otui new file mode 100644 index 0000000..b9dbc87 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/Castle.lua b/modules/game_bot/default_configs/vithrax_1.1/Castle.lua new file mode 100644 index 0000000..f01ecd5 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/Castle.lua @@ -0,0 +1,76 @@ +setDefaultTab("Tools") +UI.Label("-- [[ ANTI PUSH Panel ]] --") +addSeparator() + local panelName = "castle" + local ui = setupUI([[ +Panel + height: 40 + + BotItem + id: item + anchors.top: parent.top + anchors.left: parent.left + margin-top: 2 + + BotSwitch + id: skip + anchors.top: parent.top + anchors.left: item.right + anchors.right: parent.right + anchors.bottom: item.verticalCenter + text-align: center + !text: tr('Skip Tiles Near Target') + margin-left: 2 + + BotSwitch + id: title + anchors.top: item.verticalCenter + anchors.left: item.right + anchors.right: parent.right + anchors.bottom: item.bottom + text-align: center + !text: tr('Drop Items Around') + margin-left: 2 + + ]], parent) + ui:setId(panelName) + + if not storage[panelName] then + storage[panelName] = { + id = 2983, + around = false, + enabled = false + } + end + + ui.skip:setOn(storage[panelName].around) + ui.skip.onClick = function(widget) + storage[panelName].around = not storage[panelName].around + widget:setOn(storage[panelName].around) + end + ui.title:setOn(storage[panelName].enabled) + ui.title.onClick = function(widget) + storage[panelName].enabled = not storage[panelName].enabled + widget:setOn(storage[panelName].enabled) + end + + ui.item:setItemId(storage[panelName].id) + ui.item.onItemChange = function(widget) + storage[panelName].id = widget:getItemId() + end + + +macro(175, function() + if storage[panelName].enabled then + local blockItem = findItem(storage[panelName].id) + for _, tile in pairs(g_map.getTiles(posz())) do + if distanceFromPlayer(tile:getPosition()) == 1 and tile:isWalkable() and tile:getTopUseThing():getId() ~= storage[panelName].id and (not storage[panelName].around or not target() or (target() and getDistanceBetween(targetPos(), tile:getPosition() > 1))) then + g_game.move(blockItem, tile:getPosition()) + return + end + end + storage[panelName].enabled = false + ui.title:setOn(storage[panelName].enabled) + end +end) +addSeparator() \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/Conditions.otui b/modules/game_bot/default_configs/vithrax_1.1/Conditions.otui new file mode 100644 index 0000000..c55f1eb --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/Conditions.otui @@ -0,0 +1,412 @@ +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 180 + + 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 180 + + 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: 15 + + Label + id: label + anchors.verticalCenter: IgnoreInPz.verticalCenter + anchors.left: prev.right + margin-top: 3 + margin-left: 5 + text: Don't Cast in Protection Zones + font: cipsoftFont + +ConditionsWindow < MainWindow + !text: tr('Condition Manager') + size: 445 270 + @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/vithrax_1.1/HealBot.otui b/modules/game_bot/default_configs/vithrax_1.1/HealBot.otui new file mode 100644 index 0000000..be0f8e6 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/HealBot.otui @@ -0,0 +1,306 @@ +SpellSourceBoxPopupMenu < ComboBoxPopupMenu +SpellSourceBoxPopupMenuButton < ComboBoxPopupMenuButton +SpellSourceBox < ComboBox + @onSetup: | + self:addOption("Current Mana") + self:addOption("Current Health") + self:addOption("Mana Percent") + self:addOption("Health Percent") + +SpellConditionBoxPopupMenu < ComboBoxPopupMenu +SpellConditionBoxPopupMenuButton < ComboBoxPopupMenuButton +SpellConditionBox < ComboBox + @onSetup: | + self:addOption("Below") + self:addOption("Above") + self:addOption("Equal To") + +SpellEntry < 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 + +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: 460 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: 240 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: 460 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: 240 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: 490 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 + + 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/vithrax_1.1/Title.lua b/modules/game_bot/default_configs/vithrax_1.1/Title.lua new file mode 100644 index 0000000..2c5c0d0 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/Title.lua @@ -0,0 +1,16 @@ +local vocation = player:getVocation() +local vocText = nil + +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(10000, function() + g_window.setTitle("Tibia - " .. player:getName() .. " - " .. lvl() .. "lvl - " .. vocText) +end, batTab) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/alarms.otui b/modules/game_bot/default_configs/vithrax_1.1/alarms.otui new file mode 100644 index 0000000..23682de --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/analyzers.lua b/modules/game_bot/default_configs/vithrax_1.1/analyzers.lua new file mode 100644 index 0000000..816a02b --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/analyzers.lua @@ -0,0 +1,375 @@ +local analyserPanelName = "AnalysersPanel" +local ui = setupUI([[ +Panel + height: 18 + + Button + id: analyzersMain + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + height: 18 + text: Hunt Analysers + ]], parent) +ui:setId(analyserPanelName) + +if not storage[analyserPanelName] then + storage[analyserPanelName] = { + bestHit = 0, + bestHeal = 0, + lootItems = {} + } +end + +analyzersWindow = g_ui.createWidget('MainAnalyzer', modules.game_interface.getRightPanel()) +huntWindow = g_ui.createWidget('HuntAnalyser', modules.game_interface.getRightPanel()) +impactWindow = g_ui.createWidget('ImpactAnalyser', modules.game_interface.getRightPanel()) +lootWindow = g_ui.createWidget('LootAnalyser', modules.game_interface.getRightPanel()) +xpWindow = g_ui.createWidget('XpAnalyser', modules.game_interface.getRightPanel()) +analyzersWindow:setup() +huntWindow:setup() +impactWindow:setup() +lootWindow:setup() +xpWindow:setup() + +rootWidget = g_ui.getRootWidget() +lootListWindow = g_ui.createWidget('LootWindow', rootWidget) +lootListWindow:hide() + +function refresh() + analyzersWindow:setContentMinimumHeight(105) + analyzersWindow:setContentMaximumHeight(105) + huntWindow:setContentMinimumHeight(30) + impactWindow:setContentMinimumHeight(30) + impactWindow:setContentMaximumHeight(185) + lootWindow:setContentMinimumHeight(30) + xpWindow:setContentMinimumHeight(30) + xpWindow:setContentMaximumHeight(65) +end +refresh() + +function huntWindowToggle() + if huntWindow:isVisible() then + huntWindow:close() + else + huntWindow:open() + end +end + +function impactWindowToggle() + if impactWindow:isVisible() then + impactWindow:close() + else + impactWindow:open() + end +end + +function lootWindowToggle() + if lootWindow:isVisible() then + lootWindow:close() + else + lootWindow:open() + end +end + +function xpWindowToggle() + if xpWindow:isVisible() then + xpWindow:close() + else + xpWindow:open() + end +end + +ui.analyzersMain.onClick = function(widget) + if analyzersWindow:isVisible() then + analyzersWindow:close() + else + analyzersWindow:open() + end +end +lootWindow.contentsPanel.LootEdit.onClick = function(widget) + lootListWindow:show() + lootListWindow:raise() + lootListWindow:focus() +end + +if storage[analyserPanelName].lootItems and #storage[analyserPanelName].lootItems > 0 then + for _, name in ipairs(storage[analyserPanelName].lootItems) do + local label = g_ui.createWidget("LootItemName", lootListWindow.LootList) + label.remove.onClick = function(widget) + table.removevalue(storage[analyserPanelName].lootItems, label:getText()) + label:destroy() + end + label:setText(name) + end +end + +lootListWindow.AddLoot.onClick = function(widget) + local lootName = lootListWindow.LootName:getText() + if lootName:len() > 0 and not table.contains(storage[analyserPanelName].lootItems, lootName, true) then + table.insert(storage[analyserPanelName].lootItems, lootName) + local label = g_ui.createWidget("LootItemName", lootListWindow.LootList) + label.remove.onClick = function(widget) + table.removevalue(storage[analyserPanelName].lootItems, label:getText()) + label:destroy() + end + label:setText(lootName) + lootListWindow.LootName:setText('') + end +end + +lootListWindow.closeButton.onClick = function(widget) + lootListWindow:hide() +end + +analyzersWindow.contentsPanel.HuntButton.onClick = function(widget) + huntWindowToggle() +end +analyzersWindow.contentsPanel.lootSupplyButton.onClick = function(widget) + lootWindowToggle() +end +analyzersWindow.contentsPanel.impactButton.onClick = function(widget) + impactWindowToggle() +end +analyzersWindow.contentsPanel.xpButton.onClick = function(widget) + xpWindowToggle() +end + +local uptime +local launchTime = now +local startTime = now +function sessionTime() + uptime = math.floor((now - launchTime)/1000) + local hours = string.format("%02.f", math.floor(uptime/3600)) + local mins = string.format("%02.f", math.floor(uptime/60 - (hours*60))) + +return hours .. ":" .. mins .. "h" +end + +local startExp = exp() +function expGained() + return exp() - startExp +end + +function expForLevel(level) + return math.floor((50*level*level*level)/3 - 100*level*level + (850*level)/3 - 200) +end + +function expH() + return (expGained() / (now - startTime)) +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 + +function checkExpSpeed() + local player = g_game.getLocalPlayer() + if not player then return end + + local currentExp = player:getExperience() + local currentTime = now/1000 + if player.lastExps ~= nil then + player.expSpeed = (currentExp - player.lastExps[1][1])/(currentTime - player.lastExps[1][2]) + else + player.lastExps = {} + end + table.insert(player.lastExps, {currentExp, currentTime}) + if #player.lastExps > 30 then + table.remove(player.lastExps, 1) + end + + return player.expSpeed +end + +function nextLevelData(time) + + if checkExpSpeed() ~= nil then + expPerHour = math.floor(checkExpSpeed() * 3600) + if expPerHour > 0 then + nextLevelExp = expForLevel(player:getLevel()+1) + hoursLeft = (nextLevelExp - player:getExperience()) / expPerHour + minutesLeft = math.floor((hoursLeft - math.floor(hoursLeft))*60) + hoursLeft = math.floor(hoursLeft) + timeLeft = tostring(hoursLeft .. ":" .. minutesLeft .. "h") + end + end + + if time then + return expPerHour + else + return timeLeft + end +end + +function sum(t) + local sum = 0 + for k,v in pairs(t) do + sum = sum + v + end + + return sum +end + +local cumulatedDamage = 0 +local cumulatedHealing = 0 +local allHits = {} +local allHeals = {} +local dps +local hps +local kills = {} +local droppedItems = {} +onTextMessage(function(mode, text) + -- [[ kill counter ]] -- + if string.find(text, "Loot of") then + local split = string.split(text, ":") + local mobName = string.split(split[1], "of ")[2]:trim() + table.insert(kills, mobName) + + local killCount = {} + for i, entry in pairs(kills) do + if killCount[entry] then + killCount[entry] = killCount[entry] + 1 + else + killCount[entry] = 1 + end + end + + for i, child in pairs(huntWindow.contentsPanel.MessagePanel:getChildren()) do + child:destroy() + end + + for k,v in pairs(killCount) do + local label = g_ui.createWidget("MonsterLabel", huntWindow.contentsPanel.MessagePanel) + label:setText(v .. "x " .. k) + end + + -- [[ loot counter ]] -- + local monsterDrop = string.split(split[2], ",") + + if #monsterDrop > 0 then + for i=1,#monsterDrop do + local drop = monsterDrop[i]:trim() + for i, entry in pairs(storage[analyserPanelName].lootItems) do + if string.match(drop, entry) then + local entryCount + if tonumber(string.match(drop, "%d+")) then + entryCount = tonumber(string.match(drop, "%d+")) + else + entryCount = 1 + end + if droppedItems[entry] then + droppedItems[entry] = droppedItems[entry] + entryCount + else + droppedItems[entry] = entryCount + end + end + end + end + end + for i, child in pairs(lootWindow.contentsPanel.MessagePanel:getChildren()) do + child:destroy() + end + for k,v in pairs(droppedItems) do + local label = g_ui.createWidget("MonsterLabel", lootWindow.contentsPanel.MessagePanel) + label:setText(v .. "x " .. k) + end + end + + -- damage + if string.find(text, "hitpoints due to your attack") then + table.insert(allHits, tonumber(string.match(text, "%d+"))) + if dps then + if now - startTime > 1000 then + local dmgSum = sum(allHits) + dps = dmgSum + allHits = {} + startTime = now + end + else + dps = 0 + end + + local dmgValue = tonumber(string.match(text, "%d+")) + cumulatedDamage = cumulatedDamage + dmgValue + if storage[analyserPanelName].bestHit < dmgValue then + storage[analyserPanelName].bestHit = dmgValue + end + end + -- healing + if string.find(text, "You heal") then + table.insert(allHeals, tonumber(string.match(text, "%d+"))) + if hps then + if now - startTime > 1000 then + local healSum = sum(allHeals) + hps = healSum + allHeals = {} + startTime = now + end + else + hps = 0 + end + local healValue = tonumber(string.match(text, "%d+")) + cumulatedHealing = cumulatedHealing + healValue + if storage[analyserPanelName].bestHeal < healValue then + storage[analyserPanelName].bestHeal = healValue + end + end + + -- [[ waste]] -- + if string.find(text, "Using one of") then + local splitTwo = string.split(text, "Using one of") + if #splitTwo == 1 then + local itemAmount = string.match(splitTwo[1], "%d+") + end + + end +end) + +function hourVal(v) + if not v then return end + return (v/uptime)*3600 +end + +function expH() + return (expGained()/uptime)*3600 +end + +local lootWorth +macro(1000, function() + -- [[ profit ]] -- + lootWorth = 0 + for k, v in pairs(droppedItems) do + if lootitems[k] then + lootWorth = lootWorth + (lootitems[k]*v) + end + end + -- [[ Hunt Window ]] -- + huntWindow.contentsPanel.sessionValue:setText(sessionTime()) + huntWindow.contentsPanel.xpGainValue:setText(format_thousand(expGained())) + huntWindow.contentsPanel.xpHourValue:setText(format_thousand(expH())) + if cumulatedDamage then huntWindow.contentsPanel.damageValue:setText(format_thousand(cumulatedDamage)) end + if cumulatedHealing then huntWindow.contentsPanel.healingValue:setText(format_thousand(cumulatedHealing)) end + huntWindow.contentsPanel.damageHourValue:setText(format_thousand(hourVal(cumulatedDamage))) + huntWindow.contentsPanel.healingHourValue:setText(format_thousand(hourVal(cumulatedHealing))) + huntWindow.contentsPanel.lootValue:setText(format_thousand(lootWorth)) + -- [[ XP Window ]] -- + xpWindow.contentsPanel.xpValue:setText(format_thousand(expGained())) + xpWindow.contentsPanel.hourValue:setText(format_thousand(expH())) + if not nextLevelData() then xpWindow.contentsPanel.ttnlValue:setText("-") else xpWindow.contentsPanel.ttnlValue:setText(nextLevelData()) end + -- [[ Impact Window ]] -- + if cumulatedDamage then impactWindow.contentsPanel.damageValue:setText(format_thousand(cumulatedDamage)) end + if dps then impactWindow.contentsPanel.maxDpsValue:setText(format_thousand(dps)) end + impactWindow.contentsPanel.allTimeHighValue:setText(format_thousand(storage[analyserPanelName].bestHit)) + if cumulatedHealing then impactWindow.contentsPanel.healingValue:setText(format_thousand(cumulatedHealing)) end + if hps then impactWindow.contentsPanel.maxHpsValue:setText(format_thousand(hps)) end + impactWindow.contentsPanel.allTimeHighHealValue:setText(format_thousand(storage[analyserPanelName].bestHeal)) + -- [[ Loot Window ]] -- + lootWindow.contentsPanel.lootValue:setText(format_thousand(lootWorth)) + lootWindow.contentsPanel.lootHourValue:setText(format_thousand(hourVal(lootWorth))) +end) diff --git a/modules/game_bot/default_configs/vithrax_1.1/analyzers.otui b/modules/game_bot/default_configs/vithrax_1.1/analyzers.otui new file mode 100644 index 0000000..e3e24a0 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/analyzers.otui @@ -0,0 +1,47 @@ +MainAnalyzer < MiniWindow + !text: tr('Analytics Selector') + height: 125 + icon: /images/topbuttons/analyzers + &autoOpen: false + + + MiniWindowContents + Button + id: HuntButton + !text: tr('Hunting Session Analyser') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + margin-top: 3 + margin-left: 3 + margin-right: 3 + + Button + id: lootSupplyButton + !text: tr('Loot & Supplies Analyser') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + margin-left: 3 + margin-right: 3 + + Button + id: impactButton + !text: tr('Impact Analyser') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + margin-left: 3 + margin-right: 3 + + Button + id: xpButton + !text: tr('XP Analyser') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + margin-left: 3 + margin-right: 3 \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/antikick.lua b/modules/game_bot/default_configs/vithrax_1.1/antikick.lua new file mode 100644 index 0000000..16a963f --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/antikick.lua @@ -0,0 +1,3 @@ +macro(60000, function() + turn(math.random(0,3)) +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/antipush.lua b/modules/game_bot/default_configs/vithrax_1.1/antipush.lua new file mode 100644 index 0000000..33080f3 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/antipush.lua @@ -0,0 +1,76 @@ +AntiPush = function(parent) + if not parent then + parent = panel + end + + local panelName = "antiPushPanel" + local ui = g_ui.createWidget("ItemsPanel", parent) + ui:setId(panelName) + + if not storage[panelName] then + storage[panelName] = {} + end + + ui.title:setText("Anti-Push Items") + ui.title:setOn(storage[panelName].enabled) + ui.title.onClick = function(widget) + storage[panelName].enabled = not storage[panelName].enabled + widget:setOn(storage[panelName].enabled) + end + + if type(storage[panelName].items) ~= 'table' then + storage[panelName].items = {3031, 3035, 0, 0, 0} + end + + for i=1,5 do + ui.items:getChildByIndex(i).onItemChange = function(widget) + storage[panelName].items[i] = widget:getItemId() + end + ui.items:getChildByIndex(i):setItemId(storage[panelName].items[i]) + end + + macro(100, function() + if not storage[panelName].enabled then + return + end + local tile = g_map.getTile(player:getPosition()) + if not tile then + return + end + local topItem = tile:getTopUseThing() + if topItem and topItem:isStackable() then + topItem = topItem:getId() + else + topItem = 0 + end + local candidates = {} + for i, item in pairs(storage[panelName].items) do + if item >= 100 and item ~= topItem and findItem(item) then + table.insert(candidates, item) + end + end + if #candidates == 0 then + return + end + if type(storage[panelName].lastItem) ~= 'number' or storage[panelName].lastItem > #candidates then + storage[panelName].lastItem = 1 + end + local item = findItem(candidates[storage[panelName].lastItem]) + g_game.move(item, player:getPosition(), 1) + storage[panelName].lastItem = storage[panelName].lastItem + 1 + end) + + macro(175, "Pull Nearby Items", function() + local trashitem = nil + for _, tile in pairs(g_map.getTiles(posz())) do + if distanceFromPlayer(tile:getPosition()) == 1 and #tile:getItems() ~= 0 and not tile:getTopUseThing():isNotMoveable() then + trashitem = tile:getTopUseThing() + g_game.move(trashitem, pos(), trashitem:getCount()) + return + end + end + end) +end + +AntiPush(setDefaultTab("Tools")) +addSeparator() \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/bless buy.lua b/modules/game_bot/default_configs/vithrax_1.1/bless buy.lua new file mode 100644 index 0000000..d56c639 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/bless buy.lua @@ -0,0 +1,8 @@ +if player:getBlessings() == 0 then + say("!bless") + schedule(2000, function() + if player:getBlessings() == 0 then + error("!! Blessings not bought !!") + end + end) +end diff --git a/modules/game_bot/default_configs/vithrax_1.1/cavebot/actions.lua b/modules/game_bot/default_configs/vithrax_1.1/cavebot/actions.lua new file mode 100644 index 0000000..9f83280 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/cavebot/actions.lua @@ -0,0 +1,315 @@ +CaveBot.Actions = {} + +-- it adds an action widget to list +CaveBot.addAction = function(action, value, focus) + action = action:lower() + local raction = CaveBot.Actions[action] + if not raction then + return error("Invalid cavebot action: " .. action) + end + if type(value) == 'number' then + value = tostring(value) + end + local widget = UI.createWidget("CaveBotAction", CaveBot.actionList) + widget:setText(action .. ":" .. value:split("\n")[1]) + widget.action = action + widget.value = value + if raction.color then + widget:setColor(raction.color) + end + widget.onDoubleClick = function(cwidget) -- edit on double click + if CaveBot.Editor then + schedule(20, function() -- schedule to have correct focus + CaveBot.Editor.edit(cwidget.action, cwidget.value, function(action, value) + CaveBot.editAction(cwidget, action, value) + CaveBot.save() + end) + end) + end + end + if focus then + widget:focus() + CaveBot.actionList:ensureChildVisible(widget) + end + return widget +end + +-- it updates existing widget, you should call CaveBot.save() later +CaveBot.editAction = function(widget, action, value) + action = action:lower() + local raction = CaveBot.Actions[action] + if not raction then + return error("Invalid cavebot action: " .. action) + end + + if not widget.action or not widget.value then + return error("Invalid cavebot action widget, has missing action or value") + end + + widget:setText(action .. ":" .. value:split("\n")[1]) + widget.action = action + widget.value = value + if raction.color then + widget:setColor(raction.color) + end + return widget +end + +--[[ +registerAction: +action - string, color - string, callback = function(value, retries, prev) +value is a string value of action, retries is number which will grow by 1 if return is "retry" +prev is a true when previuos action was executed succesfully, false otherwise +it must return true if executed correctly, false otherwise +it can also return string "retry", then the function will be called again in 20 ms +]]-- +CaveBot.registerAction = function(action, color, callback) + action = action:lower() + if CaveBot.Actions[action] then + return error("Duplicated acction: " .. action) + end + CaveBot.Actions[action] = { + color=color, + callback=callback + } +end + +CaveBot.registerAction("label", "yellow", function(value, retries, prev) + return true +end) + +CaveBot.registerAction("gotolabel", "#FFFF55", function(value, retries, prev) + return CaveBot.gotoLabel(value) +end) + +CaveBot.registerAction("delay", "#AAAAAA", function(value, retries, prev) + if retries == 0 then + CaveBot.delay(tonumber(value)) + return "retry" + end + return true +end) + +CaveBot.registerAction("function", "red", function(value, retries, prev) + local prefix = "local retries = " .. retries .. "\nlocal prev = " .. tostring(prev) .. "\nlocal delay = CaveBot.delay\nlocal gotoLabel = CaveBot.gotoLabel\n" + prefix = prefix .. "local macro = function() error('Macros inside cavebot functions are not allowed') end\n" + for extension, callbacks in pairs(CaveBot.Extensions) do + prefix = prefix .. "local " .. extension .. " = CaveBot.Extensions." .. extension .. "\n" + end + local status, result = pcall(function() + return assert(load(prefix .. value, "cavebot_function"))() + end) + if not status then + error("Error in cavebot function:\n" .. result) + return false + end + return result +end) + +CaveBot.registerAction("goto", "green", function(value, retries, prev) + local pos = regexMatch(value, "\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+),?\\s*([0-9]?)") + if not pos[1] then + error("Invalid cavebot goto action value. It should be position (x,y,z), is: " .. value) + return false + end + + if CaveBot.Config.get("mapClick") then + if retries >= 5 then + return false -- tried 5 times, can't get there + end + else + if retries >= 100 then + return false -- tried 100 times, can't get there + end + end + + local precision = tonumber(pos[1][5]) + pos = {x=tonumber(pos[1][2]), y=tonumber(pos[1][3]), z=tonumber(pos[1][4])} + local playerPos = player:getPosition() + if pos.z ~= playerPos.z then + return false -- different floor + end + + if math.abs(pos.x-playerPos.x) + math.abs(pos.y-playerPos.y) > 40 then + return false -- too far way + end + + local minimapColor = g_map.getMinimapColor(pos) + local stairs = (minimapColor >= 210 and minimapColor <= 213) + + if stairs then + if math.abs(pos.x-playerPos.x) == 0 and math.abs(pos.y-playerPos.y) <= 0 then + return true -- already at position + end + elseif math.abs(pos.x-playerPos.x) == 0 and math.abs(pos.y-playerPos.y) <= (precision or 1) then + return true -- already at position + end + -- check if there's a path to that place, ignore creatures and fields + local path = findPath(playerPos, pos, 40, { ignoreNonPathable = true, precision = 1, ignoreCreatures = true }) + if not path then + return false -- there's no way + end + + -- check if there's a path to destination but consider Creatures (attack only if trapped) + local path2 = findPath(playerPos, pos, 40, { ignoreNonPathable = true, precision = 1 }) + if not path2 then + local monsters = {} + for i, spec in pairs(getSpectators()) do + if spec:isMonster() and spec:canShoot() and findPath(playerPos, spec:getPosition(), 20, {ignoreNonPathable = true, precision = 1}) then + table.insert(monsters, {mob = spec, dist = getDistanceBetween(pos, spec:getPosition())}) + end + end + table.sort(monsters, function(a,b) return a.dist < b.dist end) + if monsters[1] then + g_game.attack(monsters[1].mob) + storage.blockMonster = monsters[1].mob + autoWalk(storage.blockMonster, 10, {precision = 1}) + storage.clearing = true + CaveBot.setOff() + g_game.setChaseMode(1) + schedule(10000, function() CaveBot.setOn() end) -- just in case callback trigger fails + return "retry" + else + return false -- there's no way + end + end + + -- try to find path, don't ignore creatures, don't ignore fields + if not CaveBot.Config.get("ignoreFields") and CaveBot.walkTo(pos, 40) then + return "retry" + end + + -- try to find path, don't ignore creatures, ignore fields + if CaveBot.walkTo(pos, 40, { ignoreNonPathable = true }) then + return "retry" + end + + if retries >= 3 then + -- try to lower precision, find something close to final position + local precison = retries - 1 + if stairs then + precison = 0 + end + if CaveBot.walkTo(pos, 50, { ignoreNonPathable = true, precision = precison }) then + return "retry" + end + end + + if not CaveBot.Config.get("mapClick") and retries >= 5 then + return false + end + + if CaveBot.Config.get("skipBlocked") then + return false + end + + -- everything else failed, try to walk ignoring creatures, maybe will work + CaveBot.walkTo(pos, 40, { ignoreNonPathable = true, precision = 1, ignoreCreatures = true }) + return "retry" +end) + +onCreatureDisappear(function(creature) + if creature ~= storage.blockMonster then return end + if storage.clearing then + CaveBot.setOn() + storage.blockMonster = nil + storage.clearing = false + end +end) + +onCreaturePositionChange(function(creature, newPos, oldPos) + if creature ~= storage.blockMonster and creature ~= player then return end + if storage.clearing then + if creature == storage.blockMonster and not findPath(player:getPosition(), newPos, 20, {ignoreNonPathable = true, precision = 1}) then + CaveBot.setOn() + storage.blockMonster = nil + storage.clearing = false + end + if creature == player then + if oldPos.z ~= newPos.z then + CaveBot.setOn() + storage.blockMonster = nil + storage.clearing = false + end + end + end +end) + +CaveBot.registerAction("use", "#FFB272", function(value, retries, prev) + local pos = regexMatch(value, "\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)") + if not pos[1] then + local itemid = tonumber(value) + if not itemid then + error("Invalid cavebot use action value. It should be (x,y,z) or item id, is: " .. value) + return false + end + use(itemid) + return true + end + + pos = {x=tonumber(pos[1][2]), y=tonumber(pos[1][3]), z=tonumber(pos[1][4])} + local playerPos = player:getPosition() + if pos.z ~= playerPos.z then + return false -- different floor + end + + if math.max(math.abs(pos.x-playerPos.x), math.abs(pos.y-playerPos.y)) > 7 then + return false -- too far way + end + + local tile = g_map.getTile(pos) + if not tile then + return false + end + + local topThing = tile:getTopUseThing() + if not topThing then + return false + end + + use(topThing) + CaveBot.delay(CaveBot.Config.get("useDelay") + CaveBot.Config.get("ping")) + return true +end) + +CaveBot.registerAction("usewith", "#EEB292", function(value, retries, prev) + local pos = regexMatch(value, "\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)") + if not pos[1] then + if not itemid then + error("Invalid cavebot usewith action value. It should be (itemid,x,y,z) or item id, is: " .. value) + return false + end + use(itemid) + return true + end + + local itemid = tonumber(pos[1][2]) + pos = {x=tonumber(pos[1][3]), y=tonumber(pos[1][4]), z=tonumber(pos[1][5])} + local playerPos = player:getPosition() + if pos.z ~= playerPos.z then + return false -- different floor + end + + if math.max(math.abs(pos.x-playerPos.x), math.abs(pos.y-playerPos.y)) > 7 then + return false -- too far way + end + + local tile = g_map.getTile(pos) + if not tile then + return false + end + + local topThing = tile:getTopUseThing() + if not topThing then + return false + end + + usewith(itemid, topThing) + CaveBot.delay(CaveBot.Config.get("useDelay") + CaveBot.Config.get("ping")) + return true +end) + +CaveBot.registerAction("say", "#FF55FF", function(value, retries, prev) + say(value) + return true +end) diff --git a/modules/game_bot/default_configs/vithrax_1.1/cavebot/bank.lua b/modules/game_bot/default_configs/vithrax_1.1/cavebot/bank.lua new file mode 100644 index 0000000..7ade925 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/cavebot/bank.lua @@ -0,0 +1,72 @@ +CaveBot.Extensions.Bank = {} + +CaveBot.Extensions.Bank.setup = function() + CaveBot.registerAction("bank", "#00FFFF", function(value, retries) + local data = string.split(value, ",") + local waitVal = 300 + local amount = 0 + local actionType + local npcName + if #data ~= 3 and #data ~= 2 then + warn("CaveBot[Bank]: incorrect value!") + return false + else + actionType = data[1]:trim():lower() + npcName = data[2]:trim() + if #data == 3 then + amount = tonumber(data[3]:trim()) + end + end + + if actionType ~= "withdraw" and actionType ~= "deposit" then + warn("CaveBot[Bank]: incorrect action type! should be withdraw/deposit, is: " .. actionType) + return false + elseif actionType == "withdraw" then + local value = tonumber(amount) + if not value then + warn("CaveBot[Bank]: incorrect amount value! should be number, is: " .. amount) + return false + end + end + + if retries > 5 then + print("CaveBot[Bank]: too many tries, skipping") + return false + end + + local npc = getCreatureByName(npcName) + if not npc then + print("CaveBot[Bank]: NPC not found, skipping") + return false + end + + local pos = player:getPosition() + local npcPos = npc:getPosition() + if math.max(math.abs(pos.x - npcPos.x), math.abs(pos.y - npcPos.y)) > 3 then + autoWalk(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/vithrax_1.1/cavebot/buy_supplies.lua b/modules/game_bot/default_configs/vithrax_1.1/cavebot/buy_supplies.lua new file mode 100644 index 0000000..959d506 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/cavebot/buy_supplies.lua @@ -0,0 +1,116 @@ +CaveBot.Extensions.BuySupplies = {} + +storage.buySuppliesCap = 0 +CaveBot.Extensions.BuySupplies.setup = function() + CaveBot.registerAction("BuySupplies", "#00FFFF", function(value, retries) + local item1Count = 0 + local item2Count = 0 + local item3Count = 0 + local item4Count = 0 + local item5Count = 0 + + local val = string.split(value, ",") + local waitVal + if #val == 0 or #val > 2 then + warn("CaveBot[BuySupplies]: incorrect BuySupplies value") + return false + elseif #val == 2 then + waitVal = tonumber(val[2]:trim()) + end + + local npc = getCreatureByName(val[1]:trim()) + if not npc then + print("CaveBot[BuySupplies]: NPC not found") + return false + end + + if not waitVal and #val == 2 then + warn("CaveBot[BuySupplies]: incorrect delay values!") + elseif waitVal and #val == 2 then + delay(waitVal) + end + + if retries > 30 then + print("CaveBot[BuySupplies]: Too many tries, can't buy") + return false + end + + if freecap() == storage.buySuppliesCap then + storage.buySuppliesCap = 0 + print("CaveBot[BuySupplies]: Bought Everything, proceeding") + return true + end + + delay(800) + + local pos = player:getPosition() + local npcPos = npc:getPosition() + if math.max(math.abs(pos.x - npcPos.x), math.abs(pos.y - npcPos.y)) > 3 then + autoWalk(npcPos, 20, {ignoreNonPathable = true, precision=3}) + delay(300) + return "retry" + end + + for _, container in pairs(getContainers()) do + for _, item in ipairs(container:getItems()) do + if (storage[suppliesPanelName].item1 > 100) and (item:getId() == storage[suppliesPanelName].item1) then + item1Count = item1Count + item:getCount() + end + if (storage[suppliesPanelName].item2 > 100) and (item:getId() == storage[suppliesPanelName].item2) then + item2Count = item2Count + item:getCount() + end + if (storage[suppliesPanelName].item3 > 100) and (item:getId() == storage[suppliesPanelName].item3) then + item3Count = item3Count + item:getCount() + end + if (storage[suppliesPanelName].item4 > 100) and (item:getId() == storage[suppliesPanelName].item4) then + item4Count = item4Count + item:getCount() + end + if (storage[suppliesPanelName].item5 > 100) and (item:getId() == storage[suppliesPanelName].item5) then + item5Count = item5Count + item:getCount() + end + end + end + + local itemList = { + item1 = {ID = storage[suppliesPanelName].item1, maxAmount = storage[suppliesPanelName].item1Max, currentAmount = item1Count}, + item2 = {ID = storage[suppliesPanelName].item2, maxAmount = storage[suppliesPanelName].item2Max, currentAmount = item2Count}, + item3 = {ID = storage[suppliesPanelName].item3, maxAmount = storage[suppliesPanelName].item3Max, currentAmount = item3Count}, + item4 = {ID = storage[suppliesPanelName].item4, maxAmount = storage[suppliesPanelName].item4Max, currentAmount = item4Count}, + item5 = {ID = storage[suppliesPanelName].item5, maxAmount = storage[suppliesPanelName].item5Max, currentAmount = item5Count} + } + + if not NPC.isTrading() then + NPC.say("hi") + schedule(500, function() NPC.say("trade") end) + else + storage.buySuppliesCap = freecap() + end + + for i, item in pairs(itemList) do + if item["ID"] > 100 then + local amountToBuy = item["maxAmount"] - item["currentAmount"] + if amountToBuy > 100 then + for i=1, math.ceil(amountToBuy/100), 1 do + NPC.buy(item["ID"], math.min(100, amountToBuy)) + amountToBuy = amountToBuy - math.min(100, amountToBuy) + print("CaveBot[BuySupplies]: bought " .. amountToBuy .. "x " .. item["ID"]) + return "retry" + end + else + if amountToBuy > 0 then + NPC.buy(item["ID"], amountToBuy) + print("CaveBot[BuySupplies]: bought " .. amountToBuy .. "x " .. item["ID"]) + return "retry" + end + end + end + end + return "retry" + end) + + CaveBot.Editor.registerAction("buysupplies", "buy supplies", { + value="NPC name", + title="Buy Supplies", + description="NPC Name, delay(in ms, optional)", + }) +end \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/cavebot/cavebot.lua b/modules/game_bot/default_configs/vithrax_1.1/cavebot/cavebot.lua new file mode 100644 index 0000000..a00ee71 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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 + error("Invalid return from cavebot action (" .. currentAction.action .. "), should be \"retry\", false or true, is: " .. tostring(result)) + end + else + error("Error while executing cavebot action (" .. currentAction.action .. "):\n" .. result) + end + else + error("Invalid cavebot action: " .. currentAction.action) + end + + if retry then + return + end + + if currentAction ~= ui.list:getFocusedChild() then + -- focused child can change durring action, get it again and reset state + currentAction = ui.list:getFocusedChild() or ui.list:getFirstChild() + actionRetries = 0 + prevActionResult = true + end + local nextAction = ui.list:getChildIndex(currentAction) + 1 + if nextAction > actions then + nextAction = 1 + end + ui.list:focusChild(ui.list:getChildByIndex(nextAction)) +end) + +-- config, its callback is called immediately, data can be nil +local lastConfig = "" +config = Config.setup("cavebot_configs", configWidget, "cfg", function(name, enabled, data) + if enabled and CaveBot.Recorder.isOn() then + CaveBot.Recorder.disable() + CaveBot.setOff() + return + end + + local currentActionIndex = ui.list:getChildIndex(ui.list:getFocusedChild()) + ui.list:destroyChildren() + if not data then return cavebotMacro.setOff() end + + local cavebotConfig = nil + for k,v in ipairs(data) do + if type(v) == "table" and #v == 2 then + if v[1] == "config" then + local status, result = pcall(function() + return json.decode(v[2]) + end) + if not status then + error("Error while parsing CaveBot extensions from config:\n" .. result) + else + cavebotConfig = result + end + elseif v[1] == "extensions" then + local status, result = pcall(function() + return json.decode(v[2]) + end) + if not status then + error("Error while parsing CaveBot extensions from config:\n" .. result) + else + for extension, callbacks in pairs(CaveBot.Extensions) do + if callbacks.onConfigChange then + callbacks.onConfigChange(name, enabled, result[extension]) + end + end + end + else + CaveBot.addAction(v[1], v[2]) + end + end + end + + CaveBot.Config.onConfigChange(name, enabled, cavebotConfig) + + actionRetries = 0 + CaveBot.resetWalking() + prevActionResult = true + cavebotMacro.setOn(enabled) + cavebotMacro.delay = nil + if lastConfig == name then + -- restore focused child on the action list + ui.list:focusChild(ui.list:getChildByIndex(currentActionIndex)) + end + lastConfig = name +end) + +-- ui callbacks +ui.showEditor.onClick = function() + if not CaveBot.Editor then return end + if ui.showEditor:isOn() then + CaveBot.Editor.hide() + ui.showEditor:setOn(false) + else + CaveBot.Editor.show() + ui.showEditor:setOn(true) + end +end + +ui.showConfig.onClick = function() + if not CaveBot.Config then return end + if ui.showConfig:isOn() then + CaveBot.Config.hide() + ui.showConfig:setOn(false) + else + CaveBot.Config.show() + ui.showConfig:setOn(true) + end +end + +-- public function, you can use them in your scripts +CaveBot.isOn = function() + return config.isOn() +end + +CaveBot.isOff = function() + return config.isOff() +end + +CaveBot.setOn = function(val) + if val == false then + return CaveBot.setOff(true) + end + config.setOn() +end + +CaveBot.setOff = function(val) + if val == false then + return CaveBot.setOn(true) + end + config.setOff() +end + +CaveBot.delay = function(value) + cavebotMacro.delay = math.max(cavebotMacro.delay or 0, now + value) +end + +CaveBot.gotoLabel = function(label) + label = label:lower() + for index, child in ipairs(ui.list:getChildren()) do + if child.action == "label" and child.value:lower() == label then + ui.list:focusChild(child) + return true + end + end + return false +end + +CaveBot.save = function() + local data = {} + for index, child in ipairs(ui.list:getChildren()) do + table.insert(data, {child.action, child.value}) + end + + if CaveBot.Config then + table.insert(data, {"config", json.encode(CaveBot.Config.save())}) + end + + local extension_data = {} + for extension, callbacks in pairs(CaveBot.Extensions) do + if callbacks.onSave then + local ext_data = callbacks.onSave() + if type(ext_data) == "table" then + extension_data[extension] = ext_data + end + end + end + table.insert(data, {"extensions", json.encode(extension_data, 2)}) + config.save(data) +end diff --git a/modules/game_bot/default_configs/vithrax_1.1/cavebot/cavebot.otui b/modules/game_bot/default_configs/vithrax_1.1/cavebot/cavebot.otui new file mode 100644 index 0000000..b92ed05 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/cavebot/config.lua b/modules/game_bot/default_configs/vithrax_1.1/cavebot/config.lua new file mode 100644 index 0000000..549f663 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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 error("Duplicated config key: " .. id) + end + + local panel + local setter -- sets value + if type(defaultValue) == "number" then + panel = UI.createWidget("CaveBotConfigNumberValuePanel", CaveBot.Config.ui) + setter = function(value) + CaveBot.Config.values[id] = value + panel.value:setText(value, true) + end + setter(defaultValue) + panel.value.onTextChange = function(widget, newValue) + newValue = tonumber(newValue) + if newValue then + CaveBot.Config.values[id] = newValue + CaveBot.save() + end + end + elseif type(defaultValue) == "boolean" then + panel = UI.createWidget("CaveBotConfigBooleanValuePanel", CaveBot.Config.ui) + setter = function(value) + CaveBot.Config.values[id] = value + panel.value:setOn(value, true) + end + setter(defaultValue) + panel.value.onClick = function(widget) + widget:setOn(not widget:isOn()) + CaveBot.Config.values[id] = widget:isOn() + CaveBot.save() + end + else + return error("Invalid default value of config for key " .. id .. ", should be number or boolean") + end + + panel.title:setText(tr(title) .. ":") + + CaveBot.Config.value_setters[id] = setter + CaveBot.Config.values[id] = defaultValue + CaveBot.Config.default_values[id] = defaultValue +end + +CaveBot.Config.get = function(id) + if CaveBot.Config.values[id] == nil then + return error("Invalid CaveBot.Config.get, id: " .. id) + end + return CaveBot.Config.values[id] +end \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/cavebot/config.otui b/modules/game_bot/default_configs/vithrax_1.1/cavebot/config.otui new file mode 100644 index 0000000..21d479d --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/cavebot/d_withdraw.lua b/modules/game_bot/default_configs/vithrax_1.1/cavebot/d_withdraw.lua new file mode 100644 index 0000000..a034e5f --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/cavebot/d_withdraw.lua @@ -0,0 +1,179 @@ +CaveBot.Extensions.DWithdraw = {} + +comparePosition = function(pPos, tPos) + return (getDistanceBetween(pPos, tPos) <= 1) +end + +local depotIDs = {3497, 3498, 3499, 3500} +storage.stopSearch = false +storage.lootContainerOpen = false +local i = 1 + + +CaveBot.Extensions.DWithdraw.setup = function() + CaveBot.registerAction("dpwithdraw", "#00FFFF", function(value, retries) + if freecap() < 200 then + print("CaveBot[DepotWithdraw]: cap limit reached, proceeding") + return true + end + if retries > 600 then + print("CaveBot[DepotWithdraw]: actions limit reached, proceeding") + return true + end + delay(50) + if not value or #string.split(value, ",") ~= 2 then return end + local destName = string.split(value, ",")[1]:trim() + local destId = tonumber(string.split(value, ",")[2]:trim()) + 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 autoWalk(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(22797), 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="shopping bag, 21411", + title="Loot Withdraw", + description="insert 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/vithrax_1.1/cavebot/depositer.lua b/modules/game_bot/default_configs/vithrax_1.1/cavebot/depositer.lua new file mode 100644 index 0000000..d397c47 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/cavebot/depositor.lua b/modules/game_bot/default_configs/vithrax_1.1/cavebot/depositor.lua new file mode 100644 index 0000000..c596650 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/cavebot/depositor.lua @@ -0,0 +1,376 @@ +CaveBot.Extensions.Depositor = {} + +local depotIDs = {3497, 3498, 3499, 3500} +local reset = function() + storage.stopSearch = false + storage.lootContainerOpen = false + storage.containersClosed = false + storage.containersReset = false + storage.currentStack = 0 + storage.currentNonStack = nonStackMin + storage.lastTry = nil + storage.lootItemsCount = 0 + storage.depositDone = false +end +local i = 1 + +CaveBot.Extensions.Depositor.setup = function() + CaveBot.registerAction("depositor", "#00FFFF", function(value, retries) + if retries > 400 then + print("CaveBot[Depositor]: Depositor actions limit reached, proceeding") + reset() + return true + end + + local name = storage["_configs"]["targetbot_configs"]["selected"] + local file = configDir .. "/targetbot_configs/" .. name .. ".json" + local data = g_resources.readFileContents(file) + local lootList = Config.parse(data)['looting']['items'] + local lootContainers = Config.parse(data)['looting']['containers'] + local mainBp + local stackBp + local nonStackBp + + local valueString = string.split(value, ",") -- if 3 then it's old tibia + + -- if old tibia then setup backpacks + if #valueString == 3 then + mainBp = tonumber(valueString[1]:trim()) + stackBp = tonumber(valueString[2]:trim()) -- non-stack bp count + nonStackBp = tonumber(valueString[3]:trim()) -- stack bp count + + if not mainBp or not stackBp or not nonStackBp then + warn("CaveBot[Depositor]: incorrect values! should be 3x ID of containers!") + reset() + return false + end + end + + -- start with checking the containers + local lootDestination = {} + for _, container in pairs(lootContainers) do + if not table.find(lootDestination, container['id']) then + table.insert(lootDestination, container['id']) + end + end + + -- pretty much every container action is needed only if you want to work with containers + if (value:lower() == "yes" or #valueString == 3) and not storage.containersReset then + + -- what is open and what's not + local currentContainers = {} + for i, container in pairs(getContainers()) do + if not table.find(currentContainers, container:getContainerItem():getId()) then + table.insert(currentContainers, container:getContainerItem():getId()) + end + end + + delay(500) -- slow down this function until containers reset + if #lootDestination > 0 then + -- first closing all that are opened + if not storage.containersClosed then + for i, container in pairs(getContainers()) do + if table.find(lootDestination, container:getContainerItem():getId()) then + g_game.close(container) + return "retry" + end + end + storage.containersClosed = true + end + -- now reopen them + if not storage.containersReset and storage.containersClosed then + for i, container in pairs(getContainers()) do + for j, item in pairs(container:getItems()) do + if table.find(lootDestination, item:getId()) and not table.find(currentContainers, item:getId()) then + g_game.open(item) + return "retry" + end + end + end + storage.containersReset = true + end + end + end + + if storage.depositDone then + reset() + print("CaveBot[Depositor]: Deposit finished, proceeding") + return true + end + + local tileList = {} + local tPos + local depotClear = false + local depotOpen = false + local depotBoxOpen = false + for _,tile in pairs(g_map.getTiles(posz())) do + for i,thing in pairs(tile:getThings()) do + if table.find(depotIDs, thing:getId()) then + table.insert(tileList, {tileObj = tile, distance = getDistanceBetween(pos(), tile:getPosition()), depotID = thing:getId()}) + end + end + end + table.sort(tileList, function(a,b) return a.distance < b.distance end) + ::findEmptyDP:: + if tileList[i] and not storage.stopSearch then + if tileList[i].depotID == 3498 then + tPos = {x = tileList[i].tileObj:getPosition().x + 1, y = tileList[i].tileObj:getPosition().y, z = tileList[i].tileObj:getPosition().z} + elseif tileList[i].depotID == 3499 then + tPos = {x = tileList[i].tileObj:getPosition().x, y = tileList[i].tileObj:getPosition().y + 1, z = tileList[i].tileObj:getPosition().z} + elseif tileList[i].depotID == 3500 then + tPos = {x = tileList[i].tileObj:getPosition().x - 1, y = tileList[i].tileObj:getPosition().y, z = tileList[i].tileObj:getPosition().z} + elseif tileList[i].depotID == 3497 then + tPos = {x = tileList[i].tileObj:getPosition().x, y = tileList[i].tileObj:getPosition().y - 1, z = tileList[i].tileObj:getPosition().z} + end + if tPos then + local dest = g_map.getTile(tPos) + if not (getDistanceBetween(pos(), dest:getPosition()) <= 1) then + if not dest:getCreatures()[1] and dest:isWalkable() then + if autoWalk(dest:getPosition(), {ignoreNonPathable=true}) then + storage.stopSearch = true + delay(100) + end + else + i = i + 1 + goto findEmptyDP + end + end + end + end + if tileList[i] and not table.find(depotIDs, tileList[i].tileObj:getTopLookThing():getId()) and (getDistanceBetween(pos(), tileList[i].tileObj:getPosition()) <= 1) then + for j=1,table.getn(tileList[i].tileObj:getThings()),1 do + if not tileList[i].tileObj:getThings()[j]:isNotMoveable() then + delay(500) + g_game.move(tileList[i].tileObj:getThings()[j], pos(), tileList[i].tileObj:getThings()[j]:getCount()) + end + end + if table.find(depotIDs, tileList[i].tileObj:getTopLookThing():getId()) then + depotClear = true + end + else + depotClear = true + end + if depotClear then + for _, container in pairs(getContainers()) do + if container:getName():lower() == "locker" then + depotOpen = true + end + end + end + if tileList[i] and depotClear and not depotOpen and not storage.lootContainerOpen then + delay(500) + g_game.use(tileList[i].tileObj:getTopUseThing()) + depotOpen = true + end + i = 1 + + -- finding depot + if depotOpen then + for _, container in pairs(getContainers()) do + if container:getName():lower() == "depot chest" then + depotBoxOpen = true + end + end + if findItem(3502) and not depotBoxOpen then + delay(500) + g_game.use(findItem(3502)) + depotBoxOpen = true + end + end + if depotBoxOpen and not storage.lootContainerOpen then + for _, container in pairs(getContainers()) do + if container:getName():lower() == "depot chest" then + for _, item in ipairs(container:getItems()) do + if #valueString ~= 3 then -- new depot + if item:isContainer() and table.find({22797, 22798}, item:getId()) then + delay(500) + storage.lootContainerOpen = true + break + end + else + if item:isContainer() and item:getId() == mainBp then + delay(500) + g_game.use(item, container) + storage.lootContainerOpen = true + break + end + end + end + break + end + end + end + + if #valueString == 3 then + delay(150) + for _, container in pairs(getContainers()) do + if container:getContainerItem():getId() == mainBp then + storage.lootContainerOpen = true + storage.isDepositing = true + break + end + end + end + + + local looting = {} + for _, lootItem in pairs(lootList) do + if not table.find(looting, lootItem['id']) and not table.find({3031, 3035, 3043}, lootItem['id']) then + table.insert(looting, lootItem['id']) + end + end + delay(200) + local currentItems = 0 + for _, container in pairs(getContainers()) do + for _, item in ipairs(container:getItems()) do + if table.find(looting, item:getId()) then + currentItems = currentItems + item:getCount() + end + end + end + + if currentItems == 0 then + if value:lower() ~= "yes" and #valueString ~= 3 then + storage.containersClosed = false + storage.containersReset = false + storage.depositDone = true + return "retry" + end + + for i, container in pairs(getContainers()) do + for j, item in pairs(container:getItems()) do + if table.find(lootDestination, container:getContainerItem():getId()) and table.find(lootDestination, item:getId()) then + g_game.open(item, container) + return "retry" + end + end + end + + storage.containersClosed = false + storage.containersReset = false + storage.depositDone = true + return "retry" + end + + -- only if old depot + local stackMin + local stackMax + local nonStackMin + local nonStackMax + if #valueString == 3 then + -- backpacks setup + local stack = 0 + local nonStack = 0 + for i, container in pairs(getContainers()) do + if container:getContainerItem():getId() == mainBp then + for i, item in pairs(container:getItems()) do + if item:getId() == stackBp then + stack = stack + 1 + elseif item:getId() == nonStackBp then + nonStack = nonStack + 1 + end + end + end + end + + stackMax = stack - 1 + nonStackMin = stack + nonStackMax = (stack + nonStack) - 1 + + storage.currentStack = 0 + storage.currentNonStack = nonStackMin + + if storage.lootItemsCount == currentItems then + if storage.lastTry == 1 then + if storage.currentStack < stackMax then + storage.currentStack = storage.currentStack + 1 + else + warn("CaveBot[Depositer]: Stack Backpack full! Proceeding.") + reset() + return true + end + elseif storage.lastTry == 2 then + if storage.currentNonStack < nonStackMax then + storage.currentNonStack = storage.currentNonStack + 1 + else + warn("CaveBot[Depositer]: Non-Stack Backpack full! Proceeding.") + reset() + return true + end + end + end + storage.lootItemsCount = currentItems + end + + if #looting > 0 then + if #valueString ~= 3 then -- version check, if value is set of 3 i + for i, depotcontainer in pairs(getContainers()) do + containerItemId = depotcontainer:getContainerItem():getId() + --check if open depot + if containerItemId == 3502 then + -- check all containers and items + for l, lootcontainer in pairs(getContainers()) do + for j, item in ipairs(lootcontainer:getItems()) do + -- now the criteria + if table.find(looting, item:getId()) then + -- move the item + if item:isStackable() then + g_game.move(item, depotcontainer:getSlotPosition(1), item:getCount()) + return "retry" + else + g_game.move(item, depotcontainer:getSlotPosition(0), item:getCount()) + return "retry" + end + end + end + end + end + end + else -- to be written, last part missing is stashing items for old depots + for i, depotcontainer in pairs(getContainers()) do + containerItemId = depotcontainer:getContainerItem():getId() + --check if open depot + if containerItemId == mainBp then + -- check all containers and items + for l, lootcontainer in pairs(getContainers()) do + for j, item in ipairs(lootcontainer:getItems()) do + -- now the criteria + if table.find(looting, item:getId()) then + -- move the item + if item:isStackable() then + g_game.move(item, depotcontainer:getSlotPosition(storage.currentStack), item:getCount()) + storage.lastTry = 1 + return "retry" + else + g_game.move(item, depotcontainer:getSlotPosition(storage.currentNonStack), item:getCount()) + storage.lastTry = 2 + return "retry" + end + end + end + end + end + end + + + end + else + warn("no items in looting list!") + reset() + return false + end + return "retry" + end) + + CaveBot.Editor.registerAction("depositor", "depositor", { + value="no", + title="Depositor", + description="No - just deposit \n Yes - also reopen loot containers \n mainID, stackId, nonStackId - for older tibia", + }) +end + +onPlayerPositionChange(function(newPos, oldPos) + if CaveBot.isOn() then + reset() + end +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/cavebot/doors.lua b/modules/game_bot/default_configs/vithrax_1.1/cavebot/doors.lua new file mode 100644 index 0000000..c91d984 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/cavebot/doors.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/vithrax_1.1/cavebot/editor.lua b/modules/game_bot/default_configs/vithrax_1.1/cavebot/editor.lua new file mode 100644 index 0000000..48f7925 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/cavebot/editor.lua @@ -0,0 +1,174 @@ +CaveBot.Editor = {} +CaveBot.Editor.Actions = {} + +-- also works as registerAction(action, params), then text == action +-- params are options for text editor or function to be executed when clicked +-- you have many examples how to use it bellow +CaveBot.Editor.registerAction = function(action, text, params) + if type(text) ~= 'string' then + params = text + text = action + end + + local color = nil + if type(params) ~= 'function' then + local raction = CaveBot.Actions[action] + if not raction then + return error("CaveBot editor error: action " .. action .. " doesn't exist") + end + CaveBot.Editor.Actions[action] = params + color = raction.color + end + + local button = UI.createWidget('CaveBotEditorButton', CaveBot.Editor.ui.buttons) + button:setText(text) + if color then + button:setColor(color) + end + button.onClick = function() + if type(params) == 'function' then + params() + return + end + CaveBot.Editor.edit(action, nil, function(action, value) + local focusedAction = CaveBot.actionList:getFocusedChild() + local index = CaveBot.actionList:getChildCount() + if focusedAction then + index = CaveBot.actionList:getChildIndex(focusedAction) + end + local widget = CaveBot.addAction(action, value) + CaveBot.actionList:moveChildToIndex(widget, index + 1) + CaveBot.actionList:focusChild(widget) + CaveBot.save() + end) + end + return button +end + +CaveBot.Editor.setup = function() + CaveBot.Editor.ui = UI.createWidget("CaveBotEditorPanel") + local ui = CaveBot.Editor.ui + local registerAction = CaveBot.Editor.registerAction + + registerAction("move up", function() + local action = CaveBot.actionList:getFocusedChild() + if not action then return end + local index = CaveBot.actionList:getChildIndex(action) + if index < 2 then return end + CaveBot.actionList:moveChildToIndex(action, index - 1) + CaveBot.actionList:ensureChildVisible(action) + CaveBot.save() + end) + registerAction("edit", function() + local action = CaveBot.actionList:getFocusedChild() + if not action or not action.onDoubleClick then return end + action.onDoubleClick(action) + end) + registerAction("move down", function() + local action = CaveBot.actionList:getFocusedChild() + if not action then return end + local index = CaveBot.actionList:getChildIndex(action) + if index >= CaveBot.actionList:getChildCount() then return end + CaveBot.actionList:moveChildToIndex(action, index + 1) + CaveBot.actionList:ensureChildVisible(action) + CaveBot.save() + end) + registerAction("remove", function() + local action = CaveBot.actionList:getFocusedChild() + if not action then return end + action:destroy() + CaveBot.save() + end) + + registerAction("label", { + value="labelName", + title="Label", + description="Add label", + multiline=false + }) + registerAction("delay", { + value="500", + title="Delay", + description="Delay next action (in milliseconds)", + multiline=false, + validation="^\\s*[0-9]{1,10}\\s*$" + }) + registerAction("gotolabel", "go to label", { + value="labelName", + title="Go to label", + description="Go to label", + multiline=false + }) + registerAction("goto", "go to", { + value=function() return posx() .. "," .. posy() .. "," .. posz() end, + title="Go to position", + description="Go to position (x,y,z)", + multiline=false, + validation="^\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+),?\\s*([0-9]?)$" + }) + registerAction("use", { + value=function() return posx() .. "," .. posy() .. "," .. posz() end, + title="Use", + description="Use item from position (x,y,z) or from inventory (itemId)", + multiline=false + }) + registerAction("usewith", "use with", { + value=function() return "itemId," .. posx() .. "," .. posy() .. "," .. posz() end, + title="Use with", + description="Use item at position (itemid,x,y,z)", + multiline=false, + validation="^\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)$" + }) + registerAction("say", { + value="text", + title="Say", + description="Enter text to say", + multiline=false + }) + registerAction("function", { + title="Edit bot function", + multiline=true, + value=CaveBot.Editor.ExampleFunctions[1][2], + examples=CaveBot.Editor.ExampleFunctions, + width=650 + }) + + ui.autoRecording.onClick = function() + if ui.autoRecording:isOn() then + CaveBot.Recorder.disable() + else + CaveBot.Recorder.enable() + end + end + + -- callbacks + onPlayerPositionChange(function(pos) + ui.pos:setText("Position: " .. pos.x .. ", " .. pos.y .. ", " .. pos.z) + end) + ui.pos:setText("Position: " .. posx() .. ", " .. posy() .. ", " .. posz()) +end + +CaveBot.Editor.show = function() + CaveBot.Editor.ui:show() +end + + +CaveBot.Editor.hide = function() + CaveBot.Editor.ui:hide() +end + +CaveBot.Editor.edit = function(action, value, callback) -- callback = function(action, value) + local params = CaveBot.Editor.Actions[action] + if not params then return end + if not value then + if type(params.value) == 'function' then + value = params.value() + elseif type(params.value) == 'string' then + value = params.value + end + end + + UI.EditorWindow(value, params, function(newText) + callback(action, newText) + end) +end diff --git a/modules/game_bot/default_configs/vithrax_1.1/cavebot/editor.otui b/modules/game_bot/default_configs/vithrax_1.1/cavebot/editor.otui new file mode 100644 index 0000000..d11288c --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/cavebot/example_functions.lua b/modules/game_bot/default_configs/vithrax_1.1/cavebot/example_functions.lua new file mode 100644 index 0000000..556129c --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/cavebot/example_functions.lua @@ -0,0 +1,90 @@ +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("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/vithrax_1.1/cavebot/extension_template.lua b/modules/game_bot/default_configs/vithrax_1.1/cavebot/extension_template.lua new file mode 100644 index 0000000..d015f11 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/cavebot/inbox_withdraw.lua b/modules/game_bot/default_configs/vithrax_1.1/cavebot/inbox_withdraw.lua new file mode 100644 index 0000000..f96b019 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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", "#00FFFF", function(value, retries) + local data = string.split(value, ",") + local withdrawId + local count + local itemCount = 0 + local depotAmount = 0 + if #data ~= 2 then + error("CaveBot[InboxWithdraw]: incorrect withdraw value") + return false + else + withdrawId = tonumber(data[1]) + count = tonumber(data[2]) + end + + for i, container in pairs(getContainers()) do + if not string.find(container:getName():lower(), "inbox") then + for j, item in pairs(container:getItems()) do + if item:getId() == withdrawId then + itemCount = itemCount + item:getCount() + end + end + end + end + + if itemCount >= count then + for i, container in pairs(getContainers()) do + if string.find(container:getName():lower(), "your inbox") then + g_game.close(container) + end + end + print("CaveBot[InboxWithdraw]: enough items, proceeding") + return true + end + + if retries > 400 then + print("CaveBot[InboxWithdraw]: actions limit reached, proceeding") + return true + end + + delay(200) + local tileList = {} + local tPos + local depotClear = false + local depotOpen = false + local depotBoxOpen = false + for _,tile in pairs(g_map.getTiles(posz())) do + for i,thing in pairs(tile:getThings()) do + if table.find(depotIDs, thing:getId()) then + table.insert(tileList, {tileObj = tile, distance = getDistanceBetween(pos(), tile:getPosition()), depotID = thing:getId()}) + end + end + end + table.sort(tileList, function(a,b) return a.distance < b.distance end) + ::findEmptyDP:: + if tileList[i] and not storage.stopSearch then + if tileList[i].depotID == 3498 then + tPos = {x = tileList[i].tileObj:getPosition().x + 1, y = tileList[i].tileObj:getPosition().y, z = tileList[i].tileObj:getPosition().z} + elseif tileList[i].depotID == 3499 then + tPos = {x = tileList[i].tileObj:getPosition().x, y = tileList[i].tileObj:getPosition().y + 1, z = tileList[i].tileObj:getPosition().z} + elseif tileList[i].depotID == 3500 then + tPos = {x = tileList[i].tileObj:getPosition().x - 1, y = tileList[i].tileObj:getPosition().y, z = tileList[i].tileObj:getPosition().z} + elseif tileList[i].depotID == 3497 then + tPos = {x = tileList[i].tileObj:getPosition().x, y = tileList[i].tileObj:getPosition().y - 1, z = tileList[i].tileObj:getPosition().z} + end + if tPos then + local dest = g_map.getTile(tPos) + if not comparePosition(pos(), dest:getPosition()) then + if not dest:getCreatures()[1] and dest:isWalkable() then + if autoWalk(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:getSize() 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/vithrax_1.1/cavebot/lure.lua b/modules/game_bot/default_configs/vithrax_1.1/cavebot/lure.lua new file mode 100644 index 0000000..770b62e --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/cavebot/lure.lua @@ -0,0 +1,23 @@ +CaveBot.Extensions.Lure = {} + +CaveBot.Extensions.Lure.setup = function() + CaveBot.registerAction("lure", "#00FFFF", function(value, retries) + if value == "start" then + TargetBot.enableLuring() + return true + elseif value == "stop" then + TargetBot.disableLuring() + return true + else + warn("incorrect lure value!") + return false + end + end) + + CaveBot.Editor.registerAction("lure", "lure", { + value="start", + title="Lure", + description="start/stop", + multiline=false, +}) +end \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/cavebot/pos_check.lua b/modules/game_bot/default_configs/vithrax_1.1/cavebot/pos_check.lua new file mode 100644 index 0000000..35cb477 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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 + error("wrong travel format, should be: label, distance, x, y, z") + return false + end + + local tilePos = player:getPosition() + + tilePos.x = tonumber(data[3]) + tilePos.y = tonumber(data[4]) + tilePos.z = tonumber(data[5]) + + if storage.posCheckRetries > 10 then + storage.posCheckRetries = 0 + print("CaveBot[CheckPos]: waypoints locked, too many tries, unclogging cavebot and proceeding") + return false + elseif (tilePos.z == player:getPosition().z) and (getDistanceBetween(player:getPosition(), tilePos) <= tonumber(data[2])) then + storage.posCheckRetries = 0 + print("CaveBot[CheckPos]: position reached, proceeding") + return true + else + storage.posCheckRetries = storage.posCheckRetries + 1 + CaveBot.gotoLabel(data[1]) + print("CaveBot[CheckPos]: position not-reached, going back to label: " .. data[1]) + return false + end + + + end) + + CaveBot.Editor.registerAction("poscheck", "pos check", { + value=function() return "label" .. "," .. "distance" .. "," .. posx() .. "," .. posy() .. "," .. posz() end, + title="Location Check", + description="label name, accepted dist from coordinates, x, y, z", + multiline=false, +}) +end \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/cavebot/recorder.lua b/modules/game_bot/default_configs/vithrax_1.1/cavebot/recorder.lua new file mode 100644 index 0000000..27206ba --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/cavebot/sell_all.lua b/modules/game_bot/default_configs/vithrax_1.1/cavebot/sell_all.lua new file mode 100644 index 0000000..1078ed2 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/cavebot/sell_all.lua @@ -0,0 +1,68 @@ +CaveBot.Extensions.SellAll = {} + +storage.sellAllCap = 0 +CaveBot.Extensions.SellAll.setup = function() + CaveBot.registerAction("SellAll", "#00FFFF", function(value, retries) + local val = string.split(value, ",") + local wait + if #val > 2 then + warn("CaveBot[SellAll]: incorrect sell all value!") + return false + end + + if #val == 2 then + wait = true + else + wait = false + end + + local npc = getCreatureByName(value) + if not npc then + print("CaveBot[SellAll]: NPC not found! skipping") + return false + end + + if retries > 10 then + print("CaveBot[SellAll]: can't sell, skipping") + return false + end + + if freecap() == storage.sellAllCap then + storage.sellAllCap = 0 + print("CaveBot[SellAll]: Sold everything, proceeding") + return true + end + + delay(800) + + local pos = player:getPosition() + local npcPos = npc:getPosition() + if math.max(math.abs(pos.x - npcPos.x), math.abs(pos.y - npcPos.y)) > 3 then + autoWalk(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/vithrax_1.1/cavebot/supply.lua b/modules/game_bot/default_configs/vithrax_1.1/cavebot/supply.lua new file mode 100644 index 0000000..b3cd4ca --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/cavebot/supply.lua @@ -0,0 +1,30 @@ +CaveBot.Extensions.Supply = {} + +local ui + +-- first function called, here you should setup your UI +CaveBot.Extensions.Supply.setup = function() + --ui = UI.createWidget('SupplyItemList') + --local widget = UI.createWidget('SupplyItem', ui.list) + --widget.item.onItemChange = function(newItem) + --widget.fields.min.onTextChange = function(newText) + -- make it similar to UI.Container, so if there are no free slots, add another one, keep min 4 slots, check if value min/max is number after edit +end + +-- called when cavebot config changes, configData is a table but it can be nil +CaveBot.Extensions.Supply.onConfigChange = function(configName, isEnabled, configData) + if not configData then return end + +end + +-- called when cavebot is saving config, should return table or nil +CaveBot.Extensions.Supply.onSave = function() + return {} +end + +-- bellow add you custom functions +-- this function can be used in cavebot function waypoint as: return Supply.run(retries, prev) +-- there are 2 useful parameters - retries (number) and prev (true/false), check actions.lua to learn more +CaveBot.Extensions.Supply.run = function(retries, prev) + return true +end diff --git a/modules/game_bot/default_configs/vithrax_1.1/cavebot/supply.otui b/modules/game_bot/default_configs/vithrax_1.1/cavebot/supply.otui new file mode 100644 index 0000000..83c76ac --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/cavebot/supply_check.lua b/modules/game_bot/default_configs/vithrax_1.1/cavebot/supply_check.lua new file mode 100644 index 0000000..3f56102 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/cavebot/supply_check.lua @@ -0,0 +1,65 @@ +CaveBot.Extensions.SupplyCheck = {} + +storage.supplyRetries = 0 +CaveBot.Extensions.SupplyCheck.setup = function() + CaveBot.registerAction("supplyCheck", "#00FFFF", function(value) + local softCount = itemAmount(6529) + itemAmount(3549) + local totalItem1 = itemAmount(storage[suppliesPanelName].item1) + local totalItem2 = itemAmount(storage[suppliesPanelName].item2) + local totalItem3 = itemAmount(storage[suppliesPanelName].item3) + local totalItem4 = itemAmount(storage[suppliesPanelName].item4) + local totalItem5 = itemAmount(storage[suppliesPanelName].item5) + + if storage.supplyRetries > 50 then + print("CaveBot[SupplyCheck]: Round limit reached, going back on refill.") + storage.supplyRetries = 0 + return true + elseif (storage[suppliesPanelName].imbues and player:getSkillLevel(11) ~= 100) then + print("CaveBot[SupplyCheck]: Imbues ran out. Going on refill.") + storage.supplyRetries = 0 + return true + elseif (storage[suppliesPanelName].staminaSwitch and stamina() < tonumber(storage[suppliesPanelName].staminaValue)) then + print("CaveBot[SupplyCheck]: Stamina ran out. Going on refill.") + storage.supplyRetries = 0 + return true + elseif (softCount < 1 and storage[suppliesPanelName].SoftBoots) then + print("CaveBot[SupplyCheck]: No soft boots left. Going on refill.") + storage.supplyRetries = 0 + return true + 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 true + 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 true + 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 true + 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 true + 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 true + elseif (freecap() < tonumber(storage[suppliesPanelName].capValue) and storage[suppliesPanelName].capSwitch) then + print("CaveBot[SupplyCheck]: Not enough capacity. Going on refill.") + storage.supplyRetries = 0 + return true + 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/vithrax_1.1/cavebot/travel.lua b/modules/game_bot/default_configs/vithrax_1.1/cavebot/travel.lua new file mode 100644 index 0000000..20abd3e --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/cavebot/travel.lua @@ -0,0 +1,52 @@ +CaveBot.Extensions.Travel = {} + +CaveBot.Extensions.Travel.setup = function() + CaveBot.registerAction("Travel", "#00FFFF", function(value, retries) + local data = string.split(value, ",") + local waitVal = 0 + if #data < 2 or #data > 3 then + warn("CaveBot[Travel]: incorrect travel value!") + return false + elseif #data == 3 then + waitVal = tonumber(data[3]:trim()) + end + + if not waitVal then + warn("CaveBot[Travel]: incorrect travel delay value!") + return false + end + + if retries > 5 then + print("CaveBot[Travel]: too many tries, can't travel") + return false + end + + local npc = getCreatureByName(data[1]:trim()) + if not npc then + print("CaveBot[Travel]: NPC not found, can't travel") + return false + end + + local pos = player:getPosition() + local npcPos = npc:getPosition() + if math.max(math.abs(pos.x - npcPos.x), math.abs(pos.y - npcPos.y)) > 3 then + autoWalk(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/vithrax_1.1/cavebot/walking.lua b/modules/game_bot/default_configs/vithrax_1.1/cavebot/walking.lua new file mode 100644 index 0000000..c8a7133 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/cavebot/withdraw.lua b/modules/game_bot/default_configs/vithrax_1.1/cavebot/withdraw.lua new file mode 100644 index 0000000..81a9bbf --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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", "#00FFFF", function(value, retries) + local data = string.split(value, ",") + local stashIndex + local withdrawId + local count + local itemCount = 0 + local depotAmount + if #data ~= 3 then + warn("incorrect withdraw value") + return false + else + stashIndex = tonumber(data[1]) + withdrawId = tonumber(data[2]) + count = tonumber(data[3]) + end + local withdrawSource = depotContainers[stashIndex] + + for i, container in pairs(getContainers()) do + if not string.find(container:getName():lower(), "depot") then + for j, item in pairs(container:getItems()) do + if item:getId() == withdrawId then + itemCount = itemCount + item:getCount() + end + end + end + end + + if itemCount >= count then + for i, container in pairs(getContainers()) do + if string.find(container:getName():lower(), "depot box") then + g_game.close(container) + end + end + print("enough items") + return true + end + + if retries > 400 then + return true + end + + delay(200) + local tileList = {} + local tPos + local depotClear = false + local depotOpen = false + local depotBoxOpen = false + for _,tile in pairs(g_map.getTiles(posz())) do + for i,thing in pairs(tile:getThings()) do + if table.find(depotIDs, thing:getId()) then + table.insert(tileList, {tileObj = tile, distance = getDistanceBetween(pos(), tile:getPosition()), depotID = thing:getId()}) + end + end + end + table.sort(tileList, function(a,b) return a.distance < b.distance end) + ::findEmptyDP:: + if tileList[i] and not storage.stopSearch then + if tileList[i].depotID == 3498 then + tPos = {x = tileList[i].tileObj:getPosition().x + 1, y = tileList[i].tileObj:getPosition().y, z = tileList[i].tileObj:getPosition().z} + elseif tileList[i].depotID == 3499 then + tPos = {x = tileList[i].tileObj:getPosition().x, y = tileList[i].tileObj:getPosition().y + 1, z = tileList[i].tileObj:getPosition().z} + elseif tileList[i].depotID == 3500 then + tPos = {x = tileList[i].tileObj:getPosition().x - 1, y = tileList[i].tileObj:getPosition().y, z = tileList[i].tileObj:getPosition().z} + elseif tileList[i].depotID == 3497 then + tPos = {x = tileList[i].tileObj:getPosition().x, y = tileList[i].tileObj:getPosition().y - 1, z = tileList[i].tileObj:getPosition().z} + end + if tPos then + local dest = g_map.getTile(tPos) + if not comparePosition(pos(), dest:getPosition()) then + if not dest:getCreatures()[1] and dest:isWalkable() then + if autoWalk(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:getSize() 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/vithrax_1.1/combo.otui b/modules/game_bot/default_configs/vithrax_1.1/combo.otui new file mode 100644 index 0000000..b89013a --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/drop items.lua b/modules/game_bot/default_configs/vithrax_1.1/drop items.lua new file mode 100644 index 0000000..ef7b0e1 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/drop items.lua @@ -0,0 +1,29 @@ +setDefaultTab("Cave") + +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.Separator() \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/eat food.lua b/modules/game_bot/default_configs/vithrax_1.1/eat food.lua new file mode 100644 index 0000000..9f0fcb5 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/hunt.otui b/modules/game_bot/default_configs/vithrax_1.1/hunt.otui new file mode 100644 index 0000000..9a28f74 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/hunt.otui @@ -0,0 +1,296 @@ +MonsterLabel < Label + opacity: 0.87 + text-offset: 2 0 + focusable: false + height: 16 + +HuntAnalyser < MiniWindow + !text: tr('Hunt Analyser') + height: 222 + icon: /images/topbuttons/analyzers + &save: true + &autoOpen: false + + MiniWindowContents + Label + id: session + !text: tr('Session:') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + margin-top: 3 + margin-left: 3 + margin-right: 3 + + BotLabel + id: sessionValue + !text: tr('00:00h') + anchors.right: parent.right + anchors.verticalCenter: session.verticalCenter + margin-left: 3 + margin-right: 3 + + HorizontalSeparator + id: separator + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + + Label + id: xpGain + !text: tr('XP Gain:') + anchors.left: parent.left + anchors.top: prev.bottom + margin-top: 3 + margin-left: 3 + + Label + id: xpGainValue + !text: tr('0') + anchors.right: parent.right + anchors.verticalCenter: xpGain.verticalCenter + margin-right: 3 + width: 110 + text-align: right + + HorizontalSeparator + id: separator + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + + Label + id: xpHour + !text: tr('XP/h:') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + margin-left: 3 + margin-right: 3 + + Label + id: xpHourValue + !text: tr('0') + anchors.right: parent.right + anchors.verticalCenter: xpHour.verticalCenter + margin-left: 3 + width: 100 + text-align: right + margin-right: 3 + + HorizontalSeparator + id: separator + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + + Label + id: loot + !text: tr('Loot:') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + margin-left: 3 + margin-right: 3 + + Label + id: lootValue + !text: tr('0') + anchors.right: parent.right + anchors.verticalCenter: loot.verticalCenter + margin-left: 3 + margin-right: 3 + width: 100 + text-align: right + + HorizontalSeparator + id: separator + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + + Label + id: supplies + !text: tr('Supplies:') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + margin-left: 3 + margin-right: 3 + + Label + id: suppliesValue + !text: tr('0') + anchors.right: parent.right + anchors.verticalCenter: supplies.verticalCenter + margin-left: 3 + margin-right: 3 + width: 110 + text-align: right + + HorizontalSeparator + id: separator + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + + Label + id: balance + !text: tr('Balance:') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + margin-left: 3 + margin-right: 3 + + Label + id: balanceValue + !text: tr('0') + anchors.right: parent.right + anchors.verticalCenter: balance.verticalCenter + margin-left: 3 + margin-right: 3 + width: 110 + text-align: right + + HorizontalSeparator + id: separator + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + + Label + id: damage + !text: tr('Damage:') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + margin-left: 3 + margin-right: 3 + + Label + id: damageValue + !text: tr('0') + anchors.right: parent.right + anchors.verticalCenter: damage.verticalCenter + margin-left: 3 + margin-right: 3 + width: 100 + text-align: right + + HorizontalSeparator + id: separator + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + + Label + id: damageHour + !text: tr('Damage/h:') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + margin-left: 3 + margin-right: 3 + + Label + id: damageHourValue + !text: tr('0') + anchors.right: parent.right + anchors.verticalCenter: damageHour.verticalCenter + margin-left: 3 + margin-right: 3 + width: 100 + text-align: right + + HorizontalSeparator + id: separator + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + + Label + id: healing + !text: tr('Healing:') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + margin-left: 3 + margin-right: 3 + + Label + id: healingValue + !text: tr('0') + anchors.right: parent.right + anchors.verticalCenter: healing.verticalCenter + margin-left: 3 + margin-right: 3 + width: 100 + text-align: right + + HorizontalSeparator + id: separator + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + + Label + id: healingHour + !text: tr('Healing/h:') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + margin-left: 3 + margin-right: 3 + + Label + id: healingHourValue + !text: tr('0') + anchors.right: parent.right + anchors.verticalCenter: healingHour.verticalCenter + margin-left: 3 + margin-right: 3 + width: 100 + text-align: right + + HorizontalSeparator + id: separator + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + + Label + id: Label + anchors.top: prev.bottom + anchors.left: parent.left + margin-top: 10 + margin-left: 3 + !text: tr('Monsters Killed:') + + TextList + id: MessagePanel + anchors.top: prev.bottom + anchors.left: parent.left + anchors.right: parent.right + margin-top: 3 + margin-left: 3 + margin-right: 3 + height: 400 \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/impact.otui b/modules/game_bot/default_configs/vithrax_1.1/impact.otui new file mode 100644 index 0000000..be1683e --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/impact.otui @@ -0,0 +1,195 @@ +ImpactAnalyser < MiniWindow + !text: tr('Impact Analyser') + height: 205 + icon: /images/topbuttons/analyzers + &save: true + &autoOpen: false + + MiniWindowContents + Label + id: damageCategory + !text: tr('Damage') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + margin-top: 5 + height: 20 + font: sans-bold-16px + text-align: center + margin-left: 3 + margin-right: 3 + + Label + id: damageTotal + !text: tr('Total:') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 5 + margin-left: 3 + margin-right: 3 + + Label + id: damageValue + !text: tr('0') + anchors.right: parent.right + anchors.verticalCenter: damageTotal.verticalCenter + margin-left: 3 + margin-right: 3 + width: 100 + text-align: right + + HorizontalSeparator + id: separator + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + + Label + id: maxDps + !text: tr('DPS:') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + margin-left: 3 + margin-right: 3 + + Label + id: maxDpsValue + !text: tr('0') + anchors.right: parent.right + anchors.verticalCenter: maxDps.verticalCenter + margin-left: 3 + margin-right: 3 + width: 100 + text-align: right + + HorizontalSeparator + id: separator + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + + Label + id: allTimeHigh + !text: tr('All-Time High:') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + margin-left: 3 + margin-right: 3 + + Label + id: allTimeHighValue + !text: tr('0') + anchors.right: parent.right + anchors.verticalCenter: allTimeHigh.verticalCenter + margin-left: 3 + margin-right: 3 + width: 100 + text-align: right + + HorizontalSeparator + id: separator + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + + Label + id: healingCategory + !text: tr('Healing') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 15 + height: 20 + font: sans-bold-16px + text-align: center + margin-left: 3 + margin-right: 3 + + Label + id: healingTotal + !text: tr('Total:') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 5 + margin-left: 3 + margin-right: 3 + + Label + id: healingValue + !text: tr('0') + anchors.right: parent.right + anchors.verticalCenter: healingTotal.verticalCenter + margin-left: 3 + margin-right: 3 + width: 100 + text-align: right + + HorizontalSeparator + id: separator + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + + Label + id: maxHps + !text: tr('HPS:') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + margin-left: 3 + margin-right: 3 + + Label + id: maxHpsValue + !text: tr('0') + anchors.right: parent.right + anchors.verticalCenter: maxHps.verticalCenter + margin-left: 3 + margin-right: 3 + width: 100 + text-align: right + + HorizontalSeparator + id: separator + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + + Label + id: allTimeHighHeal + !text: tr('All-Time High:') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + margin-left: 3 + margin-right: 3 + + Label + id: allTimeHighHealValue + !text: tr('0') + anchors.right: parent.right + anchors.verticalCenter: allTimeHighHeal.verticalCenter + margin-left: 3 + margin-right: 3 + width: 100 + text-align: right + + HorizontalSeparator + id: separator + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/items.lua b/modules/game_bot/default_configs/vithrax_1.1/items.lua new file mode 100644 index 0000000..c83a7f3 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/items.lua @@ -0,0 +1,1234 @@ +lootitems = { + ["gold coin"] = 1, + ["platinum coin"] = 1000, + ["crystal coin"] = 10000, + ["abyss hammer"] = 20000, + ["acorn"] = 10, + ["albino plate"] = 1500, + ["alloy legs"] = 11000, + ["alptramun's toothbrush"] = 270000, + ["amber"] = 20000, + ["amber staff"] = 8000, + ["amber with a bug"] = 41000, + ["amber with a dragonfly"] = 56000, + ["ancient amulet"] = 200, + ["ancient belt buckle"] = 260, + ["ancient coin"] = 350, + ["ancient liche bone"] = 28000, + ["ancient shield"] = 900, + ["ancient stone"] = 200, + ["angel figurine"] = 36000, + ["angelic axe"] = 5000, + ["ankh"] = 100, + ["antlers"] = 50, + ["ape fur"] = 120, + ["apron"] = 1300, + ["arbalest"] = 42000, + ["arcane staff"] = 42000, + ["assassin dagger"] = 20000, + ["axe"] = 7, + ["axe ring"] = 100, + ["baby seal doll"] = 20000, + ["badger boots"] = 7500, + ["badger fur"] = 15, + ["bamboo stick"] = 30, + ["banana sash"] = 55, + ["banana staff"] = 1000, + ["bandana"] = 150, + ["bar of gold"] = 10000, + ["basalt fetish"] = 210, + ["basalt figurine"] = 160, + ["bast skirt"] = 750, + ["bat decoration"] = 2000, + ["bat wing"] = 50, + ["battle axe"] = 80, + ["battle hammer"] = 120, + ["battle shield"] = 95, + ["battle stone"] = 290, + ["batwing hat"] = 8000, + ["bear paw"] = 100, + ["beast's nightmare-cushion"] = 630000, + ["beastslayer axe"] = 1500, + ["bed of nails"] = 500, + ["beer tap"] = 50, + ["beetle carapace"] = 200, + ["beetle necklace"] = 1500, + ["behemoth claw"] = 2000, + ["behemoth trophy"] = 20000, + ["bejeweled ship's telescope"] = 20000, + ["berserk potion"] = 500, + ["berserker"] = 40000, + ["black hood"] = 190, + ["black pearl"] = 280, + ["black shield"] = 800, + ["black wool"] = 300, + ["blacksteel sword"] = 6000, + ["blade of corruption"] = 60000, + ["blazing bone"] = 610, + ["blessed sceptre"] = 40000, + ["blood preservation"] = 320, + ["blood tincture in a vial"] = 360, + ["bloody dwarven beard"] = 110, + ["bloody edge"] = 30000, + ["bloody pincers"] = 100, + ["bloody tears"] = 70000, + ["blue crystal shard"] = 1500, + ["blue crystal splinter"] = 400, + ["blue gem"] = 5000, + ["blue glass plate"] = 60, + ["blue goanna scale"] = 230, + ["blue legs"] = 15000, + ["blue piece of cloth"] = 200, + ["blue robe"] = 10000, + ["blue rose"] = 250, + ["boggy dreads"] = 200, + ["bola"] = 35, + ["bone club"] = 5, + ["bone fetish"] = 150, + ["bone shield"] = 80, + ["bone shoulderplate"] = 150, + ["bone sword"] = 20, + ["bone toothpick"] = 150, + ["bonebeast trophy3"] = 6000, + ["bonebreaker"] = 10000, + ["bonecarving knife"] = 190, + ["bonelord eye"] = 80, + ["bonelord helmet"] = 2200, + ["bonelord shield"] = 1200, + ["bones of zorvorax"] = 10000, + ["bony tail"] = 210, + ["book of necromantic rituals"] = 180, + ["book of prayers"] = 120, + ["book page"] = 640, + ["boots of haste"] = 30000, + ["bow"] = 100, + ["bowl of terror sweat"] = 500, + ["brain head's giant neuron"] = 100000, + ["brain head's left hemisphere"] = 90000, + ["brain head's right hemisphere"] = 50000, + ["brass armor"] = 150, + ["brass helmet"] = 30, + ["brass legs"] = 49, + ["brass shield"] = 25, + ["bright bell"] = 220, + ["bright sword"] = 6000, + ["brimstone fangs"] = 380, + ["brimstone shell"] = 210, + ["broadsword"] = 500, + ["broken crossbow"] = 30, + ["broken draken mail"] = 340, + ["broken gladiator shield"] = 190, + ["broken halberd"] = 100, + ["broken helmet"] = 20, + ["broken key ring"] = 8000, + ["broken longbow"] = 120, + ["broken ring of ending"] = 4000, + ["broken shamanic staff"] = 35, + ["broken slicer"] = 120, + ["broken throwing axe"] = 230, + ["broken visor"] = 1900, + ["bronze amulet"] = 50, + ["brooch of embracement"] = 14000, + ["brown crystal splinter"] = 400, + ["brown piece of cloth"] = 100, + ["brutetamer's staff"] = 1500, + ["buckle"] = 7000, + ["bullseye potion"] = 500, + ["bunch of ripe rice"] = 75, + ["bunch of troll hair"] = 30, + ["bundle of cursed straw"] = 800, + ["butcher's axe"] = 18000, + ["calopteryx cape"] = 15000, + ["capricious heart"] = 2100, + ["capricious robe"] = 1200, + ["carapace shield"] = 32000, + ["carlin sword"] = 118, + ["carniphila seeds"] = 50, + ["carrion worm fang"] = 35, + ["castle shield"] = 5000, + ["cat's paw"] = 2000, + ["cave devourer eyes"] = 550, + ["cave devourer legs"] = 350, + ["cave devourer maw"] = 600, + ["cavebear skull"] = 550, + ["centipede leg"] = 28, + ["ceremonial ankh"] = 20000, + ["chain armor"] = 70, + ["chain bolter"] = 40000, + ["chain helmet"] = 17, + ["chain legs"] = 25, + ["chaos mace"] = 9000, + ["charmer's tiara"] = 900, + ["chasm spawn abdomen"] = 240, + ["chasm spawn head"] = 850, + ["chasm spawn tail"] = 120, + ["cheese cutter"] = 50, + ["cheesy figurine"] = 150, + ["chicken feather"] = 30, + ["chitinous mouth"] = 10000, + ["claw of 'the noxious spawn'"] = 15000, + ["cliff strider claw"] = 800, + ["closed trap"] = 75, + ["club"] = 1, + ["club ring"] = 100, + ["coal"] = 20, + ["coat"] = 1, + ["cobra crest"] = 650, + ["cobra crown"] = 50000, + ["cobra tongue"] = 15, + ["coconut shoes"] = 500, + ["collar of blue plasma"] = 6000, + ["collar of green plasma"] = 6000, + ["collar of red plasma"] = 6000, + ["colourful feather"] = 110, + ["colourful feathers"] = 400, + ["colourful snail shell"] = 250, + ["compass"] = 45, + ["composite hornbow"] = 25000, + ["compound eye"] = 150, + ["condensed energy"] = 260, + ["copper shield"] = 50, + ["coral brooch"] = 750, + ["corrupted flag"] = 700, + ["countess sorrow's frozen tear"] = 50000, + ["cow bell"] = 120, + ["cowtana"] = 2500, + ["crab pincers"] = 35, + ["cracked alabaster vase"] = 180, + ["cranial basher"] = 30000, + ["crawler head plating"] = 210, + ["crawler's essence"] = 3700, + ["crest of the deep seas"] = 10000, + ["crocodile boots"] = 1000, + ["crossbow"] = 120, + ["crowbar"] = 50, + ["crown"] = 2700, + ["crown armor"] = 12000, + ["crown helmet"] = 2500, + ["crown legs"] = 12000, + ["crown shield"] = 8000, + ["cruelty's chest"] = 720000, + ["cruelty's claw"] = 640000, + ["crunor idol"] = 30000, + ["crusader helmet"] = 6000, + ["crystal bone"] = 250, + ["crystal crossbow"] = 35000, + ["crystal mace"] = 12000, + ["crystal necklace"] = 400, + ["crystal of balance"] = 1000, + ["crystal of focus"] = 2000, + ["crystal of power"] = 3000, + ["crystal pedestal"] = 500, + ["crystal ring"] = 250, + ["crystal sword"] = 600, + ["crystal wand"] = 10000, + ["crystalline armor"] = 16000, + ["crystalline spikes"] = 440, + ["crystallized anger"] = 400, + ["cultish mask"] = 280, + ["cultish robe"] = 150, + ["cultish symbol"] = 500, + ["curious matter"] = 430, + ["cursed bone"] = 6000, + ["cursed shoulder spikes"] = 320, + ["cyan crystal fragment"] = 800, + ["cyclops toe"] = 55, + ["cyclops trophy"] = 500, + ["dagger"] = 2, + ["damaged armor plates"] = 280, + ["damaged worm head"] = 8000, + ["damselfly eye"] = 25, + ["damselfly wing"] = 20, + ["dandelion seeds"] = 200, + ["dangerous proto matter"] = 300, + ["daramian mace"] = 110, + ["daramian waraxe"] = 1000, + ["dark armor"] = 400, + ["dark bell"] = 250, + ["dark helmet"] = 250, + ["dark mushroom"] = 100, + ["dark rosary"] = 48, + ["dark shield"] = 400, + ["dead rat"] = 1, + ["dead weight"] = 450, + ["death ring"] = 1000, + ["deepling axe"] = 40000, + ["deepling breaktime snack"] = 90, + ["deepling claw"] = 430, + ["deepling guard belt buckle"] = 230, + ["deepling ridge"] = 360, + ["deepling scales"] = 80, + ["deepling squelcher"] = 7000, + ["deepling staff"] = 4000, + ["deepling warts"] = 180, + ["deeptags"] = 290, + ["deepworm jaws"] = 500, + ["deepworm spike roots"] = 650, + ["deepworm spikes"] = 800, + ["deer trophy3"] = 3000, + ["demon dust"] = 300, + ["demon helmet"] = 40000, + ["demon horn"] = 1000, + ["demon shield"] = 30000, + ["demon trophy"] = 40000, + ["demonbone amulet"] = 32000, + ["demonic essence"] = 1000, + ["demonic finger"] = 1000, + ["demonic skeletal hand"] = 80, + ["demonrage sword"] = 36000, + ["depth calcei"] = 25000, + ["depth galea"] = 35000, + ["depth lorica"] = 30000, + ["depth ocrea"] = 16000, + ["depth scutum"] = 36000, + ["devil helmet"] = 1000, + ["diabolic skull"] = 19000, + ["diamond"] = 15000, + ["diamond sceptre"] = 3000, + ["diremaw brainpan"] = 350, + ["diremaw legs"] = 270, + ["dirty turban"] = 120, + ["disgusting trophy"] = 3000, + ["distorted heart"] = 2100, + ["distorted robe"] = 1200, + ["divine plate"] = 55000, + ["djinn blade"] = 15000, + ["doll"] = 200, + ["double axe"] = 260, + ["doublet"] = 3, + ["downy feather"] = 20, + ["dowser"] = 35, + ["drachaku"] = 10000, + ["dracola's eye"] = 50000, + ["dracoyle statue"] = 5000, + ["dragon blood"] = 700, + ["dragon claw"] = 8000, + ["dragon figurine"] = 45000, + ["dragon hammer"] = 2000, + ["dragon lance"] = 9000, + ["dragon lord trophy"] = 10000, + ["dragon necklace"] = 100, + ["dragon priest's wandtip"] = 175, + ["dragon robe"] = 50000, + ["dragon scale mail"] = 40000, + ["dragon shield"] = 4000, + ["dragon slayer"] = 15000, + ["dragon tongue"] = 550, + ["dragonbone staff"] = 3000, + ["dragon's tail"] = 100, + ["draken boots"] = 40000, + ["draken sulphur"] = 550, + ["draken trophy"] = 15000, + ["draken wristbands"] = 430, + ["drakinata"] = 10000, + ["draptor scales"] = 800, + ["dreaded cleaver"] = 10000, + ["dream essence egg"] = 205, + ["dung ball"] = 130, + ["dwarven armor"] = 30000, + ["dwarven axe"] = 1500, + ["dwarven legs"] = 40000, + ["dwarven ring"] = 100, + ["dwarven shield"] = 100, + ["earflap"] = 40, + ["earth blacksteel sword"] = 6000, + ["earth cranial basher"] = 30000, + ["earth crystal mace"] = 12000, + ["earth dragon slayer"] = 15000, + ["earth headchopper"] = 6000, + ["earth heroic axe"] = 30000, + ["earth knight axe"] = 2000, + ["earth mystic blade"] = 30000, + ["earth orcish maul"] = 6000, + ["earth relic sword"] = 25000, + ["earth spike sword"] = 1000, + ["earth war axe"] = 12000, + ["earth war hammer"] = 1200, + ["ectoplasmic sushi"] = 300, + ["egg of the many"] = 15000, + ["elder bonelord tentacle"] = 150, + ["elite draken mail"] = 50000, + ["elven amulet"] = 100, + ["elven astral observer"] = 90, + ["elven hoof"] = 115, + ["elven scouting glass"] = 50, + ["elvish bow"] = 2000, + ["elvish talisman"] = 45, + ["emerald bangle"] = 800, + ["empty honey glass"] = 270, + ["empty potion flask"] = 5, + ["enchanted chicken wing"] = 20000, + ["energy ball"] = 300, + ["energy blacksteel sword"] = 6000, + ["energy cranial basher"] = 30000, + ["energy crystal mace"] = 12000, + ["energy dragon slayer"] = 15000, + ["energy headchopper"] = 6000, + ["energy heroic axe"] = 30000, + ["energy knight axe"] = 2000, + ["energy mystic blade"] = 30000, + ["energy orcish maul"] = 6000, + ["energy relic sword"] = 25000, + ["energy ring"] = 100, + ["energy spike sword"] = 1000, + ["energy vein"] = 270, + ["energy war axe"] = 12000, + ["energy war hammer"] = 1200, + ["ensouled essence"] = 820, + ["epee"] = 8000, + ["essence of a bad dream"] = 360, + ["ethno coat"] = 200, + ["execowtioner axe"] = 12000, + ["executioner"] = 55000, + ["explorer brooch"] = 50, + ["eye of a deepling"] = 150, + ["eye of a weeper"] = 650, + ["eye of corruption"] = 390, + ["fafnar symbol"] = 950, + ["fairy wings"] = 200, + ["falcon crest"] = 650, + ["feather headdress"] = 850, + ["fern"] = 20, + ["fiery blacksteel sword"] = 6000, + ["fiery cranial basher"] = 30000, + ["fiery crystal mace"] = 12000, + ["fiery dragon slayer"] = 15000, + ["fiery headchopper"] = 6000, + ["fiery heart"] = 375, + ["fiery heroic axe"] = 30000, + ["fiery knight axe"] = 2000, + ["fiery mystic blade"] = 30000, + ["fiery orcish maul"] = 6000, + ["fiery relic sword"] = 25000, + ["fiery spike sword"] = 1000, + ["fiery war axe"] = 12000, + ["fiery war hammer"] = 1200, + ["fig leaf"] = 200, + ["figurine of cruelty"] = 3100000, + ["figurine of greed"] = 2900000, + ["figurine of hatred"] = 2700000, + ["figurine of malice"] = 2800000, + ["figurine of megalomania"] = 5000000, + ["figurine of spite"] = 3000000, + ["fir cone"] = 25, + ["fire axe"] = 8000, + ["fire mushroom"] = 200, + ["fire sword"] = 1000, + ["fish fin"] = 150, + ["fishing rod"] = 40, + ["flask of embalming fluid"] = 30, + ["flask of warrior's sweat"] = 10000, + ["flintstone"] = 800, + ["flower dress"] = 1000, + ["flower wreath"] = 500, + ["focus cape"] = 6000, + ["fox paw"] = 100, + ["frazzle skin"] = 400, + ["frazzle tongue"] = 700, + ["frost giant pelt"] = 160, + ["frosty ear of a troll"] = 30, + ["frosty heart"] = 280, + ["frozen lightning"] = 270, + ["frozen starlight"] = 20000, + ["fur armor"] = 5000, + ["fur boots"] = 2000, + ["fur shred"] = 200, + ["furry club"] = 1000, + ["garlic necklace"] = 50, + ["gauze bandage"] = 90, + ["gear crystal"] = 200, + ["gear wheel"] = 500, + ["gearwheel chain"] = 5000, + ["gemmed figurine"] = 3500, + ["geomancer's robe"] = 80, + ["geomancer's staff"] = 120, + ["ghastly dragon head"] = 700, + ["ghostly tissue"] = 90, + ["ghoul snack"] = 60, + ["giant amethyst"] = 60000, + ["giant crab pincer"] = 950, + ["giant emerald"] = 90000, + ["giant eye"] = 380, + ["giant ruby"] = 70000, + ["giant sapphire"] = 50000, + ["giant shimmering pearl"] = 3000, + ["giant smithhammer"] = 250, + ["giant sword"] = 17000, + ["giant tentacle"] = 10000, + ["giant topaz"] = 80000, + ["girlish hair decoration"] = 30, + ["glacial rod"] = 6500, + ["glacier amulet"] = 1500, + ["glacier kilt"] = 11000, + ["glacier mask"] = 2500, + ["glacier robe"] = 11000, + ["glacier shoes"] = 2500, + ["gland"] = 500, + ["glistening bone"] = 250, + ["glob of acid slime"] = 25, + ["glob of mercury"] = 20, + ["glob of tar"] = 30, + ["gloom wolf fur"] = 70, + ["glooth amulet"] = 2000, + ["glooth axe"] = 1500, + ["glooth blade"] = 1500, + ["glooth cape"] = 7000, + ["glooth club"] = 1500, + ["glooth whip"] = 2500, + ["glorious axe"] = 3000, + ["glowing rune"] = 350, + ["goanna claw"] = 260, + ["goanna meat"] = 190, + ["goat grass"] = 50, + ["goblet of gloom"] = 12000, + ["goblin ear"] = 20, + ["gold ingot"] = 5000, + ["gold nugget"] = 850, + ["gold ring"] = 8000, + ["golden amulet"] = 2000, + ["golden armor"] = 20000, + ["golden brush"] = 250, + ["golden fafnar trophy"] = 10000, + ["golden figurine"] = 3000, + ["golden legs"] = 30000, + ["golden lotus brooch"] = 270, + ["golden mask"] = 38000, + ["golden mug"] = 250, + ["golden sickle"] = 1000, + ["goo shell"] = 4000, + ["goosebump leather"] = 650, + ["grant of arms"] = 950, + ["grasshopper legs"] = 15000, + ["grave flower"] = 25, + ["greed's arm"] = 950000, + ["green bandage"] = 180, + ["green crystal fragment"] = 800, + ["green crystal shard"] = 1500, + ["green crystal splinter"] = 400, + ["green dragon leather"] = 100, + ["green dragon scale"] = 100, + ["green gem"] = 5000, + ["green glass plate"] = 180, + ["green mushroom"] = 100, + ["green piece of cloth"] = 200, + ["greenwood coat"] = 50000, + ["griffin shield"] = 3000, + ["grimace"] = 120000, + ["gruesome fan"] = 15000, + ["guardian axe"] = 9000, + ["guardian boots"] = 35000, + ["guardian halberd"] = 11000, + ["guardian shield"] = 2000, + ["guidebook"] = 200, + ["hailstorm rod"] = 3000, + ["hair of a banshee"] = 350, + ["halberd"] = 400, + ["half-digested piece of meat"] = 55, + ["half-digested stones"] = 40, + ["half-eaten brain"] = 85, + ["ham"] = 4, + ["hammer of wrath"] = 30000, + ["hand"] = 1450, + ["hand axe"] = 4, + ["hardened bone"] = 70, + ["harpoon of a giant snail"] = 15000, + ["hatched rorc egg"] = 30, + ["hatchet"] = 25, + ["haunted blade"] = 8000, + ["haunted piece of wood"] = 115, + ["hazardous heart"] = 5000, + ["hazardous robe"] = 3000, + ["head"] = 3500, + ["headchopper"] = 6000, + ["heat core"] = 10000, + ["heaven blossom"] = 50, + ["heavy mace"] = 50000, + ["heavy machete"] = 90, + ["heavy trident"] = 2000, + ["hellhound slobber"] = 500, + ["hellspawn tail"] = 475, + ["helmet of the lost"] = 2000, + ["hemp rope"] = 350, + ["heroic axe"] = 30000, + ["hexagonal ruby"] = 30000, + ["hibiscus dress"] = 3000, + ["hideous chunk"] = 510, + ["hieroglyph banner"] = 500, + ["high guard flag"] = 550, + ["high guard shoulderplates"] = 130, + ["hive bow"] = 28000, + ["hive scythe"] = 17000, + ["hollow stampor hoof"] = 400, + ["holy ash"] = 160, + ["holy orchid"] = 90, + ["honeycomb"] = 40, + ["horn"] = 300, + ["horn of kalyassa"] = 10000, + ["horoscope"] = 40, + ["horseman helmet"] = 280, + ["huge chunk of crude iron"] = 15000, + ["huge shell"] = 15000, + ["huge spiky snail shell"] = 8000, + ["humongous chunk"] = 540, + ["hunter's quiver"] = 80, + ["hunting spear"] = 25, + ["hydra egg"] = 500, + ["hydra head"] = 600, + ["ice flower"] = 370, + ["ice rapier"] = 1000, + ["icy blacksteel sword"] = 6000, + ["icy cranial basher"] = 30000, + ["icy crystal mace"] = 12000, + ["icy dragon slayer"] = 15000, + ["icy headchopper"] = 6000, + ["icy heroic axe"] = 30000, + ["icy knight axe"] = 2000, + ["icy mystic blade"] = 30000, + ["icy orcish maul"] = 6000, + ["icy relic sword"] = 25000, + ["icy spike sword"] = 1000, + ["icy war axe"] = 12000, + ["icy war hammer"] = 1200, + ["incantation notes"] = 90, + ["infernal heart"] = 2100, + ["infernal robe"] = 1200, + ["inkwell"] = 8, + ["instable proto matter"] = 300, + ["iron helmet"] = 150, + ["iron ore"] = 500, + ["ivory carving"] = 300, + ["ivory comb"] = 8000, + ["izcandar's snow globe"] = 180000, + ["izcandar's sundial"] = 225000, + ["jacket"] = 1, + ["jade hammer"] = 25000, + ["jade hat"] = 9000, + ["jagged sickle"] = 150000, + ["jaws"] = 3900, + ["jewelled belt"] = 180, + ["katana"] = 35, + ["katex' blood"] = 210, + ["key to the drowned library"] = 330, + ["knight armor"] = 5000, + ["knight axe"] = 2000, + ["knight legs"] = 5000, + ["kollos shell"] = 420, + ["kongra's shoulderpad"] = 100, + ["krimhorn helmet"] = 200, + ["lamassu hoof"] = 330, + ["lamassu horn"] = 240, + ["lancer beetle shell"] = 80, + ["lancet"] = 90, + ["lavos armor"] = 16000, + ["leaf legs"] = 500, + ["leather armor"] = 12, + ["leather boots"] = 2, + ["leather harness"] = 750, + ["leather helmet"] = 4, + ["leather legs"] = 9, + ["legion helmet"] = 22, + ["legionnaire flags"] = 500, + ["leopard armor"] = 300, + ["leviathan's amulet"] = 3000, + ["life crystal"] = 50, + ["life preserver"] = 300, + ["life ring"] = 50, + ["light shovel"] = 300, + ["lightning boots"] = 2500, + ["lightning headband"] = 2500, + ["lightning legs"] = 11000, + ["lightning pendant"] = 1500, + ["lightning robe"] = 11000, + ["lion cloak patch"] = 190, + ["lion crest"] = 270, + ["lion figurine"] = 10000, + ["lion seal"] = 210, + ["lion trophy3"] = 3000, + ["lion's mane"] = 60, + ["little bowl of myrrh"] = 500, + ["lizard essence"] = 300, + ["lizard heart"] = 530, + ["lizard leather"] = 150, + ["lizard scale"] = 120, + ["lizard trophy"] = 8000, + ["longing eyes"] = 8000, + ["longsword"] = 51, + ["lost basher's spike"] = 280, + ["lost bracers"] = 140, + ["lost husher's staff"] = 250, + ["lost soul"] = 120, + ["luminescent crystal pickaxe"] = 50, + ["luminous orb"] = 1000, + ["lump of dirt"] = 10, + ["lump of earth"] = 130, + ["lunar staff"] = 5000, + ["mace"] = 30, + ["machete"] = 6, + ["mad froth"] = 80, + ["magic light wand"] = 35, + ["magic plate armor"] = 90000, + ["magic sulphur"] = 8000, + ["magma amulet"] = 1500, + ["magma boots"] = 2500, + ["magma clump"] = 570, + ["magma coat"] = 11000, + ["magma legs"] = 11000, + ["magma monocle"] = 2500, + ["malice's horn"] = 620000, + ["malice's spine"] = 850000, + ["malofur's lunchbox"] = 240000, + ["mammoth fur cape"] = 6000, + ["mammoth fur shorts"] = 850, + ["mammoth tusk"] = 100, + ["mammoth whopper"] = 300, + ["mantassin tail"] = 280, + ["manticore ear"] = 310, + ["manticore tail"] = 220, + ["marlin trophy"] = 5000, + ["marsh stalker beak"] = 65, + ["marsh stalker feather"] = 50, + ["mastermind potion"] = 500, + ["mastermind shield"] = 50000, + ["maxilla"] = 250, + ["maxxenius head"] = 500000, + ["meat"] = 2, + ["meat hammer"] = 60, + ["medal of valiance"] = 410000, + ["medusa shield"] = 9000, + ["megalomania's essence"] = 1900000, + ["megalomania's skull"] = 1500000, + ["mercenary sword"] = 12000, + ["metal bat"] = 9000, + ["metal spats"] = 2000, + ["metal spike"] = 320, + ["might ring"] = 250, + ["milk churn"] = 100, + ["mind stone"] = 100, + ["mino lance"] = 7000, + ["mino shield"] = 3000, + ["minotaur horn"] = 75, + ["minotaur leather"] = 80, + ["minotaur trophy"] = 500, + ["miraculum"] = 60, + ["mirror"] = 10, + ["model ship"] = 1000, + ["modified crossbow"] = 10000, + ["mooh'tah plate"] = 6000, + ["moohtant cudgel"] = 14000, + ["moonlight rod"] = 200, + ["moonstone"] = 13000, + ["morbid tapestry"] = 30000, + ["morgaroth's heart"] = 15000, + ["morning star"] = 100, + ["mould heart"] = 2100, + ["mould robe"] = 1200, + ["mr. punish's handcuffs"] = 50000, + ["muck rod"] = 6000, + ["mucus plug"] = 500, + ["mutated bat ear"] = 420, + ["mutated flesh"] = 50, + ["mutated rat tail"] = 150, + ["mycological bow"] = 35000, + ["mysterious fetish"] = 50, + ["mystic blade"] = 30000, + ["mystic turban"] = 150, + ["mystical hourglass"] = 700, + ["naginata"] = 2000, + ["necklace of the deep"] = 3000, + ["necromantic robe"] = 250, + ["necrotic rod"] = 1000, + ["nettle blossom"] = 75, + ["nettle spit"] = 25, + ["nightmare blade"] = 35000, + ["noble amulet"] = 430000, + ["noble armor"] = 900, + ["noble axe"] = 10000, + ["noble cape"] = 425000, + ["noble turban"] = 430, + ["norse shield"] = 1500, + ["northwind rod"] = 1500, + ["nose ring"] = 2000, + ["obsidian lance"] = 500, + ["odd organ"] = 410, + ["ogre ear stud"] = 180, + ["ogre nose ring"] = 210, + ["old parchment"] = 500, + ["onyx chip"] = 500, + ["onyx flail"] = 22000, + ["onyx pendant"] = 3500, + ["opal"] = 500, + ["orange mushroom"] = 150, + ["orb"] = 750, + ["orc leather"] = 30, + ["orc tooth"] = 150, + ["orc trophy3"] = 1000, + ["orcish axe"] = 350, + ["orcish gear"] = 85, + ["orcish maul"] = 6000, + ["orichalcum pearl"] = 40, + ["oriental shoes"] = 15000, + ["ornamented axe"] = 20000, + ["ornamented shield"] = 1500, + ["ornate chestplate"] = 60000, + ["ornate crossbow"] = 12000, + ["ornate legs"] = 40000, + ["ornate locket"] = 18000, + ["ornate mace"] = 42000, + ["ornate shield"] = 42000, + ["orshabaal's brain"] = 12000, + ["pair of hellflayer horns"] = 1300, + ["pair of iron fists"] = 4000, + ["pair of old bracers"] = 500, + ["paladin armor"] = 15000, + ["pale worm's scalp"] = 489000, + ["panda teddy"] = 30000, + ["panther head"] = 750, + ["panther paw"] = 300, + ["patch of fine cloth"] = 1350, + ["patched boots"] = 2000, + ["peacock feather fan"] = 350, + ["pelvis bone"] = 30, + ["perfect behemoth fang"] = 250, + ["pet pig"] = 1500, + ["petrified scream"] = 250, + ["phantasmal hair"] = 500, + ["pharaoh banner"] = 1000, + ["pharaoh sword"] = 23000, + ["phoenix shield"] = 16000, + ["pick"] = 15, + ["piece of archer armor"] = 20, + ["piece of crocodile leather"] = 15, + ["piece of dead brain"] = 420, + ["piece of draconian steel"] = 3000, + ["piece of hell steel"] = 500, + ["piece of hellfire armor"] = 550, + ["piece of massacre's shell"] = 50000, + ["piece of royal steel"] = 10000, + ["piece of scarab shell"] = 45, + ["piece of swampling wood"] = 30, + ["piece of warrior armor"] = 50, + ["pieces of magic chalk"] = 210, + ["pig foot"] = 10, + ["pile of grave earth"] = 25, + ["pirate boots"] = 3000, + ["pirate hat"] = 1000, + ["pirate knee breeches"] = 200, + ["pirate shirt"] = 500, + ["pirate voodoo doll"] = 500, + ["plagueroot offshoot"] = 280000, + ["plasma pearls"] = 250, + ["plasmatic lightning"] = 270, + ["plate armor"] = 400, + ["plate legs"] = 115, + ["plate shield"] = 45, + ["platinum amulet"] = 2500, + ["poison dagger"] = 50, + ["poison gland"] = 210, + ["poison spider shell"] = 10, + ["poisonous slime"] = 50, + ["polar bear paw"] = 30, + ["pool of chitinous glue"] = 480, + ["porcelain mask"] = 2000, + ["powder herb"] = 10, + ["power ring"] = 50, + ["prismatic quartz"] = 450, + ["pristine worm head"] = 15000, + ["protection amulet"] = 100, + ["protective charm"] = 60, + ["pulverized ore"] = 400, + ["purified soul"] = 530, + ["purple robe"] = 110, + ["purple tome"] = 2000, + ["quara bone"] = 500, + ["quara eye"] = 350, + ["quara pincers"] = 410, + ["quara tentacle"] = 140, + ["queen's sceptre"] = 20000, + ["quill"] = 1100, + ["rabbit's foot"] = 50, + ["ragnir helmet"] = 400, + ["rainbow quartz"] = 500, + ["rapier"] = 5, + ["rare earth"] = 80, + ["ratana"] = 500, + ["ravenous circlet"] = 220000, + ["red crystal fragment"] = 800, + ["red dragon leather"] = 200, + ["red dragon scale"] = 200, + ["red gem"] = 1000, + ["red goanna scale"] = 270, + ["red hair dye"] = 40, + ["red lantern"] = 250, + ["red piece of cloth"] = 300, + ["red tome"] = 2000, + ["relic sword"] = 25000, + ["rhino hide"] = 175, + ["rhino horn"] = 265, + ["rhino horn carving"] = 300, + ["rift bow"] = 45000, + ["rift crossbow"] = 45000, + ["rift lance"] = 30000, + ["rift shield"] = 50000, + ["ring of blue plasma"] = 8000, + ["ring of green plasma"] = 8000, + ["ring of healing"] = 100, + ["ring of red plasma"] = 8000, + ["ring of the sky"] = 30000, + ["ripper lance"] = 500, + ["rod"] = 2200, + ["roots"] = 1200, + ["rope"] = 15, + ["rope belt"] = 66, + ["rorc egg"] = 120, + ["rorc feather"] = 70, + ["rotten heart"] = 74000, + ["rotten piece of cloth"] = 30, + ["royal axe"] = 40000, + ["royal helmet"] = 30000, + ["royal tapestry"] = 1000, + ["rubber cap"] = 11000, + ["ruby necklace"] = 2000, + ["runed sword"] = 45000, + ["ruthless axe"] = 45000, + ["sabre"] = 12, + ["sabretooth"] = 400, + ["sacred tree amulet"] = 3000, + ["safety pin"] = 120, + ["sai"] = 16500, + ["salamander shield"] = 280, + ["sample of monster blood"] = 250, + ["sandcrawler shell"] = 20, + ["sapphire hammer"] = 7000, + ["scale armor"] = 75, + ["scale of corruption"] = 680, + ["scale of gelidrazah"] = 10000, + ["scarab amulet"] = 200, + ["scarab pincers"] = 280, + ["scarab shield"] = 2000, + ["scimitar"] = 150, + ["scorpion tail"] = 25, + ["scroll of heroic deeds"] = 230, + ["scythe"] = 10, + ["scythe leg"] = 450, + ["sea horse figurine"] = 42000, + ["sea serpent scale"] = 520, + ["sea serpent trophy"] = 10000, + ["seeds"] = 150, + ["sentinel shield"] = 120, + ["serpent sword"] = 900, + ["shadow herb"] = 20, + ["shadow sceptre"] = 10000, + ["shaggy tail"] = 25, + ["shamanic hood"] = 45, + ["shamanic talisman"] = 200, + ["shard"] = 2000, + ["shimmering beetles"] = 150, + ["shiny stone"] = 500, + ["shockwave amulet"] = 3000, + ["short sword"] = 10, + ["shovel"] = 8, + ["sickle"] = 3, + ["sight of surrender's eye"] = 3000, + ["signet ring"] = 480000, + ["silencer claws"] = 390, + ["silencer resonating chamber"] = 600, + ["silken bookmark"] = 1300, + ["silkweaver bow"] = 12000, + ["silky fur"] = 35, + ["silver amulet"] = 50, + ["silver brooch"] = 150, + ["silver dagger"] = 500, + ["silver fafnar trophy"] = 1000, + ["silver hand mirror"] = 10000, + ["simple dress"] = 50, + ["single human eye"] = 1000, + ["skeleton decoration"] = 3000, + ["skull belt"] = 80, + ["skull coin"] = 12000, + ["skull fetish"] = 250, + ["skull helmet"] = 40000, + ["skull of ratha"] = 250, + ["skull shatterer"] = 170, + ["skull staff"] = 6000, + ["skullcracker armor"] = 18000, + ["skunk tail"] = 50, + ["slime mould"] = 175, + ["slimy leg"] = 4500, + ["sling herb"] = 10, + ["small amethyst"] = 200, + ["small axe"] = 5, + ["small diamond"] = 300, + ["small emerald"] = 250, + ["small enchanted amethyst"] = 200, + ["small enchanted emerald"] = 250, + ["small enchanted ruby"] = 250, + ["small enchanted sapphire"] = 250, + ["small energy ball"] = 250, + ["small flask of eyedrops"] = 95, + ["small notebook"] = 480, + ["small oil lamp"] = 150, + ["small pitchfork"] = 70, + ["small ruby"] = 250, + ["small sapphire"] = 250, + ["small topaz"] = 200, + ["snake skin"] = 400, + ["snakebite rod"] = 100, + ["sniper gloves"] = 2000, + ["soldier helmet"] = 16, + ["solid rage"] = 310, + ["some grimeleech wings"] = 1200, + ["soul orb"] = 25, + ["soul stone"] = 6000, + ["souleater trophy"] = 7500, + ["spark sphere"] = 350, + ["sparkion claw"] = 290, + ["sparkion legs"] = 310, + ["sparkion stings"] = 280, + ["sparkion tail"] = 300, + ["spear"] = 3, + ["spectral gold nugget"] = 500, + ["spectral silver nugget"] = 250, + ["spellsinger's seal"] = 280, + ["spellweaver's robe"] = 12000, + ["sphinx feather"] = 470, + ["sphinx tiara"] = 360, + ["spider fangs"] = 10, + ["spider silk"] = 100, + ["spidris mandible"] = 450, + ["spike shield"] = 250, + ["spike sword"] = 240, + ["spiked iron ball"] = 100, + ["spiked squelcher"] = 5000, + ["spiky club"] = 300, + ["spirit cloak"] = 350, + ["spirit container"] = 40000, + ["spite's spirit"] = 840000, + ["spitter nose"] = 340, + ["spooky blue eye"] = 95, + ["spool of yarn"] = 1000, + ["springsprout rod"] = 3600, + ["srezz' eye"] = 300, + ["stampor horn"] = 280, + ["stampor talons"] = 150, + ["star amulet"] = 500, + ["star herb"] = 15, + ["statue of abyssador"] = 4000, + ["statue of deathstrike"] = 3000, + ["statue of devovorga"] = 1500, + ["statue of gnomevil"] = 2000, + ["stealth ring"] = 200, + ["steel boots"] = 30000, + ["steel helmet"] = 293, + ["steel shield"] = 80, + ["stone herb"] = 20, + ["stone nose"] = 590, + ["stone skin amulet"] = 500, + ["stone wing"] = 120, + ["stonerefiner's skull"] = 100, + ["strand of medusa hair"] = 600, + ["strange helmet"] = 500, + ["strange proto matter"] = 300, + ["strange symbol"] = 200, + ["strange talisman"] = 30, + ["striped fur"] = 50, + ["studded armor"] = 25, + ["studded club"] = 10, + ["studded helmet"] = 20, + ["studded legs"] = 15, + ["studded shield"] = 16, + ["stuffed dragon"] = 6000, + ["sulphurous stone"] = 100, + ["swamp grass"] = 20, + ["swamplair armor"] = 16000, + ["swampling club"] = 40, + ["swampling moss"] = 20, + ["swarmer antenna"] = 130, + ["sword"] = 25, + ["sword ring"] = 100, + ["tail of corruption"] = 240, + ["talon"] = 320, + ["tarantula egg"] = 80, + ["tarnished rhino figurine"] = 320, + ["tattered piece of robe"] = 120, + ["taurus mace"] = 500, + ["telescope eye"] = 1600, + ["tempest shield"] = 35000, + ["templar scytheblade"] = 200, + ["tentacle piece"] = 5000, + ["terra amulet"] = 1500, + ["terra boots"] = 2500, + ["terra hood"] = 2500, + ["terra legs"] = 11000, + ["terra mantle"] = 11000, + ["terra rod"] = 2000, + ["terramite eggs"] = 50, + ["terramite legs"] = 60, + ["terramite shell"] = 170, + ["terrorbird beak"] = 95, + ["thaian sword"] = 16000, + ["the avenger"] = 42000, + ["the handmaiden's protector"] = 50000, + ["the imperor's trident"] = 50000, + ["the ironworker"] = 50000, + ["the justice seeker"] = 40000, + ["the plasmother's remains"] = 50000, + ["thick fur"] = 150, + ["thorn"] = 100, + ["throwing knife"] = 2, + ["tiger eye"] = 350, + ["time ring"] = 100, + ["titan axe"] = 4000, + ["token of love"] = 440000, + ["tooth file"] = 60, + ["tooth of tazhadur"] = 10000, + ["torn shirt"] = 250, + ["tortoise shield"] = 150, + ["tower shield"] = 8000, + ["trapped bad dream monster"] = 900, + ["trashed draken boots"] = 40000, + ["tribal mask"] = 250, + ["troll green"] = 25, + ["trollroot"] = 50, + ["trophy of jaul"] = 4000, + ["trophy of obujos"] = 3000, + ["trophy of tanjis"] = 2000, + ["tunnel tyrant head"] = 500, + ["tunnel tyrant shell"] = 700, + ["turtle shell"] = 90, + ["tusk"] = 100, + ["tusk shield"] = 850, + ["twiceslicer"] = 28000, + ["twin hooks"] = 500, + ["two handed sword"] = 450, + ["undead heart"] = 200, + ["underworld rod"] = 4400, + ["unholy bone"] = 480, + ["unholy book"] = 30000, + ["unicorn figurine"] = 50000, + ["urmahlullu's mane"] = 490000, + ["urmahlullu's paw"] = 245000, + ["urmahlullu's tail"] = 210000, + ["utua's poison"] = 230, + ["vampire dust"] = 100, + ["vampire shield"] = 15000, + ["vampire teeth"] = 275, + ["vampire's cape chain"] = 150, + ["veal"] = 40, + ["vein of ore"] = 330, + ["velvet tapestry"] = 800, + ["venison"] = 55, + ["vexclaw talon"] = 1100, + ["vial"] = 5, + ["vial of hatred"] = 737000, + ["vibrant heart"] = 2100, + ["vibrant robe"] = 1200, + ["viking helmet"] = 66, + ["viking shield"] = 85, + ["vile axe"] = 30000, + ["violet crystal shard"] = 1500, + ["violet gem"] = 10000, + ["violet glass plate"] = 2150, + ["volatile proto matter"] = 300, + ["voodoo doll"] = 400, + ["wailing widow's necklace"] = 3000, + ["walnut"] = 80, + ["wand of cosmic energy"] = 2000, + ["wand of decay"] = 1000, + ["wand of defiance"] = 6500, + ["wand of draconia"] = 1500, + ["wand of dragonbreath"] = 200, + ["wand of everblazing"] = 6000, + ["wand of inferno"] = 3000, + ["wand of starstorm"] = 3600, + ["wand of voodoo"] = 4400, + ["wand of vortex"] = 100, + ["war axe"] = 12000, + ["war crystal"] = 460, + ["war hammer"] = 470, + ["war horn"] = 8000, + ["warmaster's wristguards"] = 200, + ["warrior helmet"] = 5000, + ["warrior's axe"] = 11000, + ["warrior's shield"] = 9000, + ["warwolf fur"] = 30, + ["waspoid claw"] = 320, + ["waspoid wing"] = 190, + ["watch"] = 6, + ["watermelon tourmaline"] = 30000, + ["weaver's wandtip"] = 250, + ["wedding ring"] = 100, + ["werebadger claws"] = 160, + ["werebadger skull"] = 185, + ["werebadger trophy"] = 9000, + ["werebear fur"] = 185, + ["werebear skull"] = 195, + ["werebear trophy"] = 11000, + ["wereboar hooves"] = 175, + ["wereboar loincloth"] = 1500, + ["wereboar trophy"] = 10000, + ["wereboar tusks"] = 165, + ["werefox tail"] = 200, + ["werefox trophy"] = 9000, + ["werehyaena nose"] = 220, + ["werehyaena talisman"] = 350, + ["werehyaena trophy"] = 12000, + ["werewolf amulet"] = 3000, + ["werewolf fangs"] = 180, + ["werewolf fur"] = 380, + ["white deer antlers"] = 400, + ["white deer skin"] = 245, + ["white gem"] = 12000, + ["white pearl"] = 160, + ["white piece of cloth"] = 100, + ["white silk flower"] = 9000, + ["widow's mandibles"] = 110, + ["wild flowers"] = 120, + ["wimp tooth chain"] = 120, + ["windborn colossus armor"] = 50000, + ["winged tail"] = 800, + ["winter wolf fur"] = 20, + ["witch broom"] = 60, + ["witch hat"] = 5000, + ["withered pauldrons"] = 850, + ["withered scalp"] = 900, + ["wolf paw"] = 70, + ["wolf tooth chain"] = 100, + ["wolf trophy"] = 3000, + ["wood"] = 5, + ["wood mushroom"] = 15, + ["wooden hammer"] = 15, + ["wooden shield"] = 5, + ["wool"] = 15, + ["writhing brain"] = 370000, + ["writhing heart"] = 185000, + ["wyrm scale"] = 400, + ["wyvern fang"] = 1500, + ["wyvern talisman"] = 265, + ["yellow gem"] = 1000, + ["yellow piece of cloth"] = 150, + ["yielocks"] = 600, + ["yielowax"] = 600, + ["yirkas' egg"] = 280, + ["young lich worm"] = 25000, + ["zaoan armor"] = 14000, + ["zaoan halberd"] = 500, + ["zaoan helmet"] = 45000, + ["zaoan legs"] = 14000, + ["zaoan robe"] = 12000, + ["zaoan shoes"] = 5000, + ["zaoan sword"] = 30000, + ["zaogun flag"] = 600, + ["zaogun shoulderplates"] = 150, + -- supplies + ["mana potion"] = 56, + ["strong mana potion"] = 93, + ["great mana potion"] = 144, + ["ultimate mana potion"] = 438, + ["health potion"] = 50, + ["strong health potion"] = 115, + ["great health potion"] = 225, + ["ultimate health potion"] = 379, + ["supreme health potion"] = 625, + ["great spirit potion"] = 228, + ["ultimate spirit potion"] = 438 +} \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/jewellery equipper.lua b/modules/game_bot/default_configs/vithrax_1.1/jewellery equipper.lua new file mode 100644 index 0000000..f8d0129 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/jewellery equipper.lua @@ -0,0 +1,319 @@ +setDefaultTab("HP") +function jewelleryEquip() + panelName = "jewelleryEquipper" + + local ui = setupUI([[ +Panel + height: 130 + 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 + + Button + id: resetDefault + anchors.top: ammyScroll2.bottom + anchors.left: parent.left + anchors.right: parent.horizontalCenter + margin-top: 8 + margin-left: 2 + text: Reset Default + + SmallBotSwitch + id: pzCheck + anchors.top: ammyScroll2.bottom + anchors.left: resetDefault.right + anchors.bottom: resetDefault.bottom + anchors.right: parent.right + margin-top: 8 + margin-right: 2 + margin-left: 1 + text: Ignore in PZ + + ]], parent) + ui:setId(panelName) + if not storage[panelName] or not storage[panelName].ringId or not storage[panelName].ammyId then + storage[panelName] = { + pzCheck = true, + ringSwitch = true, + ammySwitch = true, + ringId = 3048, + ammyId = 3081, + ringMin = 30, + ringMax = 80, + ammyMin = 30, + ammyMax = 80, + valueAmmy = false, + valueRing = false, + ringValue = "HP", + ammyValue = "HP" + } + 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.ammySwitch:setOn(storage[panelName].ammyEnabled) + ui.ammySwitch.onClick = function(widget) + storage[panelName].ammyEnabled = not storage[panelName].ammyEnabled + widget:setOn(storage[panelName].ammyEnabled) + end + ui.pzCheck:setOn(storage[panelName].pzCheck) + ui.pzCheck.onClick = function(widget) + storage[panelName].pzCheck = not storage[panelName].pzCheck + widget:setOn(storage[panelName].pzCheck) + 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 + + 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.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) + + local defaultRing + local defaultAmmy + local ringToEquip + local ammyToEquip + + + -- 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 = getFinger():getId() + else + defaultRing = false + end + end + end + defaultRingFind() + + -- 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 = getNeck():getId() + else + defaultAmmy = false + end + end + end + defaultAmmyFind() + + ui.resetDefault.onClick = function(widget) + defaultRingFind() + defaultAmmyFind() + end + + macro(20, function() + ammyToEquip = findItem(storage[panelName].ammyId) + ringToEquip = findItem(storage[panelName].ringId) + + -- basic conditions to met + if not storage[panelName].ringEnabled and not storage[panelName].ammyEnabled then return end + if not storage[panelName].ringEnabled and storage[panelName].ammyEnabled and not ammyToEquip and (not getNeck() or (getNeck():getId() ~= storage[panelName].ammyId and getNeck():getId() ~= getActiveItemId(storage[panelName].ammyId))) then return end + if storage[panelName].ringEnabled and not storage[panelName].ammyEnabled and not ringToEquip and (not getFinger() or (getFinger():getId() ~= storage[panelName].ringId and getFinger():getId() ~= getActiveItemId(storage[panelName].ringId))) then return end + + -- ring unequip conditions + if storage[panelName].ringEnabled and getFinger() and getFinger():getId() == getActiveItemId(storage[panelName].ringId) and ((storage[panelName].pzCheck and isInPz()) or (not storage[panelName].valueRing and hppercent() >= storage[panelName].ringMax) or (storage[panelName].valueRing and manapercent() >= storage[panelName].ringMax)) then + if defaultRing then + moveToSlot(findItem(defaultRing), SlotFinger, 1) + else + for _,container in pairs(getContainers()) do + g_game.move(getFinger(), container:getSlotPosition(container:getItemsCount())) + return + end + end + end + + -- amulet unequip conditions + if storage[panelName].ammyEnabled and getNeck() and getNeck():getId() == getActiveItemId(storage[panelName].ammyId) and ((storage[panelName].pzCheck and isInPz()) or (not storage[panelName].valueAmmy and hppercent() >= storage[panelName].ammyMax) or (not storage[panelName].valueAmmy and manapercent() >= storage[panelName].ammyMax)) then + if defaultAmmy then + moveToSlot(findItem(defaultAmmy), SlotNeck, 1) + else + for _,container in pairs(getContainers()) do + g_game.move(getNeck(), container:getSlotPosition(container:getItemsCount())) + return + end + end + end + + -- ring equip conditions + if storage[panelName].ringEnabled and (not getFinger() or getFinger():getId() ~= getActiveItemId(storage[panelName].ringId)) and (not storage[panelName].pzCheck or not isInPz()) and ((not storage[panelName].valueRing and hppercent() <= storage[panelName].ringMin) or (storage[panelName].valueRing and manapercent() <= storage[panelName].ringMin)) then + moveToSlot(ringToEquip, SlotFinger, 1) + end + -- amulet equip conditions + if storage[panelName].ammyEnabled and (not getNeck() or getNeck():getId() ~= getActiveItemId(storage[panelName].ammyId)) and (not storage[panelName].pzCheck or not isInPz()) and ((not storage[panelName].valueAmmy and hppercent() <= storage[panelName].ammyMin) or (storage[panelName].valueAmmy and manapercent() <= storage[panelName].ammyMin)) then + moveToSlot(ammyToEquip, SlotNeck, 1) + end + end) + -- end of function +end +addSeparator() +UI.Label("-- [[ Equipper ]] --") +addSeparator() +jewelleryEquip() +addSeparator() \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/kill steal.lua b/modules/game_bot/default_configs/vithrax_1.1/kill steal.lua new file mode 100644 index 0000000..54b5e8e --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/kill steal.lua @@ -0,0 +1,111 @@ +setDefaultTab("Tools") +local panelName = "killSteal" +local ui = setupUI([[ +Panel + height: 50 + + BotItem + id: item + anchors.top: parent.top + anchors.left: parent.left + margin-top: 2 + + BotSwitch + id: title + anchors.top: parent.top + anchors.left: item.right + anchors.bottom: item.verticalCenter + text-align: center + !text: tr('Kill Steal') + margin-left: 2 + width: 90 + + Button + id: Target + anchors.top: item.top + anchors.left: title.right + anchors.right: parent.right + anchors.bottom: item.verticalCenter + margin-left: 3 + text-align: center + !text: tr('Switch') + + BotLabel + id: help + anchors.top: item.verticalCenter + anchors.left: item.right + anchors.right: parent.right + anchors.bottom: item.bottom + text-align: center + margin-left: 2 + + HorizontalScrollBar + id: HP + anchors.top: item.bottom + anchors.left: parent.left + anchors.right: parent.right + margin-top: 3 + minimum: 1 + maximum: 100 + step: 1 + +]], parent) +ui:setId(panelName) + +if not storage[panelName] then + storage[panelName] = { + id = 3155, + title = enabled, + enabled = false, + setting = true, + hp = 20 + } +end + +ui.title:setOn(storage[panelName].enabled) +ui.title.onClick = function(widget) + storage[panelName].enabled = not storage[panelName].enabled + widget:setOn(storage[panelName].enabled) +end +local updateHpText = function() + local desc + if storage[panelName].setting then + desc = "Target" + else + desc = "Enemy" + end + ui.help:setText("If " .. desc .. " HP<" .. storage[panelName].hp .. "%") +end +updateHpText() +ui.HP.onValueChange = function(scroll, value) + storage[panelName].hp = value + updateHpText() +end +ui.item:setItemId(storage[panelName].id) +ui.item.onItemChange = function(widget) + storage[panelName].id = widget:getItemId() +end +ui.HP:setValue(storage[panelName].hp) + +ui.Target.onClick = function(widget) + storage[panelName].setting = not storage[panelName].setting + updateHpText() +end + +macro(200, function() + if not storage[panelName].enabled then return end + + if storage[panelName].setting then + if target() and target():canShoot() and target():getHealthPercent() <= storage[panelName].hp then + useWith(storage[panelName].id, target()) + end + else + for _, spec in pairs(getSpectators()) do + if spec:isPlayer() and spec:canShoot() and isEnemy(spec:getName()) and spec:getHealthPercent() <= storage[panelName].hp then + useWith(storage[panelName].id, spec) + end + end + end +end) + +addSeparator() \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/loot.otui b/modules/game_bot/default_configs/vithrax_1.1/loot.otui new file mode 100644 index 0000000..c1650b9 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/loot.otui @@ -0,0 +1,150 @@ +lootg=Label < Label + opacity: 0.87 + text-offset: 2 0 + focusable: false + height: 16 + +LootAnalyser < MiniWindow + !text: tr('Loot & Supplies') + height: 100 + icon: /images/topbuttons/analyzers + &save: true + &autoOpen: false + + MiniWindowContents + Button + id: LootEdit + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + margin-left: 10 + margin-right: 10 + margin-top: 5 + height: 15 + !text: tr('Edit Loot List') + + Label + id: supply + !text: tr('Supplies:') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 5 + margin-left: 3 + margin-right: 3 + + Label + id: supplyValue + !text: tr('0') + anchors.right: parent.right + anchors.verticalCenter: supply.verticalCenter + margin-left: 3 + margin-right: 3 + width: 100 + text-align: right + + HorizontalSeparator + id: separator + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + + Label + id: supplyHour + !text: tr('Supplies/h:') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + margin-left: 3 + margin-right: 3 + + Label + id: supplyHourValue + !text: tr('0') + anchors.right: parent.right + anchors.verticalCenter: supplyHour.verticalCenter + margin-left: 3 + margin-right: 3 + width: 100 + text-align: right + + HorizontalSeparator + id: separator + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + + Label + id: loot + !text: tr('Loot:') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + margin-left: 3 + margin-right: 3 + + Label + id: lootValue + !text: tr('0') + anchors.right: parent.right + anchors.verticalCenter: loot.verticalCenter + margin-left: 3 + margin-right: 3 + width: 100 + text-align: right + + HorizontalSeparator + id: separator + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + + Label + id: lootHour + !text: tr('Loot/h:') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + margin-left: 3 + margin-right: 3 + + Label + id: lootHourValue + !text: tr('0') + anchors.right: parent.right + anchors.verticalCenter: lootHour.verticalCenter + margin-left: 3 + margin-right: 3 + width: 100 + text-align: right + + HorizontalSeparator + id: separator + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + + Label + id: Label + anchors.top: prev.bottom + anchors.left: parent.left + margin-left: 3 + margin-top: 10 + !text: tr('Items Looted:') + + TextList + id: MessagePanel + anchors.top: prev.bottom + anchors.left: parent.left + anchors.right: parent.right + margin-top: 3 + margin-left: 3 + margin-right: 3 + height: 400 \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/lootList.otui b/modules/game_bot/default_configs/vithrax_1.1/lootList.otui new file mode 100644 index 0000000..9c48238 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/lootList.otui @@ -0,0 +1,72 @@ +LootItemName < 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 + +LootWindow < MainWindow + !text: tr('Loot List') + size: 250 340 + @onEscape: self:hide() + + TextList + id: LootList + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + margin-bottom: 5 + padding: 1 + width: 200 + height: 200 + vertical-scrollbar: LootListScrollBar + + VerticalScrollBar + id: LootListScrollBar + anchors.top: LootList.top + anchors.bottom: LootList.bottom + anchors.right: LootList.right + step: 14 + pixels-scroll: true + + TextEdit + id: LootName + anchors.right: parent.right + anchors.left: parent.left + anchors.top: LootList.bottom + margin-top: 5 + + Button + id: AddLoot + !text: tr('Add Loot') + anchors.right: parent.right + anchors.left: parent.left + anchors.top: prev.bottom + margin-top: 3 + + 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/vithrax_1.1/mwall_timer.lua b/modules/game_bot/default_configs/vithrax_1.1/mwall_timer.lua new file mode 100644 index 0000000..6dc1ec4 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/oberon.lua b/modules/game_bot/default_configs/vithrax_1.1/oberon.lua new file mode 100644 index 0000000..c28e9da --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/player list.otui b/modules/game_bot/default_configs/vithrax_1.1/player list.otui new file mode 100644 index 0000000..6726e35 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/player list.otui @@ -0,0 +1,159 @@ +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: 380 350 + @onEscape: self:hide() + + Label + id: Label + anchors.left: parent.left + anchors.top: parent.top + anchors.right: parent.horizontalCenter + text-align: center + text: Friends List + margin-right: 3 + + Label + id: Label + anchors.right: parent.right + anchors.top: parent.top + anchors.left: parent.horizontalCenter + text-align: center + text: Enemy List + margin-left: 3 + + TextList + id: FriendList + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.horizontalCenter + margin-top: 15 + margin-bottom: 5 + margin-right: 3 + padding: 1 + width: 150 + 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: parent.horizontalCenter + anchors.left: parent.left + anchors.top: FriendList.bottom + margin-right: 3 + margin-top: 5 + + Button + id: AddFriend + !text: tr('Add Friend') + anchors.right: parent.horizontalCenter + anchors.left: parent.left + anchors.top: prev.bottom + margin-right: 3 + margin-top: 3 + + TextList + id: EnemyList + anchors.top: parent.top + anchors.right: parent.right + anchors.left: parent.horizontalCenter + margin-top: 15 + margin-bottom: 5 + margin-left: 3 + padding: 1 + width: 150 + 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: parent.horizontalCenter + anchors.right: parent.right + anchors.top: EnemyList.bottom + margin-left: 3 + margin-top: 5 + + Button + id: AddEnemy + !text: tr('Add Enemy') + anchors.left: parent.horizontalCenter + anchors.right: parent.right + anchors.top: prev.bottom + margin-left: 3 + margin-top: 3 + + BotSwitch + id: Members + anchors.right: parent.right + anchors.top: AddEnemy.bottom + margin-top: 10 + width: 114 + text-align: center + text: Group Members + + BotSwitch + id: Outfit + anchors.left: parent.left + anchors.top: AddEnemy.bottom + margin-top: 10 + width: 114 + text-align: center + text: Color Outfits + + BotSwitch + id: Marks + anchors.horizontalCenter: parent.horizontalCenter + 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/vithrax_1.1/pushmax.otui b/modules/game_bot/default_configs/vithrax_1.1/pushmax.otui new file mode 100644 index 0000000..d962f63 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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: 1000 + maximum: 1500 + 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/vithrax_1.1/siolist.otui b/modules/game_bot/default_configs/vithrax_1.1/siolist.otui new file mode 100644 index 0000000..79439d8 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/spy level.lua b/modules/game_bot/default_configs/vithrax_1.1/spy level.lua new file mode 100644 index 0000000..f225d76 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/storage.json b/modules/game_bot/default_configs/vithrax_1.1/storage.json new file mode 100644 index 0000000..3466aaa --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/storage.json @@ -0,0 +1,303 @@ +{ + "rope": 9596, + "castle": { + "enabled": false, + "id": 2983, + "around": false + }, + "supplyRetries": 0, + "foodItems": [ + { + "count": 1, + "id": 3582 + }, + { + "count": 1, + "id": 3577 + } + ], + "isUsing": false, + "healbot": { + "spellTable": [ + + ], + "enabled": false, + "itemTable": [ + + ] + }, + "supplies": { + "item3Max": 0, + "item2Min": 0, + "item4Max": 0, + "item1Min": 0, + "item2": 0, + "SoftBoots": false, + "item1": 0, + "item1Max": 0, + "item5Max": 0, + "item3Min": 0, + "item4Min": 0, + "imbues": false, + "item5Min": 0, + "staminaSwitch": false, + "item5": 0, + "staminaValue": 900, + "capSwitch": false, + "item3": 0, + "capValue": 0, + "item2Max": 0, + "item4": 0 + }, + "shovel": 9596, + "buySuppliesCap": 0, + "jewelleryEquipper": { + "pzCheck": true, + "ammyMin": 30, + "ringMin": 30, + "valueAmmy": false, + "ringMax": 80, + "valueRing": false, + "ringId": 3048, + "ammyId": 3081, + "ammySwitch": true, + "ringValue": "HP", + "ringSwitch": true, + "ammyMax": 80, + "ammyValue": "HP" + }, + "attackbot": { + "pvpSafe": true, + "enabled": false, + "attackTable": [ + { + "dist": 5, + "minMonsters": 4, + "pvp": false, + "category": 2, + "model": 3, + "attack": "exevo gran mas tera", + "manaCost": 25 + }, + { + "dist": 4, + "minMonsters": 2, + "pvp": false, + "category": 8, + "model": 11, + "attack": 3161, + "manaCost": 10 + }, + { + "dist": 4, + "minMonsters": 1, + "pvp": false, + "category": 6, + "model": 2, + "attack": "exori max frigo", + "manaCost": 10 + }, + { + "dist": 4, + "minMonsters": 2, + "pvp": false, + "category": 5, + "model": 8, + "attack": "exevo gran frigo hur", + "manaCost": 10 + }, + { + "dist": 9, + "minMonsters": 1, + "pvp": false, + "category": 7, + "model": 2, + "attack": 3155, + "manaCost": 1 + }, + { + "dist": 4, + "minMonsters": 1, + "pvp": false, + "category": 6, + "model": 2, + "attack": "exori frigo", + "manaCost": 1 + }, + { + "dist": 4, + "minMonsters": 1, + "pvp": true, + "category": 6, + "model": 2, + "attack": "exori max frigo", + "manaCost": 1 + }, + { + "dist": 9, + "manaCost": 1, + "pvp": true, + "category": 7, + "model": 2, + "attack": 3155, + "minMonsters": 1 + } + ], + "pvpMode": false + }, + "scythe": 9596, + "inboxContainerOpen": false, + "advancedFriendHealer": { + "itemHeal": true, + "minFriendHp": 40, + "id": 3160, + "minMana": 60, + "distance": 8, + "spellHeal": true, + "spellName": "exura sio" + }, + "autoTradeMessage": "I'm using OTClientV8!", + "BotServerChannel": "6797953434510", + "combobot": { + "attackSpellEnabled": false, + "attackLeaderTargetEnabled": false, + "onShootEnabled": false, + "item": 3155, + "followLeaderEnabled": false, + "serverTriggers": true, + "serverEnabled": false, + "attack": "", + "onSayEnabled": false, + "sayLeader": "", + "spell": "", + "shootLeader": "", + "attackItemToggle": false, + "serverLeaderTarget": false, + "commandsEnabled": true, + "sayPhrase": "", + "onCastEnabled": false, + "serverLeader": "", + "enabled": false, + "follow": "", + "castLeader": "" + }, + "antiPushPanel": { + "items": [ + 3031, + 3035, + 0, + 0, + 0 + ] + }, + "_macros": { + "": false, + "Stake Bodies": false, + "Supply Sorter": false + }, + "lootContainerOpen": false, + "sellAllCap": 0, + "_configs": { + "targetbot_configs": { + "enabled": false + }, + "cavebot_configs": { + "enabled": false + } + }, + "trashItems": [ + { + "count": 1, + "id": 283 + }, + { + "count": 1, + "id": 284 + }, + { + "count": 1, + "id": 285 + } + ], + "serverMembers": "[\"Otcliento\"]", + "stopSearch": false, + "BOTserver": { + "manaInfo": true, + "mwallInfo": true, + "mwalls": [ + + ] + }, + "ConditionPanel": { + "cureBurn": false, + "curseCost": 80, + "electrifyCost": 22, + "ignoreInPz": true, + "bleedCost": 45, + "cureCurse": false, + "holdHaste": false, + "curePosion": false, + "hasteSpell": "utani hur", + "cureParalyse": false, + "cureBleed": false, + "holdUtura": false, + "paralyseSpell": "utani hur", + "poisonCost": 20, + "utanaCost": 440, + "uturaType": "", + "utamoCost": 40, + "enabled": false, + "uturaCost": 100, + "cureElectrify": false, + "holdUtamo": false, + "paralyseCost": 40, + "hasteCost": 40, + "holdUtana": false, + "burnCost": 30 + }, + "machete": 9596, + "alarms": { + "playerDetected": false, + "creatureDetected": false, + "manaValue": 50, + "playerAttack": false, + "manaBelow": false, + "privateMessage": false, + "playerDetectedLogout": false, + "enabled": false, + "healthBelow": false, + "healthValue": 40 + }, + "playerList": { + "enemyList": [ + + ], + "outfits": false, + "groupMembers": true, + "marks": false, + "friendList": [ + + ] + }, + "pushmax": { + "pushMaxRuneId": 3188, + "mwallBlockId": 2128, + "pushDelay": 1060, + "enabled": true, + "pushMaxKey": "PageUp" + }, + "AnalysersPanel": { + "lootItems": [ + + ], + "bestHit": 0, + "bestHeal": 0 + }, + "posCheckRetries": 0, + "killSteal": { + "setting": true, + "enabled": false, + "hp": 20, + "id": 3155 + } +} \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/supplies.lua b/modules/game_bot/default_configs/vithrax_1.1/supplies.lua new file mode 100644 index 0000000..ce1bd85 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/supplies.lua @@ -0,0 +1,226 @@ +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, + 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, +} +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 + + -- 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 + + -- 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("") + 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 + +end + +ui.supplies.onClick = function(widget) + SuppliesWindow:show() + SuppliesWindow:raise() + SuppliesWindow:focus() +end + +SuppliesWindow.close.onClick = function(widget) + SuppliesWindow:hide() +end +end + +UI.Separator() +SuppliesPanel(setDefaultTab("Cave")) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/supplies.otui b/modules/game_bot/default_configs/vithrax_1.1/supplies.otui new file mode 100644 index 0000000..8220b21 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/supplies.otui @@ -0,0 +1,279 @@ +SuppliesWindow < MainWindow + !text: tr('Supplies') + size: 430 280 + @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 + + 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 + + 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/vithrax_1.1/targetbot/creature.lua b/modules/game_bot/default_configs/vithrax_1.1/targetbot/creature.lua new file mode 100644 index 0000000..d4dd545 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/targetbot/creature_attack.lua b/modules/game_bot/default_configs/vithrax_1.1/targetbot/creature_attack.lua new file mode 100644 index 0000000..048c07c --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/targetbot/creature_attack.lua @@ -0,0 +1,122 @@ +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 + +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 + + -- luring + if TargetBot.canLure() and (config.lure or config.lureCavebot) and not (config.chase and creature:getHealthPercent() < 30) and not isTrapped then + local monsters = 0 + if targets < config.lureCount then + if config.lureCavebot then + return TargetBot.allowCaveBot(200) + 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 + + 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 + end +end diff --git a/modules/game_bot/default_configs/vithrax_1.1/targetbot/creature_editor.lua b/modules/game_bot/default_configs/vithrax_1.1/targetbot/creature_editor.lua new file mode 100644 index 0000000..8d92db0 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/targetbot/creature_editor.lua @@ -0,0 +1,113 @@ +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", "Lure", 0, 5, 1) + + addScrollBar("minMana", "Min. mana for attack spell", 0, 3000, 200) + addScrollBar("attackSpellDelay", "Attack spell delay", 200, 5000, 2500) + addScrollBar("minManaGroup", "Min. mana for group attack", 0, 3000, 1500) + addScrollBar("groupAttackTargets", "Min. targets for group attack", 1, 10, 2) + addScrollBar("groupAttackRadius", "Radius of group attack spell", 1, 7, 1) + addScrollBar("groupAttackDelay", "Group attack spell delay", 200, 60000, 5000) + addScrollBar("runeAttackDelay", "Rune attack delay", 200, 5000, 2000) + addScrollBar("groupRuneAttackTargets", "Min. targets for group rune attack", 1, 10, 2) + addScrollBar("groupRuneAttackRadius", "Radius of group rune attack", 1, 7, 1) + addScrollBar("groupRuneAttackDelay", "Group rune attack delay", 200, 60000, 5000) + + 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("avoidAttacks", "Avoid wave attacks", false) + + addCheckBox("useSpellAttack", "Use attack spell", false) + addTextEdit("attackSpell", "Attack spell", "") + addCheckBox("useRuneAttack", "Use attack rune", false) + addItem("attackRune", "Attack rune:", 0) + addCheckBox("useGroupAttack", "Use group attack spell", false) + addTextEdit("groupAttackSpell", "Group attack spell", "") + addCheckBox("useGroupAttackRune", "Use group attack rune", false) + addItem("groupAttackRune", "Group attack rune:", 0) + addCheckBox("groupAttackIgnorePlayers", "Ignore players in group attack", false) + addCheckBox("groupAttackIgnoreParty", "Ignore party in group attack", false) +end diff --git a/modules/game_bot/default_configs/vithrax_1.1/targetbot/creature_editor.otui b/modules/game_bot/default_configs/vithrax_1.1/targetbot/creature_editor.otui new file mode 100644 index 0000000..24f3da6 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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: 630 + + $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/vithrax_1.1/targetbot/creature_priority.lua b/modules/game_bot/default_configs/vithrax_1.1/targetbot/creature_priority.lua new file mode 100644 index 0000000..dcc2f81 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/targetbot/looting.lua b/modules/game_bot/default_configs/vithrax_1.1/targetbot/looting.lua new file mode 100644 index 0000000..084beeb --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/targetbot/looting.lua @@ -0,0 +1,307 @@ +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 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/vithrax_1.1/targetbot/looting.otui b/modules/game_bot/default_configs/vithrax_1.1/targetbot/looting.otui new file mode 100644 index 0000000..97cb351 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/targetbot/target.lua b/modules/game_bot/default_configs/vithrax_1.1/targetbot/target.lua new file mode 100644 index 0000000..adcd20e --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/targetbot/target.lua @@ -0,0 +1,285 @@ +local targetbotMacro = nil +local config = nil +local lastAction = 0 +local cavebotAllowance = 0 +local lureEnabled = true + +-- 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 + +-- 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 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() + + 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 + + +-- 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/vithrax_1.1/targetbot/target.otui b/modules/game_bot/default_configs/vithrax_1.1/targetbot/target.otui new file mode 100644 index 0000000..6e0e4ea --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/targetbot/walking.lua b/modules/game_bot/default_configs/vithrax_1.1/targetbot/walking.lua new file mode 100644 index 0000000..b256d6a --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/use all.lua b/modules/game_bot/default_configs/vithrax_1.1/use all.lua new file mode 100644 index 0000000..cecf1e8 --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/use all.lua @@ -0,0 +1,40 @@ +-- config +storage.shovel = 9596 +storage.rope = 9596 +storage.machete = 9596 +storage.scythe = 9596 + +local useId = {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 = {593, 867} +local ropeId = {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/vithrax_1.1/xp.otui b/modules/game_bot/default_configs/vithrax_1.1/xp.otui new file mode 100644 index 0000000..c9f07cd --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/xp.otui @@ -0,0 +1,80 @@ +XpAnalyser < MiniWindow + !text: tr('XP Analyser') + height: 85 + icon: /images/topbuttons/analyzers + &save: true + &autoOpen: false + + MiniWindowContents + Label + id: xpGain + !text: tr('XP Gain:') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + margin-left: 3 + margin-right: 3 + + Label + id: xpValue + !text: tr('0') + anchors.right: parent.right + anchors.verticalCenter: xpGain.verticalCenter + margin-left: 3 + margin-right: 3 + width: 100 + text-align: right + + HorizontalSeparator + id: separatorOne + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + + Label + id: xpHour + !text: tr('XP/h:') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: xpGain.bottom + margin-top: 10 + margin-left: 3 + margin-right: 3 + + Label + id: hourValue + !text: tr('0') + anchors.right: parent.right + anchors.verticalCenter: xpHour.verticalCenter + margin-left: 3 + margin-right: 3 + width: 100 + text-align: right + + HorizontalSeparator + id: separatorTwo + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 3 + + Label + id: ttnl + !text: tr('Next Level:') + anchors.left: parent.left + anchors.right: parent.right + anchors.top: xpHour.bottom + margin-top: 10 + margin-left: 3 + margin-right: 3 + + Label + id: ttnlValue + !text: tr('-') + anchors.right: parent.right + anchors.verticalCenter: ttnl.verticalCenter + margin-left: 3 + margin-right: 3 + width: 100 + text-align: right \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/z click reuse.lua b/modules/game_bot/default_configs/vithrax_1.1/z click reuse.lua new file mode 100644 index 0000000..680ca7b --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/z mwalls.lua b/modules/game_bot/default_configs/vithrax_1.1/z mwalls.lua new file mode 100644 index 0000000..b86310e --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/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/vithrax_1.1/z sort supply.lua b/modules/game_bot/default_configs/vithrax_1.1/z sort supply.lua new file mode 100644 index 0000000..c15f1ab --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/z sort supply.lua @@ -0,0 +1,76 @@ +setDefaultTab("Cave") +UI.Separator() + +-- config + +local ammoBp = "crystal backpack" +local potionBp = "camouflage backpack" +local runeBp = "yellow backpack" + +-- script + +local potions = {268, 237, 238, 23373, 266, 236, 239, 7643, 23375, 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 = {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} + +local potionsContainer = nil +local runesContainer = nil +local ammoContainer = nil + +macro(500, "Supply Sorter", function() + + -- set the containers + if not potionsContainer or not runesContainer or not ammoContainer then + for i, container in pairs(getContainers()) do + if container:getName():lower() == potionBp:lower() then + potionsContainer = container + elseif container:getName():lower() == runeBp:lower() then + runesContainer = container + elseif container:getName():lower() == ammoBp:lower() then + ammoContainer = container + end + end + end + + + + -- potions + if potionsContainer then + for i, container in pairs(getContainers()) do + if (container:getName():lower() ~= potionBp:lower() 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(potions, item:getId()) then + 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:getName():lower() ~= runeBp:lower() 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(runes, item:getId()) then + 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:getName():lower() ~= ammoBp:lower() 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 + g_game.move(item, ammoContainer:getSlotPosition(ammoContainer:getItemsCount()), item:getCount()) + end + end + end + end + end + +end) \ No newline at end of file diff --git a/modules/game_bot/default_configs/vithrax_1.1/z stake, knife.lua b/modules/game_bot/default_configs/vithrax_1.1/z stake, knife.lua new file mode 100644 index 0000000..7429a9d --- /dev/null +++ b/modules/game_bot/default_configs/vithrax_1.1/z stake, knife.lua @@ -0,0 +1,33 @@ +setDefaultTab("Cave") + +UI.Separator() +-- Config + +local useKnife = true +local useStake = true + +-- Script + + +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} + + +macro(200,"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 useKnife and table.find(knifeBodies, item:getId()) and findItem(5908) then + CaveBot.delay(200) + useWith(5908, item) + return + end + if useStake and table.find(stakeBodies, item:getId()) and findItem(5942) then + CaveBot.delay(200) + useWith(5942, item) + return + end + end + end + +end) \ No newline at end of file diff --git a/modules/game_bot/executor.lua b/modules/game_bot/executor.lua index ee55fba..30004ac 100644 --- a/modules/game_bot/executor.lua +++ b/modules/game_bot/executor.lua @@ -42,6 +42,7 @@ function executeBot(config, storage, tabs, msgCallback, saveConfigCallback, relo onKeyPress = {}, onTalk = {}, onTextMessage = {}, + onLoginAdvice = {}, onAddThing = {}, onRemoveThing = {}, onCreatureAppear = {}, @@ -60,7 +61,8 @@ function executeBot(config, storage, tabs, msgCallback, saveConfigCallback, relo onOpenChannel = {}, onCloseChannel = {}, onChannelEvent = {}, - onTurn = {} + onTurn = {}, + onWalk = {} } -- basic functions & classes @@ -235,6 +237,11 @@ function executeBot(config, storage, tabs, msgCallback, saveConfigCallback, relo for i, callback in ipairs(context._callbacks.onTextMessage) do callback(mode, text) end + end, + onLoginAdvice = function(message) + for i, callback in ipairs(context._callbacks.onLoginAdvice) do + callback(message) + end end, onAddThing = function(tile, thing) for i, callback in ipairs(context._callbacks.onAddThing) do @@ -331,6 +338,11 @@ function executeBot(config, storage, tabs, msgCallback, saveConfigCallback, relo callback(creature, direction) end end, + onWalk = function(creature, oldPos, newPos) + for i, callback in ipairs(context._callbacks.onWalk) do + callback(creature, oldPos, newPos) + end + end, } } end \ No newline at end of file diff --git a/modules/game_bot/functions/callbacks.lua b/modules/game_bot/functions/callbacks.lua index f76440f..cb0db12 100644 --- a/modules/game_bot/functions/callbacks.lua +++ b/modules/game_bot/functions/callbacks.lua @@ -70,6 +70,11 @@ context.onTextMessage = function(callback) return context.callback("onTextMessage", callback) end +-- onLoginAdvice(callback) -- callback = function(message) +context.onLoginAdvice = function(callback) + return context.callback("onLoginAdvice", callback) +end + -- onAddThing(callback) -- callback = function(tile, thing) context.onAddThing = function(callback) return context.callback("onAddThing", callback) @@ -165,6 +170,10 @@ context.onTurn = function(callback) return context.callback("onTurn", callback) end +-- onWalk -- callback = function(creature, oldPos, newPos) +context.onWalk = function(callback) + return context.callback("onWalk", callback) +end -- CUSTOM CALLBACKS diff --git a/modules/game_bot/functions/map.lua b/modules/game_bot/functions/map.lua index 198478a..01a6df0 100644 --- a/modules/game_bot/functions/map.lua +++ b/modules/game_bot/functions/map.lua @@ -238,4 +238,19 @@ context.canShoot = function(pos, distance) return tile:canShoot(distance) end return false -end \ No newline at end of file +end + +context.isTrapped = function(creature) + if not creature then + creature = context.player + end + local pos = creature: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 + return false + end + end + return true +end diff --git a/modules/game_bot/functions/player.lua b/modules/game_bot/functions/player.lua index d43a455..fdb4a71 100644 --- a/modules/game_bot/functions/player.lua +++ b/modules/game_bot/functions/player.lua @@ -159,6 +159,7 @@ context.cancelFollow = g_game.cancelFollow context.cancelAttackAndFollow = g_game.cancelAttackAndFollow context.logout = g_game.forceLogout +context.safeLogout = g_game.safeLogout context.ping = g_game.getPing modules.game_cooldown.isGroupCooldownIconActive(id) diff --git a/modules/game_containers/containers.lua b/modules/game_containers/containers.lua index 3e08270..5aa2831 100644 --- a/modules/game_containers/containers.lua +++ b/modules/game_containers/containers.lua @@ -1,9 +1,14 @@ +local gameStart = 0 + function init() connect(Container, { onOpen = onContainerOpen, onClose = onContainerClose, onSizeChange = onContainerChangeSize, onUpdateItem = onContainerUpdateItem }) - connect(Game, { onGameEnd = clean() }) + connect(g_game, { + onGameStart = markStart, + onGameEnd = clean + }) reloadContainers() end @@ -13,7 +18,10 @@ function terminate() onClose = onContainerClose, onSizeChange = onContainerChangeSize, onUpdateItem = onContainerUpdateItem }) - disconnect(Game, { onGameEnd = clean() }) + disconnect(g_game, { + onGameStart = markStart, + onGameEnd = clean + }) end function reloadContainers() @@ -29,6 +37,10 @@ function clean() end end +function markStart() + gameStart = g_clock.millis() +end + function destroy(container) if container.window then container.window:destroy() @@ -93,7 +105,12 @@ function onContainerOpen(container, previousContainer) else containerWindow = g_ui.createWidget('ContainerWindow', modules.game_interface.getContainerPanel()) end - containerWindow:setId('container' .. container:getId()) + + containerWindow:setId('container' .. container:getId() .. '_' .. container:getName()) + if gameStart + 1000 < g_clock.millis() then + containerWindow:clearSettings() + end + local containerPanel = containerWindow:getChildById('contentsPanel') local containerItemWidget = containerWindow:getChildById('containerItemWidget') containerWindow.onClose = function() diff --git a/modules/game_market/marketprotocol.lua b/modules/game_market/marketprotocol.lua index a7573c4..7fcbbe1 100644 --- a/modules/game_market/marketprotocol.lua +++ b/modules/game_market/marketprotocol.lua @@ -55,13 +55,15 @@ local function parseMarketEnter(protocol, msg) end end - local balance - if g_game.getClientVersion() >= 981 or g_game.getClientVersion() < 944 then - balance = msg:getU64() - else - balance = msg:getU32() + local balance = 0 + if g_game.getClientVersion() <= 1250 or not g_game.getFeature(GameTibia12Protocol) then + if g_game.getClientVersion() >= 981 or g_game.getClientVersion() < 944 then + balance = msg:getU64() + else + balance = msg:getU32() + end end - + local vocation = -1 if g_game.getClientVersion() >= 944 and g_game.getClientVersion() < 950 then vocation = msg:getU8() -- get vocation id diff --git a/modules/game_protocol/protocol.lua b/modules/game_protocol/protocol.lua index 8ee0b89..59bb933 100644 --- a/modules/game_protocol/protocol.lua +++ b/modules/game_protocol/protocol.lua @@ -1,7 +1,150 @@ +local registredOpcodes = nil + +local ServerPackets = { + DailyRewardCollectionState = 0xDE, + OpenRewardWall = 0xE2, + CloseRewardWall = 0xE3, + DailyRewardBasic = 0xE4, + DailyRewardHistory = 0xE5, + RestingAreaState = 0xA9, + BestiaryData = 0xd5, + BestiaryOverview = 0xd6, + BestiaryMonsterData = 0xd7, + BestiaryCharmsData = 0xd8, + BestiaryTracker = 0xd9, + BestiaryTrackerTab = 0xB9 +} + +-- Server Types +local DAILY_REWARD_TYPE_ITEM = 1 +local DAILY_REWARD_TYPE_STORAGE = 2 +local DAILY_REWARD_TYPE_PREY_REROLL = 3 +local DAILY_REWARD_TYPE_XP_BOOST = 4 + +-- Client Types +local DAILY_REWARD_SYSTEM_SKIP = 1 +local DAILY_REWARD_SYSTEM_TYPE_ONE = 1 +local DAILY_REWARD_SYSTEM_TYPE_TWO = 2 +local DAILY_REWARD_SYSTEM_TYPE_OTHER = 1 +local DAILY_REWARD_SYSTEM_TYPE_PREY_REROLL = 2 +local DAILY_REWARD_SYSTEM_TYPE_XP_BOOST = 3 + function init() + connect(g_game, { onEnterGame = registerProtocol, + onPendingGame = registerProtocol, + onGameEnd = unregisterProtocol }) + if g_game.isOnline() then + registerProtocol() + end end function terminate() + disconnect(g_game, { onEnterGame = registerProtocol, + onPendingGame = registerProtocol, + onGameEnd = unregisterProtocol }) + + unregisterProtocol() end +function registerProtocol() + if registredOpcodes ~= nil or not g_game.getFeature(GameTibia12Protocol) then + return + end + + registredOpcodes = {} + registerOpcode(ServerPackets.OpenRewardWall, function(protocol, msg) + msg:getU8() + msg:getU32() + msg:getU8() + local taken = msg:getU8() + if taken > 0 then + msg:getString() + end + msg:getU32() + msg:getU16() + msg:getU16() + end) + + registerOpcode(ServerPackets.CloseRewardWall, function(protocol, msg) + + end) + + registerOpcode(ServerPackets.DailyRewardBasic, function(protocol, msg) + local count = msg:getU8() + for i = 1, count do + readDailyReward(msg) + readDailyReward(msg) + end + local maxBonus = msg:getU8() + for i = 1, maxBonus do + msg:getString() + msg:getU8() + end + msg:getU8() + end) + + registerOpcode(ServerPackets.DailyRewardHistory, function(protocol, msg) + local count = msg:getU8() + for i=1,count do + msg:getU32() + msg:getU8() + msg:getString() + msg:getU16() + end + end) + + registerOpcode(ServerPackets.BestiaryTrackerTab, function(protocol, msg) + local count = msg:getU8() + for i = 1, count do + msg:getU16() + msg:getU32() + msg:getU16() + msg:getU16() + msg:getU16() + msg:getU8() + end + end) + + +end + +function unregisterProtocol() + if registredOpcodes == nil then + return + end + for _, opcode in ipairs(registredOpcodes) do + ProtocolGame.unregisterOpcode(opcode) + end + registredOpcodes = nil +end + +function registerOpcode(code, func) + if registredOpcodes[code] ~= nil then + error("Duplicated registed opcode: " .. code) + end + registredOpcodes[code] = func + ProtocolGame.registerOpcode(code, func) +end + +function readDailyReward(msg) + local systemType = msg:getU8() + if (systemType == 1) then + msg:getU8() + local count = msg:getU8() + for i = 1, count do + msg:getU16() + msg:getString() + msg:getU32() + end + elseif (systemType == 2) then + msg:getU8() + local type = msg:getU8() + + if (type == DAILY_REWARD_SYSTEM_TYPE_PREY_REROLL) then + msg:getU8() + elseif (type == DAILY_REWARD_SYSTEM_TYPE_XP_BOOST) then + msg:getU16() + end + end +end \ No newline at end of file diff --git a/modules/gamelib/const.lua b/modules/gamelib/const.lua index dd8e245..e2dcbd7 100644 --- a/modules/gamelib/const.lua +++ b/modules/gamelib/const.lua @@ -190,6 +190,7 @@ GamePlayerStateU32 = 105 GameOutfitShaders = 106 GameForceAllowItemHotkeys = 107 GameCountU16 = 108 +GameDrawAuraOnTop = 109 GamePacketSizeU32 = 110 GamePacketCompression = 111 diff --git a/otclient_dx.exe b/otclient_dx.exe index d7a5b66..35b92a1 100644 Binary files a/otclient_dx.exe and b/otclient_dx.exe differ diff --git a/otclient_gl.exe b/otclient_gl.exe index 3d211bf..deae190 100644 Binary files a/otclient_gl.exe and b/otclient_gl.exe differ diff --git a/otclient_linux b/otclient_linux index 9e162e1..9842843 100644 Binary files a/otclient_linux and b/otclient_linux differ diff --git a/otclientv8.apk b/otclientv8.apk index da886eb..a620be4 100644 Binary files a/otclientv8.apk and b/otclientv8.apk differ