setDefaultTab('main') -- locales local panelName = "AttackBot" local currentSettings local showSettings = false local showItem = false local category = 1 local patternCategory = 1 local pattern = 1 local mainWindow -- label library local categories = { "Targeted Spell (exori hur, exori flam, etc)", "Area Rune (avalanche, great fireball, etc)", "Targeted Rune (sudden death, icycle, etc)", "Empowerment (utito tempo, etc)", "Absolute Spell (exori, hells core, etc)", } local patterns = { -- targeted spells { "1 Sqm Range (exori ico)", "2 Sqm Range", "3 Sqm Range (strike spells)", "4 Sqm Range (exori san)", "5 Sqm Range (exori hur)", "6 Sqm Range", "7 Sqm Range (exori con)", "8 Sqm Range", "9 Sqm Range", "10 Sqm Range" }, -- area runes { "Cross (explosion)", "Bomb (fire bomb)", "Ball (gfb, avalanche)" }, -- empowerment/targeted rune { "1 Sqm Range", "2 Sqm Range", "3 Sqm Range", "4 Sqm Range", "5 Sqm Range", "6 Sqm Range", "7 Sqm Range", "8 Sqm Range", "9 Sqm Range", "10 Sqm Range", }, -- absolute { "Adjacent (exori, exori gran)", "3x3 Wave (vis hur, tera hur)", "Small Area (mas san, exori mas)", "Medium Area (mas flam, mas frigo)", "Large Area (mas vis, mas tera)", "Short Beam (vis lux)", "Large Beam (gran vis lux)", "Sweep (exori min)", -- 8 "Small Wave (gran frigo hur)", "Big Wave (flam hur, frigo hur)", "Huge Wave (gran flam hur)", } } -- spellPatterns[category][pattern][1 - normal, 2 - safe] local spellPatterns = { {}, -- blank, wont be used -- Area Runes, { { -- cross [[ 010 111 010 ]], -- cross SAFE [[ 01110 01110 11111 11111 11111 01110 01110 ]] }, { -- bomb [[ 111 111 111 ]], -- bomb SAFE [[ 11111 11111 11111 11111 11111 ]] }, { -- ball [[ 0011100 0111110 1111111 1111111 1111111 0111110 0011100 ]], -- ball SAFE [[ 000111000 001111100 011111110 111111111 111111111 111111111 011111110 001111100 000111000 ]] }, }, {}, -- blank, wont be used -- Absolute { {-- adjacent [[ 111 111 111 ]], -- adjacent SAFE [[ 11111 11111 11111 11111 11111 ]] }, { -- 3x3 Wave [[ 0000NNN0000 0000NNN0000 0000NNN0000 00000N00000 WWW00N00EEE WWWWW0EEEEE WWW00S00EEE 00000S00000 0000SSS0000 0000SSS0000 0000SSS0000 ]], -- 3x3 Wave SAFE [[ 0000NNNNN0000 0000NNNNN0000 0000NNNNN0000 0000NNNNN0000 WWWW0NNN0EEEE WWWWWNNNEEEEE WWWWWW0EEEEEE WWWWWSSSEEEEE WWWW0SSS0EEEE 0000SSSSS0000 0000SSSSS0000 0000SSSSS0000 0000SSSSS0000 ]] }, { -- small area [[ 0011100 0111110 1111111 1111111 1111111 0111110 0011100 ]], -- small area SAFE [[ 000111000 001111100 011111110 111111111 111111111 111111111 011111110 001111100 000111000 ]] }, { -- medium area [[ 00000100000 00011111000 00111111100 01111111110 01111111110 11111111111 01111111110 01111111110 00111111100 00001110000 00000100000 ]], -- medium area SAFE [[ 0000011100000 0000111110000 0001111111000 0011111111100 0111111111110 0111111111110 1111111111111 0111111111110 0111111111110 0011111111100 0001111111000 0000111110000 0000011100000 ]] }, { -- large area [[ 0000001000000 0000011100000 0000111110000 0001111111000 0011111111100 0111111111110 1111111111111 0111111111110 0011111111100 0001111111000 0000111110000 0000011100000 0000001000000 ]], -- large area SAFE [[ 000000010000000 000000111000000 000001111100000 000011111110000 000111111111000 001111111111100 011111111111110 111111111111111 011111111111110 001111111111100 000111111111000 000011111110000 000001111100000 000000111000000 000000010000000 ]] }, { -- short beam [[ 00000N00000 00000N00000 00000N00000 00000N00000 00000N00000 WWWWW0EEEEE 00000S00000 00000S00000 00000S00000 00000S00000 00000S00000 ]], -- short beam SAFE [[ 00000NNN00000 00000NNN00000 00000NNN00000 00000NNN00000 00000NNN00000 WWWWWNNNEEEEE WWWWWW0EEEEEE 00000SSS00000 00000SSS00000 00000SSS00000 00000SSS00000 00000SSS00000 00000SSS00000 ]] }, { -- large beam [[ 0000000N0000000 0000000N0000000 0000000N0000000 0000000N0000000 0000000N0000000 0000000N0000000 0000000N0000000 WWWWWWW0EEEEEEE 0000000S0000000 0000000S0000000 0000000S0000000 0000000S0000000 0000000S0000000 0000000S0000000 0000000S0000000 ]], -- large beam SAFE [[ 0000000NNN0000000 0000000NNN0000000 0000000NNN0000000 0000000NNN0000000 0000000NNN0000000 0000000NNN0000000 0000000NNN0000000 WWWWWWWNNNEEEEEEE WWWWWWWW0EEEEEEEE WWWWWWWSSSEEEEEEE 0000000SSS0000000 0000000SSS0000000 0000000SSS0000000 0000000SSS0000000 0000000SSS0000000 0000000SSS0000000 0000000SSS0000000 ]], }, {}, -- sweep, wont be used { -- small wave [[ 00NNN00 00NNN00 WW0N0EE WWW0EEE WW0S0EE 00SSS00 00SSS00 ]], -- small wave SAFE [[ 00NNNNN00 00NNNNN00 WWNNNNNEE WWWWNEEEE WWWW0EEEE WWWWSEEEE WWSSSSSEE 00SSSSS00 00SSSSS00 ]] }, { -- large wave [[ 000NNNNN000 000NNNNN000 0000NNN0000 WW00NNN00EE WWWW0N0EEEE WWWWW0EEEEE WWWW0S0EEEE WW00SSS00EE 0000SSS0000 000SSSSS000 000SSSSS000 ]], [[ 000NNNNNNN000 000NNNNNNN000 000NNNNNNN000 WWWWNNNNNEEEE WWWWNNNNNEEEE WWWWWNNNEEEEE WWWWWW0EEEEEE WWWWWSSSEEEEE WWWWSSSSSEEEE WWWWSSSSSEEEE 000SSSSSSS000 000SSSSSSS000 000SSSSSSS000 ]] }, { -- huge wave [[ 0000NNNNN0000 0000NNNNN0000 00000NNN00000 00000NNN00000 WW0000N0000EE WWWW00N00EEEE WWWWWW0EEEEEE WWWW00S00EEEE WW0000S0000EE 00000SSS00000 00000SSS00000 0000SSSSS0000 0000SSSSS0000 ]], [[ 0000000NNN0000000 0000000NNN0000000 0000000NNN0000000 0000000NNN0000000 0000000NNN0000000 0000000NNN0000000 0000000NNN0000000 WWWWWWWNNNEEEEEEE WWWWWWWW0EEEEEEEE WWWWWWWSSSEEEEEEE 0000000SSS0000000 0000000SSS0000000 0000000SSS0000000 0000000SSS0000000 0000000SSS0000000 0000000SSS0000000 0000000SSS0000000 ]] } } } -- direction patterns local ek = (voc() == 1 or voc() == 11) and true local posN = ek and [[ 111 000 000 ]] or [[ 00011111000 00011111000 00011111000 00011111000 00000100000 00000000000 00000000000 00000000000 00000000000 00000000000 00000000000 ]] local posE = ek and [[ 001 001 001 ]] or [[ 00000000000 00000000000 00000000000 00000001111 00000001111 00000011111 00000001111 00000001111 00000000000 00000000000 00000000000 ]] local posS = ek and [[ 000 000 111 ]] or [[ 00000000000 00000000000 00000000000 00000000000 00000000000 00000000000 00000100000 00011111000 00011111000 00011111000 00011111000 ]] local posW = ek and [[ 100 100 100 ]] or [[ 00000000000 00000000000 00000000000 11110000000 11110000000 11111000000 11110000000 11110000000 00000000000 00000000000 00000000000 ]] -- AttackBotConfig -- create blank profiles if not AttackBotConfig[panelName] or not AttackBotConfig[panelName][1] or #AttackBotConfig[panelName] ~= 5 then AttackBotConfig[panelName] = { [1] = { enabled = false, attackTable = {}, ignoreMana = true, Kills = false, Rotate = false, name = "Profile #1", Cooldown = true, Visible = true, pvpMode = false, KillsAmount = 1, PvpSafe = true, BlackListSafe = false, AntiRsRange = 5 }, [2] = { enabled = false, attackTable = {}, ignoreMana = true, Kills = false, Rotate = false, name = "Profile #2", Cooldown = true, Visible = true, pvpMode = false, KillsAmount = 1, PvpSafe = true, BlackListSafe = false, AntiRsRange = 5 }, [3] = { enabled = false, attackTable = {}, ignoreMana = true, Kills = false, Rotate = false, name = "Profile #3", Cooldown = true, Visible = true, pvpMode = false, KillsAmount = 1, PvpSafe = true, BlackListSafe = false, AntiRsRange = 5 }, [4] = { enabled = false, attackTable = {}, ignoreMana = true, Kills = false, Rotate = false, name = "Profile #4", Cooldown = true, Visible = true, pvpMode = false, KillsAmount = 1, PvpSafe = true, BlackListSafe = false, AntiRsRange = 5 }, [5] = { enabled = false, attackTable = {}, ignoreMana = true, Kills = false, Rotate = false, name = "Profile #5", Cooldown = true, Visible = true, pvpMode = false, KillsAmount = 1, PvpSafe = true, BlackListSafe = false, AntiRsRange = 5 }, } end if not AttackBotConfig.currentBotProfile or AttackBotConfig.currentBotProfile == 0 or AttackBotConfig.currentBotProfile > 5 then AttackBotConfig.currentBotProfile = 1 end -- create panel UI ui = UI.createWidget("AttackBotBotPanel") -- finding correct table, manual unfortunately local setActiveProfile = function() local n = AttackBotConfig.currentBotProfile currentSettings = AttackBotConfig[panelName][n] end setActiveProfile() if not currentSettings.AntiRsRange then currentSettings.AntiRsRange = 5 end local setProfileName = function() ui.name:setText(currentSettings.name) end -- small UI elements ui.title.onClick = function(widget) currentSettings.enabled = not currentSettings.enabled widget:setOn(currentSettings.enabled) vBotConfigSave("atk") end ui.settings.onClick = function(widget) mainWindow:show() mainWindow:raise() mainWindow:focus() end mainWindow = UI.createWindow("AttackBotWindow") mainWindow:hide() local panel = mainWindow.mainPanel local settingsUI = mainWindow.settingsPanel mainWindow.onVisibilityChange = function(widget, visible) if not visible then currentSettings.attackTable = {} for i, child in ipairs(panel.entryList:getChildren()) do table.insert(currentSettings.attackTable, child.params) end vBotConfigSave("atk") end end -- main panel -- functions function toggleSettings() panel:setVisible(not showSettings) mainWindow.shooterLabel:setVisible(not showSettings) settingsUI:setVisible(showSettings) mainWindow.settingsLabel:setVisible(showSettings) mainWindow.settings:setText(showSettings and "Back" or "Settings") end toggleSettings() mainWindow.settings.onClick = function() showSettings = not showSettings toggleSettings() end function toggleItem() panel.monsters:setWidth(showItem and 405 or 341) panel.itemId:setVisible(showItem) panel.spellName:setVisible(not showItem) end toggleItem() function setCategoryText() panel.category.description:setText(categories[category]) end setCategoryText() function setPatternText() panel.range.description:setText(patterns[patternCategory][pattern]) end setPatternText() -- in/de/crementation buttons panel.previousCategory.onClick = function() if category == 1 then category = #categories else category = category - 1 end showItem = (category == 2 or category == 3) and true or false patternCategory = category == 4 and 3 or category == 5 and 4 or category pattern = 1 toggleItem() setPatternText() setCategoryText() end panel.nextCategory.onClick = function() if category == #categories then category = 1 else category = category + 1 end showItem = (category == 2 or category == 3) and true or false patternCategory = category == 4 and 3 or category == 5 and 4 or category pattern = 1 toggleItem() setPatternText() setCategoryText() end panel.previousSource.onClick = function() warn("[AttackBot] TODO, reserved for future use.") end panel.nextSource.onClick = function() warn("[AttackBot] TODO, reserved for future use.") end panel.previousRange.onClick = function() local t = patterns[patternCategory] if pattern == 1 then pattern = #t else pattern = pattern - 1 end setPatternText() end panel.nextRange.onClick = function() local t = patterns[patternCategory] if pattern == #t then pattern = 1 else pattern = pattern + 1 end setPatternText() end -- eo in/de/crementation ------- [[core table function]] ------- function setupWidget(widget) local params = widget.params widget:setText(params.description) if params.itemId > 0 then widget.spell:setVisible(false) widget.id:setVisible(true) widget.id:setItemId(params.itemId) end widget:setTooltip(params.tooltip) widget.remove.onClick = function() panel.up:setEnabled(false) panel.down:setEnabled(false) widget:destroy() end widget.enabled:setChecked(params.enabled) widget.enabled.onClick = function() params.enabled = not params.enabled widget.enabled:setChecked(params.enabled) end -- will serve as edit widget.onDoubleClick = function(widget) panel.manaPercent:setValue(params.mana) panel.creatures:setValue(params.count) panel.minHp:setValue(params.minHp) panel.maxHp:setValue(params.maxHp) panel.cooldown:setValue(params.cooldown) showItem = params.itemId > 100 and true or false panel.itemId:setItemId(params.itemId) panel.spellName:setText(params.spell or "") panel.orMore:setChecked(params.orMore) toggleItem() category = params.category patternCategory = params.patternCategory pattern = params.pattern setPatternText() setCategoryText() widget:destroy() end widget.onClick = function(widget) if #panel.entryList:getChildren() == 1 then panel.up:setEnabled(false) panel.down:setEnabled(false) elseif panel.entryList:getChildIndex(widget) == 1 then panel.up:setEnabled(false) panel.down:setEnabled(true) elseif panel.entryList:getChildIndex(widget) == panel.entryList:getChildCount() then panel.up:setEnabled(true) panel.down:setEnabled(false) else panel.up:setEnabled(true) panel.down:setEnabled(true) end end end -- refreshing values function refreshAttacks() if not currentSettings.attackTable then return end panel.entryList:destroyChildren() for i, entry in pairs(currentSettings.attackTable) do local label = UI.createWidget("AttackEntry", panel.entryList) label.params = entry setupWidget(label) end end refreshAttacks() panel.up:setEnabled(false) panel.down:setEnabled(false) -- adding values panel.addEntry.onClick = function(wdiget) -- first variables local creatures = panel.monsters:getText():lower() local monsters = (creatures:len() == 0 or creatures == "*" or creatures == "monster names") and true or string.split(creatures, ",") local mana = panel.manaPercent:getValue() local count = panel.creatures:getValue() local minHp = panel.minHp:getValue() local maxHp = panel.maxHp:getValue() local cooldown = panel.cooldown:getValue() local itemId = panel.itemId:getItemId() local spell = panel.spellName:getText() local tooltip = monsters ~= true and creatures local orMore = panel.orMore:isChecked() -- validation if showItem and itemId < 100 then return warn("[AttackBot]: please fill item ID!") elseif not showItem and (spell:lower() == "spell name" or spell:len() == 0) then return warn("[AttackBot]: please fill spell name!") end local regex = patternCategory ~= 1 and [[^[^\(]+]] or [[^[^R]+]] local type = regexMatch(patterns[patternCategory][pattern], regex)[1][1]:trim() regex = [[^[^ ]+]] local categoryName = regexMatch(categories[category], regex)[1][1]:trim():lower() local specificMonsters = monsters == true and "Any Creatures" or "Creatures" local attackType = showItem and "rune "..itemId or spell local countDescription = orMore and count.."+" or count local params = { creatures = creatures, monsters = monsters, mana = mana, count = count, minHp = minHp, maxHp = maxHp, cooldown = cooldown, itemId = itemId, spell = spell, enabled = true, category = category, patternCategory = patternCategory, pattern = pattern, tooltip = tooltip, orMore = orMore, description = '['..type..'] '..countDescription.. ' '..specificMonsters..': '..attackType..', '..categoryName..' ('..minHp..'%-'..maxHp..'%)' } local label = UI.createWidget("AttackEntry", panel.entryList) label.params = params setupWidget(label) resetFields() end -- moving values -- up panel.up.onClick = function(widget) local focused = panel.entryList:getFocusedChild() local n = panel.entryList:getChildIndex(focused) if n-1 == 1 then widget:setEnabled(false) end panel.down:setEnabled(true) panel.entryList:moveChildToIndex(focused, n-1) panel.entryList:ensureChildVisible(focused) end -- down panel.down.onClick = function(widget) local focused = panel.entryList:getFocusedChild() local n = panel.entryList:getChildIndex(focused) if n + 1 == panel.entryList:getChildCount() then widget:setEnabled(false) end panel.up:setEnabled(true) panel.entryList:moveChildToIndex(focused, n+1) panel.entryList:ensureChildVisible(focused) end -- [[settings panel]] -- settingsUI.profileName.onTextChange = function(widget, text) currentSettings.name = text setProfileName() end settingsUI.IgnoreMana.onClick = function(widget) currentSettings.ignoreMana = not currentSettings.ignoreMana settingsUI.IgnoreMana:setChecked(currentSettings.ignoreMana) end settingsUI.Rotate.onClick = function(widget) currentSettings.Rotate = not currentSettings.Rotate settingsUI.Rotate:setChecked(currentSettings.Rotate) end settingsUI.Kills.onClick = function(widget) currentSettings.Kills = not currentSettings.Kills settingsUI.Kills:setChecked(currentSettings.Kills) end settingsUI.Cooldown.onClick = function(widget) currentSettings.Cooldown = not currentSettings.Cooldown settingsUI.Cooldown:setChecked(currentSettings.Cooldown) end settingsUI.Visible.onClick = function(widget) currentSettings.Visible = not currentSettings.Visible settingsUI.Visible:setChecked(currentSettings.Visible) end settingsUI.PvpMode.onClick = function(widget) currentSettings.pvpMode = not currentSettings.pvpMode settingsUI.PvpMode:setChecked(currentSettings.pvpMode) end settingsUI.PvpSafe.onClick = function(widget) currentSettings.PvpSafe = not currentSettings.PvpSafe settingsUI.PvpSafe:setChecked(currentSettings.PvpSafe) end settingsUI.Training.onClick = function(widget) currentSettings.Training = not currentSettings.Training settingsUI.Training:setChecked(currentSettings.Training) end settingsUI.BlackListSafe.onClick = function(widget) currentSettings.BlackListSafe = not currentSettings.BlackListSafe settingsUI.BlackListSafe:setChecked(currentSettings.BlackListSafe) end settingsUI.KillsAmount.onValueChange = function(widget, value) currentSettings.KillsAmount = value end settingsUI.AntiRsRange.onValueChange = function(widget, value) currentSettings.AntiRsRange = value end -- window elements mainWindow.closeButton.onClick = function() showSettings = false toggleSettings() resetFields() mainWindow:hide() end -- core functions function resetFields() showItem = false toggleItem() pattern = 1 patternCategory = 1 category = 1 setPatternText() setCategoryText() panel.manaPercent:setText(1) panel.creatures:setText(1) panel.minHp:setValue(0) panel.maxHp:setValue(100) panel.cooldown:setText(1) panel.monsters:setText("monster names") panel.itemId:setItemId(0) panel.spellName:setText("spell name") panel.orMore:setChecked(false) end resetFields() function loadSettings() -- BOT panel ui.title:setOn(currentSettings.enabled) setProfileName() -- main panel refreshAttacks() -- settings settingsUI.profileName:setText(currentSettings.name) settingsUI.Visible:setChecked(currentSettings.Visible) settingsUI.Cooldown:setChecked(currentSettings.Cooldown) settingsUI.PvpMode:setChecked(currentSettings.pvpMode) settingsUI.PvpSafe:setChecked(currentSettings.PvpSafe) settingsUI.BlackListSafe:setChecked(currentSettings.BlackListSafe) settingsUI.AntiRsRange:setValue(currentSettings.AntiRsRange) settingsUI.IgnoreMana:setChecked(currentSettings.ignoreMana) settingsUI.Rotate:setChecked(currentSettings.Rotate) settingsUI.Kills:setChecked(currentSettings.Kills) settingsUI.KillsAmount:setValue(currentSettings.KillsAmount) settingsUI.Training:setChecked(currentSettings.Training) end loadSettings() local activeProfileColor = function() for i=1,5 do if i == AttackBotConfig.currentBotProfile then ui[i]:setColor("green") else ui[i]:setColor("white") end end end activeProfileColor() local profileChange = function() setActiveProfile() activeProfileColor() loadSettings() resetFields() vBotConfigSave("atk") end for i=1,5 do local button = ui[i] button.onClick = function() AttackBotConfig.currentBotProfile = i profileChange() end end -- public functions AttackBot = {} -- global table AttackBot.isOn = function() return currentSettings.enabled end AttackBot.isOff = function() return not currentSettings.enabled end AttackBot.setOff = function() currentSettings.enabled = false ui.title:setOn(currentSettings.enabled) vBotConfigSave("atk") end AttackBot.setOn = function() currentSettings.enabled = true ui.title:setOn(currentSettings.enabled) vBotConfigSave("atk") end AttackBot.getActiveProfile = function() return AttackBotConfig.currentBotProfile -- returns number 1-5 end AttackBot.setActiveProfile = function(n) if not n or not tonumber(n) or n < 1 or n > 5 then return error("[AttackBot] wrong profile parameter! should be 1 to 5 is " .. n) else AttackBotConfig.currentBotProfile = n profileChange() end end AttackBot.show = function() mainWindow:show() mainWindow:raise() mainWindow:focus() end -- otui covered, now support functions function getPattern(category, pattern, safe) safe = safe and 2 or 1 return spellPatterns[category][pattern][safe] end function getMonstersInArea(category, posOrCreature, pattern, minHp, maxHp, safePattern, monsterNamesTable) -- monsterNamesTable can be nil local monsters = 0 local t = {} if monsterNamesTable == true or not monsterNamesTable then t = {} else t = monsterNamesTable end if safePattern then for i, spec in pairs(getSpectators(posOrCreature, safePattern)) do if spec ~= player and (spec:isPlayer() and not spec:isPartyMember()) then return 0 end end end if category == 1 or category == 3 or category == 4 then for i, spec in pairs(getSpectators()) do local specHp = spec:getHealthPercent() local name = spec:getName():lower() monsters = spec:isMonster() and specHp >= minHp and specHp <= maxHp and (#t == 0 or table.find(t, name)) and (g_game.getClientVersion() < 960 or spec:getType() < 3) and monsters + 1 or monsters end return monsters end for i, spec in pairs(getSpectators(posOrCreature, pattern)) do if spec ~= player then local specHp = spec:getHealthPercent() local name = spec:getName():lower() monsters = spec:isMonster() and specHp >= minHp and specHp <= maxHp and (#t == 0 or table.find(t, name)) and (g_game.getClientVersion() < 960 or spec:getType() < 3) and monsters + 1 or monsters end end return monsters end -- for area runes only -- should return valid targets number (int) and position function getBestTileByPattern(pattern, minHp, maxHp, safePattern, monsterNamesTable) local tiles = g_map.getTiles(posz()) local targetTile = {amount=0,pos=false} for i, tile in pairs(tiles) do local tPos = tile:getPosition() local distance = distanceFromPlayer(tPos) if tile:canShoot() and tile:isWalkable() and distance < 4 then local amount = getMonstersInArea(2, tPos, pattern, minHp, maxHp, safePattern, monsterNamesTable) if amount > targetTile.amount then targetTile = {amount=amount,pos=tPos} end end end return targetTile.amount > 0 and targetTile or false end function executeAttackBotAction(categoryOrPos, idOrFormula, cooldown) cooldown = cooldown or 0 if categoryOrPos == 4 or categoryOrPos == 5 or categoryOrPos == 1 then cast(idOrFormula, cooldown) elseif categoryOrPos == 3 then useWith(idOrFormula, target()) end end -- support function covered, now the main loop macro(100, function() if not currentSettings.enabled then return end if #currentSettings.attackTable == 0 or isInPz() or not target() or modules.game_cooldown.isGroupCooldownIconActive(1) then return end if currentSettings.Training and target() and target():getName():lower():find("training") then return end if g_game.getClientVersion() < 960 or not currentSettings.Cooldown then delay(400) end local monstersN = 0 local monstersE = 0 local monstersS = 0 local monstersW = 0 monstersN = getCreaturesInArea(pos(), posN, 2) monstersE = getCreaturesInArea(pos(), posE, 2) monstersS = getCreaturesInArea(pos(), posS, 2) monstersW = getCreaturesInArea(pos(), posW, 2) local posTable = {monstersE, monstersN, monstersS, monstersW} local bestSide = 0 local bestDir -- pulling out the biggest number for i, v in pairs(posTable) do if v > bestSide then bestSide = v end end -- associate biggest number with turn direction if monstersN == bestSide then bestDir = 0 elseif monstersE == bestSide then bestDir = 1 elseif monstersS == bestSide then bestDir = 2 elseif monstersW == bestSide then bestDir = 3 end if currentSettings.Rotate then if player:getDirection() ~= bestDir and bestSide > 0 then turn(bestDir) return end end -- support functions done, main spells now --[[ entry = { creatures = creatures, monsters = monsters, (formatted creatures) mana = mana, count = count, minHp = minHp, maxHp = maxHp, cooldown = cooldown, itemId = itemId, spell = spell, enabled = true, category = category, patternCategory = patternCategory, pattern = pattern, tooltip = tooltip, description = '['..type..'] '..count.. 'x '..specificMonsters..': '..attackType..', '..categoryName..' ('..minHp..'%-'..maxHp..'%)' } ]] for i, child in ipairs(panel.entryList:getChildren()) do local entry = child.params local attackData = entry.itemId > 100 and entry.itemId or entry.spell if entry.enabled and manapercent() >= entry.mana then if (type(attackData) == "string" and canCast(entry.spell, not currentSettings.ignoreMana, not currentSettings.Cooldown)) or (entry.itemId > 100 and (not currentSettings.Visible or findItem(entry.itemId))) then -- first PVP scenario if currentSettings.pvpMode and target():getHealthPercent() >= entry.minHp and target():getHealthPercent() <= entry.maxHp and target():canShoot() then if entry.category == 2 then return warn("[AttackBot] Area Runes cannot be used in PVP situation!") else return executeAttackBotAction(entry.category, attackData, entry.cooldown) end end -- empowerment if entry.category == 4 and not isBuffed() then local monsterAmount = getMonstersInArea(entry.category, nil, nil, entry.minHp, entry.maxHp, false, entry.monsters) if (entry.orMore and monsterAmount >= entry.count or not entry.orMore and monsterAmount == entry.count) and distanceFromPlayer(target():getPosition()) <= entry.pattern then return executeAttackBotAction(entry.category, attackData, entry.cooldown) end -- elseif entry.category == 1 or entry.category == 3 then local monsterAmount = getMonstersInArea(entry.category, nil, nil, entry.minHp, entry.maxHp, false, entry.monsters) if (entry.orMore and monsterAmount >= entry.count or not entry.orMore and monsterAmount == entry.count) and distanceFromPlayer(target():getPosition()) <= entry.pattern then return executeAttackBotAction(entry.category, attackData, entry.cooldown) end elseif entry.category == 5 then local pCat = entry.patternCategory local pattern = entry.pattern local anchorParam = (pattern == 2 or pattern == 6 or pattern == 7 or pattern > 9) and player or pos() local safe = currentSettings.PvpSafe and spellPatterns[pCat][entry.pattern][2] or false local monsterAmount = pCat ~= 8 and getMonstersInArea(entry.category, anchorParam, spellPatterns[pCat][entry.pattern][1], entry.minHp, entry.maxHp, safe, entry.monsters) if (pattern ~= 8 and (entry.orMore and monsterAmount >= entry.count or not entry.orMore and monsterAmount == entry.count)) or (pattern == 8 and bestSide >= entry.count and (not currentSettings.PvpSafe or getPlayers(2) == 0)) then if (not currentSettings.BlackListSafe or not isBlackListedPlayerInRange(currentSettings.AntiRsRange)) and (not currentSettings.Kills or killsToRs() > currentSettings.KillsAmount) then return executeAttackBotAction(entry.category, attackData, entry.cooldown) end end elseif entry.category == 2 then local pCat = entry.patternCategory local safe = currentSettings.PvpSafe and spellPatterns[pCat][entry.pattern][2] or false local data = getBestTileByPattern(spellPatterns[pCat][entry.pattern][1], entry.minHp, entry.maxHp, safe, entry.monsters) local monsterAmount local pos if data then monsterAmount = data.amount pos = data.pos end if monsterAmount and (entry.orMore and monsterAmount >= entry.count or not entry.orMore and monsterAmount == entry.count) then if (not currentSettings.BlackListSafe or not isBlackListedPlayerInRange(currentSettings.AntiRsRange)) and (not currentSettings.Kills or killsToRs() > currentSettings.KillsAmount) then return useWith(attackData, g_map.getTile(pos):getTopUseThing()) end end end end end end end)