mirror of
https://github.com/OTCv8/otclientv8.git
synced 2025-04-29 10:49:21 +02:00
1248 lines
33 KiB
Lua
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) |