2022-06-06 22:04:52 +00:00

1248 lines
33 KiB
Lua

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)