mirror of
https://github.com/OTCv8/otclientv8.git
synced 2025-10-19 06:03:27 +02:00
OTCv8 3.0 rev 2
This commit is contained in:
@@ -474,7 +474,9 @@ function initCallbacks()
|
||||
onChannelList = botChannelList,
|
||||
onOpenChannel = botOpenChannel,
|
||||
onCloseChannel = botCloseChannel,
|
||||
onChannelEvent = botChannelEvent
|
||||
onChannelEvent = botChannelEvent,
|
||||
onImbuementWindow = botOnImbuementWindow,
|
||||
onModalDialog = botOnModalDialog,
|
||||
})
|
||||
|
||||
connect(Tile, {
|
||||
@@ -527,7 +529,9 @@ function terminateCallbacks()
|
||||
onChannelList = botChannelList,
|
||||
onOpenChannel = botOpenChannel,
|
||||
onCloseChannel = botCloseChannel,
|
||||
onChannelEvent = botChannelEvent
|
||||
onChannelEvent = botChannelEvent,
|
||||
onImbuementWindow = botOnImbuementWindow,
|
||||
onModalDialog = botOnModalDialog,
|
||||
})
|
||||
|
||||
disconnect(Tile, {
|
||||
@@ -702,4 +706,14 @@ end
|
||||
function botCreatureWalk(creature, oldPos, newPos)
|
||||
if botExecutor == nil then return false end
|
||||
safeBotCall(function() botExecutor.callbacks.onWalk(creature, oldPos, newPos) end)
|
||||
end
|
||||
end
|
||||
|
||||
function botOnImbuementWindow(itemId, slots, activeSlots, imbuements, needItems)
|
||||
if botExecutor == nil then return false end
|
||||
safeBotCall(function() botExecutor.callbacks.onImbuementWindow(itemId, slots, activeSlots, imbuements, needItems) end)
|
||||
end
|
||||
|
||||
function botOnModalDialog(id, title, message, buttons, enterButton, escapeButton, choices, priority)
|
||||
if botExecutor == nil then return false end
|
||||
safeBotCall(function() botExecutor.callbacks.onModalDialog(id, title, message, buttons, enterButton, escapeButton, choices, priority) end)
|
||||
end
|
||||
|
@@ -1,8 +1,8 @@
|
||||
Module
|
||||
name: game_bot
|
||||
description: Advanced OTClientV8 Bot
|
||||
author: otclient@otclient.ovh
|
||||
sandboxed: true
|
||||
scripts: [ bot ]
|
||||
@onLoad: init()
|
||||
@onUnload: terminate()
|
||||
Module
|
||||
name: game_bot
|
||||
description: Advanced OTClientV8 Bot
|
||||
author: otclient@otclient.ovh
|
||||
sandboxed: true
|
||||
scripts: [ bot ]
|
||||
@onLoad: init()
|
||||
@onUnload: terminate()
|
||||
|
@@ -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]+),?\\s*([0-9]?)$"
|
||||
validation="^\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)$"
|
||||
})
|
||||
registerAction("use", {
|
||||
value=function() return posx() .. "," .. posy() .. "," .. posz() end,
|
||||
|
@@ -0,0 +1,23 @@
|
||||
goto:1033,1044,7
|
||||
goto:1031,1038,7
|
||||
goto:1030,1038,7
|
||||
goto:1157,985,7
|
||||
goto:1161,981,7
|
||||
goto:1033,1042,7
|
||||
goto:1034,1038,7
|
||||
goto:1169,985,7
|
||||
goto:1175,985,7
|
||||
goto:1176,983,7
|
||||
goto:756,846,7
|
||||
goto:756,846,7
|
||||
config:{"walk":100,"walk2":false}
|
||||
extensions:[[
|
||||
{
|
||||
"Depositer": [
|
||||
|
||||
],
|
||||
"Supply": [
|
||||
|
||||
]
|
||||
}
|
||||
]]
|
@@ -0,0 +1,13 @@
|
||||
goto:84,112,6
|
||||
goto:95,108,6
|
||||
config:{"mapClickDelay":100,"walkDelay":10,"ping":250,"ignoreFields":false,"useDelay":400,"mapClick":false}
|
||||
extensions:[[
|
||||
{
|
||||
"Depositer": [
|
||||
|
||||
],
|
||||
"Supply": [
|
||||
|
||||
]
|
||||
}
|
||||
]]
|
@@ -0,0 +1,104 @@
|
||||
goto:93,129,7
|
||||
goto:96,123,7
|
||||
goto:96,117,7
|
||||
goto:101,114,7
|
||||
goto:95,111,6
|
||||
goto:89,111,6
|
||||
goto:83,108,6
|
||||
goto:80,102,6
|
||||
goto:80,96,6
|
||||
goto:85,90,6
|
||||
goto:88,92,6
|
||||
goto:91,86,7
|
||||
goto:97,85,7
|
||||
goto:103,84,7
|
||||
function:[[
|
||||
|
||||
TargetBot.enableLuring()
|
||||
|
||||
return true
|
||||
|
||||
|
||||
]]
|
||||
goto:109,79,7
|
||||
goto:112,79,7
|
||||
goto:112,79,8
|
||||
function:[[
|
||||
|
||||
TargetBot.disableLuring()
|
||||
|
||||
return true
|
||||
|
||||
|
||||
]]
|
||||
goto:112,79,7
|
||||
goto:106,84,8
|
||||
goto:100,80,8
|
||||
goto:100,74,8
|
||||
goto:99,80,8
|
||||
goto:105,83,8
|
||||
function:[[
|
||||
TargetBot.setOff()
|
||||
return true
|
||||
]]
|
||||
goto:111,82,8
|
||||
goto:112,79,8
|
||||
goto:106,82,7
|
||||
goto:100,85,7
|
||||
goto:94,85,7
|
||||
goto:91,91,7
|
||||
goto:89,92,7
|
||||
goto:83,90,6
|
||||
function:[[
|
||||
TargetBot.setOff()
|
||||
return true
|
||||
]]
|
||||
goto:77,94,6
|
||||
goto:75,95,6
|
||||
goto:69,96,7
|
||||
goto:63,100,7
|
||||
goto:61,102,7
|
||||
goto:62,96,8
|
||||
use:61,102,8
|
||||
goto:62,101,8
|
||||
goto:68,99,7
|
||||
goto:74,95,7
|
||||
goto:75,95,7
|
||||
goto:79,101,6
|
||||
goto:81,107,6
|
||||
goto:87,109,6
|
||||
goto:93,112,6
|
||||
function:[[
|
||||
|
||||
TargetBot.disableLuring()
|
||||
|
||||
return true
|
||||
|
||||
|
||||
]]
|
||||
goto:99,116,6
|
||||
use:102,114,6
|
||||
goto:101,115,6
|
||||
use:100,116,5
|
||||
goto:101,115,5
|
||||
goto:100,116,4
|
||||
goto:102,114,5
|
||||
goto:101,114,6
|
||||
goto:96,120,7
|
||||
goto:95,126,7
|
||||
function:[[
|
||||
g_game.safeLogout()
|
||||
delay(1000)
|
||||
return "retry"
|
||||
]]
|
||||
config:{"useDelay":400,"mapClickDelay":100,"walkDelay":20,"ping":150,"ignoreFields":false,"skipBlocked":true,"mapClick":false}
|
||||
extensions:[[
|
||||
{
|
||||
"Depositer": [
|
||||
|
||||
],
|
||||
"Supply": [
|
||||
|
||||
]
|
||||
}
|
||||
]]
|
128
modules/game_bot/default_configs/cavebot_1.3/storage.json
Normal file
128
modules/game_bot/default_configs/cavebot_1.3/storage.json
Normal file
@@ -0,0 +1,128 @@
|
||||
{
|
||||
"hpitem1": {
|
||||
"max": 90,
|
||||
"title": "HP%",
|
||||
"subType": 0,
|
||||
"item": 266,
|
||||
"min": 51,
|
||||
"on": false
|
||||
},
|
||||
"foodItems": [
|
||||
{
|
||||
"id": 3582,
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"id": 3577,
|
||||
"count": 1
|
||||
}
|
||||
],
|
||||
"autoEquip": [
|
||||
{
|
||||
"item1": 3052,
|
||||
"title": "Auto Equip",
|
||||
"item2": 3089,
|
||||
"on": false,
|
||||
"slot": 9
|
||||
},
|
||||
{
|
||||
"item1": 0,
|
||||
"title": "Auto Equip",
|
||||
"item2": 0,
|
||||
"on": false,
|
||||
"slot": 0
|
||||
},
|
||||
{
|
||||
"item1": 0,
|
||||
"title": "Auto Equip",
|
||||
"item2": 0,
|
||||
"on": false,
|
||||
"slot": 0
|
||||
},
|
||||
{
|
||||
"item1": 0,
|
||||
"title": "Auto Equip",
|
||||
"item2": 0,
|
||||
"on": false,
|
||||
"slot": 0
|
||||
}
|
||||
],
|
||||
"ingame_hotkeys": "singlehotkey(\"f1\", function()\nlocal shaders = {\"stars\", \"gold\", \"rainbow\", \"sweden\", \"brazil\", \"line\", \"3line\", \"circle\", \"outline\"}\nlocal p = 0\nfor i, c in pairs(getSpectators()) do\n c:setOutfitShader(shaders[1 + p % 10])\n p = p + 1\nend\nend)\n\nsinglehotkey(\"1\", function()\n for _, s in ipairs(getSpectators()) do\n if s:canShoot(3) then\n info(s:getName())\n else\n warn(s:getName())\n end\n end\nend)",
|
||||
"healing2": {
|
||||
"max": 50,
|
||||
"title": "HP%",
|
||||
"on": false,
|
||||
"min": 1,
|
||||
"text": "exura vita"
|
||||
},
|
||||
"ingame_macros": "",
|
||||
"hasteSpell": "utani hur",
|
||||
"manaitem2": {
|
||||
"max": 50,
|
||||
"title": "MP%",
|
||||
"subType": 0,
|
||||
"item": 3157,
|
||||
"min": 0,
|
||||
"on": false
|
||||
},
|
||||
"_configs": {
|
||||
"cavebot_configs": {
|
||||
"selected": "test_src",
|
||||
"enabled": false
|
||||
},
|
||||
"targetbot_configs": {
|
||||
"enabled": false,
|
||||
"selected": "config_name"
|
||||
}
|
||||
},
|
||||
"healing1": {
|
||||
"max": 100,
|
||||
"title": "HP%",
|
||||
"on": false,
|
||||
"min": 51,
|
||||
"text": "exura"
|
||||
},
|
||||
"dropItems": [
|
||||
{
|
||||
"id": 283,
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"id": 284,
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"id": 285,
|
||||
"count": 1
|
||||
}
|
||||
],
|
||||
"_macros": {
|
||||
"": false
|
||||
},
|
||||
"manaitem1": {
|
||||
"max": 90,
|
||||
"title": "MP%",
|
||||
"subType": 0,
|
||||
"item": 268,
|
||||
"min": 51,
|
||||
"on": false
|
||||
},
|
||||
"hpitem2": {
|
||||
"max": 50,
|
||||
"title": "HP%",
|
||||
"subType": 0,
|
||||
"item": 3160,
|
||||
"min": 0,
|
||||
"on": false
|
||||
},
|
||||
"manaShield": "utamo vita",
|
||||
"autoTradeMessage": "I'm using OTClientV8!",
|
||||
"antiParalyze": "utani hur",
|
||||
"manaTrain": {
|
||||
"max": 100,
|
||||
"title": "MP%",
|
||||
"on": false,
|
||||
"min": 80,
|
||||
"text": "utevo lux"
|
||||
}
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"looting": {
|
||||
"items": [
|
||||
|
||||
],
|
||||
"maxDanger": 10,
|
||||
"minCapacity": 100,
|
||||
"containers": [
|
||||
{
|
||||
"count": 1,
|
||||
"id": 2853
|
||||
}
|
||||
],
|
||||
"everyItem": true
|
||||
},
|
||||
"targeting": [
|
||||
{
|
||||
"useSpellAttack": false,
|
||||
"useRuneAttack": false,
|
||||
"minMana": 200,
|
||||
"avoidAttacks": false,
|
||||
"groupAttackTargets": 2,
|
||||
"groupAttackSpell": "",
|
||||
"danger": 1,
|
||||
"runeAttackDelay": 2000,
|
||||
"lureCavebot": true,
|
||||
"dontLoot": false,
|
||||
"useGroupAttackRune": false,
|
||||
"groupRuneAttackRadius": 1,
|
||||
"groupAttackIgnorePlayers": true,
|
||||
"maxDistance": 10,
|
||||
"groupAttackIgnoreParty": false,
|
||||
"lureCount": 5,
|
||||
"useGroupAttack": false,
|
||||
"groupRuneAttackTargets": 2,
|
||||
"attackSpell": "",
|
||||
"groupAttackRune": 0,
|
||||
"groupAttackRadius": 1,
|
||||
"keepDistanceRange": 1,
|
||||
"groupRuneAttackDelay": 5000,
|
||||
"priority": 1,
|
||||
"attackRune": 0,
|
||||
"groupAttackDelay": 5000,
|
||||
"minManaGroup": 1500,
|
||||
"lure": true,
|
||||
"keepDistance": false,
|
||||
"attackSpellDelay": 2500,
|
||||
"chase": true,
|
||||
"name": "cat, w?lf, snake, troll",
|
||||
"regex": "^cat$|^w.?lf$|^snake$|^troll$"
|
||||
}
|
||||
]
|
||||
}
|
@@ -2,7 +2,7 @@ if player:getBlessings() == 0 then
|
||||
say("!bless")
|
||||
schedule(2000, function()
|
||||
if player:getBlessings() == 0 then
|
||||
error("!! Blessings not bought !!")
|
||||
warn("!! Blessings not bought !!")
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
@@ -1,348 +1,360 @@
|
||||
function executeBot(config, storage, tabs, msgCallback, saveConfigCallback, reloadCallback, websockets)
|
||||
-- load lua and otui files
|
||||
local configFiles = g_resources.listDirectoryFiles("/bot/" .. config, true, false)
|
||||
local luaFiles = {}
|
||||
local uiFiles = {}
|
||||
for i, file in ipairs(configFiles) do
|
||||
local ext = file:split(".")
|
||||
if ext[#ext]:lower() == "lua" then
|
||||
table.insert(luaFiles, file)
|
||||
end
|
||||
if ext[#ext]:lower() == "ui" or ext[#ext]:lower() == "otui" then
|
||||
table.insert(uiFiles, file)
|
||||
end
|
||||
end
|
||||
|
||||
if #luaFiles == 0 then
|
||||
return error("Config (/bot/" .. config .. ") doesn't have lua files")
|
||||
end
|
||||
|
||||
-- init bot variables
|
||||
local context = {}
|
||||
context.configDir = "/bot/".. config
|
||||
context.tabs = tabs
|
||||
context.mainTab = context.tabs:addTab("Main", g_ui.createWidget('BotPanel')).tabPanel.content
|
||||
context.panel = context.mainTab
|
||||
context.saveConfig = saveConfigCallback
|
||||
context.reload = reloadCallback
|
||||
|
||||
context.storage = storage
|
||||
if context.storage._macros == nil then
|
||||
context.storage._macros = {} -- active macros
|
||||
end
|
||||
|
||||
-- websockets, macros, hotkeys, scheduler, icons, callbacks
|
||||
context._websockets = websockets
|
||||
context._macros = {}
|
||||
context._hotkeys = {}
|
||||
context._scheduler = {}
|
||||
context._callbacks = {
|
||||
onKeyDown = {},
|
||||
onKeyUp = {},
|
||||
onKeyPress = {},
|
||||
onTalk = {},
|
||||
onTextMessage = {},
|
||||
onLoginAdvice = {},
|
||||
onAddThing = {},
|
||||
onRemoveThing = {},
|
||||
onCreatureAppear = {},
|
||||
onCreatureDisappear = {},
|
||||
onCreaturePositionChange = {},
|
||||
onCreatureHealthPercentChange = {},
|
||||
onUse = {},
|
||||
onUseWith = {},
|
||||
onContainerOpen = {},
|
||||
onContainerClose = {},
|
||||
onContainerUpdateItem = {},
|
||||
onMissle = {},
|
||||
onAnimatedText = {},
|
||||
onStaticText = {},
|
||||
onChannelList = {},
|
||||
onOpenChannel = {},
|
||||
onCloseChannel = {},
|
||||
onChannelEvent = {},
|
||||
onTurn = {},
|
||||
onWalk = {}
|
||||
}
|
||||
|
||||
-- basic functions & classes
|
||||
context.print = print
|
||||
context.pairs = pairs
|
||||
context.ipairs = ipairs
|
||||
context.tostring = tostring
|
||||
context.math = math
|
||||
context.table = table
|
||||
context.string = string
|
||||
context.tonumber = tonumber
|
||||
context.type = type
|
||||
context.pcall = pcall
|
||||
context.os = {
|
||||
time = os.time,
|
||||
date = os.date,
|
||||
difftime = os.difftime,
|
||||
date = os.date,
|
||||
clock = os.clock
|
||||
}
|
||||
context.load = function(str) return assert(load(str, nil, nil, context)) end
|
||||
context.loadstring = context.load
|
||||
context.assert = assert
|
||||
context.dofile = function(file) assert(load(g_resources.readFileContents("/bot/" .. config .. "/" .. file), file, nil, context))() end
|
||||
context.gcinfo = gcinfo
|
||||
context.tr = tr
|
||||
context.json = json
|
||||
context.base64 = base64
|
||||
context.regexMatch = regexMatch
|
||||
context.getDistanceBetween = function(p1, p2)
|
||||
return math.max(math.abs(p1.x - p2.x), math.abs(p1.y - p2.y))
|
||||
end
|
||||
context.isMobile = g_app.isMobile
|
||||
context.getVersion = g_app.getVersion
|
||||
|
||||
-- classes
|
||||
context.g_resources = g_resources
|
||||
context.g_game = g_game
|
||||
context.g_map = g_map
|
||||
context.g_ui = g_ui
|
||||
context.g_sounds = g_sounds
|
||||
context.g_window = g_window
|
||||
context.g_mouse = g_mouse
|
||||
context.g_things = g_things
|
||||
context.g_platform = {
|
||||
openUrl = g_platform.openUrl,
|
||||
openDir = g_platform.openDir,
|
||||
}
|
||||
|
||||
context.Item = Item
|
||||
context.Creature = Creature
|
||||
context.ThingType = ThingType
|
||||
context.Effect = Effect
|
||||
context.Missile = Missile
|
||||
context.Player = Player
|
||||
context.Monster = Monster
|
||||
context.StaticText = StaticText
|
||||
context.HTTP = HTTP
|
||||
context.OutputMessage = OutputMessage
|
||||
context.modules = modules
|
||||
|
||||
-- log functions
|
||||
context.info = function(text) return msgCallback("info", tostring(text)) end
|
||||
context.warn = function(text) return msgCallback("warn", tostring(text)) end
|
||||
context.error = function(text) return msgCallback("error", tostring(text)) end
|
||||
context.warning = context.warn
|
||||
|
||||
-- init context
|
||||
context.now = g_clock.millis()
|
||||
context.time = g_clock.millis()
|
||||
context.player = g_game.getLocalPlayer()
|
||||
|
||||
-- init functions
|
||||
G.botContext = context
|
||||
dofiles("functions")
|
||||
context.Panels = {}
|
||||
dofiles("panels")
|
||||
G.botContext = nil
|
||||
|
||||
-- run ui scripts
|
||||
for i, file in ipairs(uiFiles) do
|
||||
g_ui.importStyle(file)
|
||||
end
|
||||
|
||||
-- run lua script
|
||||
for i, file in ipairs(luaFiles) do
|
||||
assert(load(g_resources.readFileContents(file), file, nil, context))()
|
||||
context.panel = context.mainTab -- reset default tab
|
||||
end
|
||||
|
||||
return {
|
||||
script = function()
|
||||
context.now = g_clock.millis()
|
||||
context.time = g_clock.millis()
|
||||
|
||||
for i, macro in ipairs(context._macros) do
|
||||
if macro.lastExecution + macro.timeout <= context.now and macro.enabled then
|
||||
local status, result = pcall(function()
|
||||
if macro.callback(macro) then
|
||||
macro.lastExecution = context.now
|
||||
end
|
||||
end)
|
||||
if not status then
|
||||
context.error("Macro: " .. macro.name .. " execution error: " .. result)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
while #context._scheduler > 0 and context._scheduler[1].execution <= g_clock.millis() do
|
||||
local status, result = pcall(function()
|
||||
context._scheduler[1].callback()
|
||||
end)
|
||||
if not status then
|
||||
context.error("Schedule execution error: " .. result)
|
||||
end
|
||||
table.remove(context._scheduler, 1)
|
||||
end
|
||||
end,
|
||||
callbacks = {
|
||||
onKeyDown = function(keyCode, keyboardModifiers)
|
||||
local keyDesc = determineKeyComboDesc(keyCode, keyboardModifiers)
|
||||
for i, macro in ipairs(context._macros) do
|
||||
if macro.switch and macro.hotkey == keyDesc then
|
||||
macro.switch:onClick()
|
||||
end
|
||||
end
|
||||
local hotkey = context._hotkeys[keyDesc]
|
||||
if hotkey then
|
||||
if hotkey.single then
|
||||
if hotkey.callback() then
|
||||
hotkey.lastExecution = context.now
|
||||
end
|
||||
end
|
||||
if hotkey.switch then
|
||||
hotkey.switch:setOn(true)
|
||||
end
|
||||
end
|
||||
for i, callback in ipairs(context._callbacks.onKeyDown) do
|
||||
callback(keyDesc)
|
||||
end
|
||||
end,
|
||||
onKeyUp = function(keyCode, keyboardModifiers)
|
||||
local keyDesc = determineKeyComboDesc(keyCode, keyboardModifiers)
|
||||
local hotkey = context._hotkeys[keyDesc]
|
||||
if hotkey then
|
||||
if hotkey.switch then
|
||||
hotkey.switch:setOn(false)
|
||||
end
|
||||
end
|
||||
for i, callback in ipairs(context._callbacks.onKeyUp) do
|
||||
callback(keyDesc)
|
||||
end
|
||||
end,
|
||||
onKeyPress = function(keyCode, keyboardModifiers, autoRepeatTicks)
|
||||
local keyDesc = determineKeyComboDesc(keyCode, keyboardModifiers)
|
||||
local hotkey = context._hotkeys[keyDesc]
|
||||
if hotkey and not hotkey.single then
|
||||
if hotkey.callback() then
|
||||
hotkey.lastExecution = context.now
|
||||
end
|
||||
end
|
||||
for i, callback in ipairs(context._callbacks.onKeyPress) do
|
||||
callback(keyDesc, autoRepeatTicks)
|
||||
end
|
||||
end,
|
||||
onTalk = function(name, level, mode, text, channelId, pos)
|
||||
for i, callback in ipairs(context._callbacks.onTalk) do
|
||||
callback(name, level, mode, text, channelId, pos)
|
||||
end
|
||||
end,
|
||||
onTextMessage = function(mode, text)
|
||||
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
|
||||
callback(tile, thing)
|
||||
end
|
||||
end,
|
||||
onRemoveThing = function(tile, thing)
|
||||
for i, callback in ipairs(context._callbacks.onRemoveThing) do
|
||||
callback(tile, thing)
|
||||
end
|
||||
end,
|
||||
onCreatureAppear = function(creature)
|
||||
for i, callback in ipairs(context._callbacks.onCreatureAppear) do
|
||||
callback(creature)
|
||||
end
|
||||
end,
|
||||
onCreatureDisappear = function(creature)
|
||||
for i, callback in ipairs(context._callbacks.onCreatureDisappear) do
|
||||
callback(creature)
|
||||
end
|
||||
end,
|
||||
onCreaturePositionChange = function(creature, newPos, oldPos)
|
||||
for i, callback in ipairs(context._callbacks.onCreaturePositionChange) do
|
||||
callback(creature, newPos, oldPos)
|
||||
end
|
||||
end,
|
||||
onCreatureHealthPercentChange = function(creature, healthPercent)
|
||||
for i, callback in ipairs(context._callbacks.onCreatureHealthPercentChange) do
|
||||
callback(creature, healthPercent)
|
||||
end
|
||||
end,
|
||||
onUse = function(pos, itemId, stackPos, subType)
|
||||
for i, callback in ipairs(context._callbacks.onUse) do
|
||||
callback(pos, itemId, stackPos, subType)
|
||||
end
|
||||
end,
|
||||
onUseWith = function(pos, itemId, target, subType)
|
||||
for i, callback in ipairs(context._callbacks.onUseWith) do
|
||||
callback(pos, itemId, target, subType)
|
||||
end
|
||||
end,
|
||||
onContainerOpen = function(container, previousContainer)
|
||||
for i, callback in ipairs(context._callbacks.onContainerOpen) do
|
||||
callback(container, previousContainer)
|
||||
end
|
||||
end,
|
||||
onContainerClose = function(container)
|
||||
for i, callback in ipairs(context._callbacks.onContainerClose) do
|
||||
callback(container)
|
||||
end
|
||||
end,
|
||||
onContainerUpdateItem = function(container, slot, item)
|
||||
for i, callback in ipairs(context._callbacks.onContainerUpdateItem) do
|
||||
callback(container, slot, item)
|
||||
end
|
||||
end,
|
||||
onMissle = function(missle)
|
||||
for i, callback in ipairs(context._callbacks.onMissle) do
|
||||
callback(missle)
|
||||
end
|
||||
end,
|
||||
onAnimatedText = function(thing, text)
|
||||
for i, callback in ipairs(context._callbacks.onAnimatedText) do
|
||||
callback(thing, text)
|
||||
end
|
||||
end,
|
||||
onStaticText = function(thing, text)
|
||||
for i, callback in ipairs(context._callbacks.onStaticText) do
|
||||
callback(thing, text)
|
||||
end
|
||||
end,
|
||||
onChannelList = function(channels)
|
||||
for i, callback in ipairs(context._callbacks.onChannelList) do
|
||||
callback(channels)
|
||||
end
|
||||
end,
|
||||
onOpenChannel = function(channelId, channelName)
|
||||
for i, callback in ipairs(context._callbacks.onOpenChannel) do
|
||||
callback(channels)
|
||||
end
|
||||
end,
|
||||
onCloseChannel = function(channelId)
|
||||
for i, callback in ipairs(context._callbacks.onCloseChannel) do
|
||||
callback(channelId)
|
||||
end
|
||||
end,
|
||||
onChannelEvent = function(channelId, name, event)
|
||||
for i, callback in ipairs(context._callbacks.onChannelEvent) do
|
||||
callback(channelId, name, event)
|
||||
end
|
||||
end,
|
||||
onTurn = function(creature, direction)
|
||||
for i, callback in ipairs(context._callbacks.onTurn) do
|
||||
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,
|
||||
}
|
||||
}
|
||||
function executeBot(config, storage, tabs, msgCallback, saveConfigCallback, reloadCallback, websockets)
|
||||
-- load lua and otui files
|
||||
local configFiles = g_resources.listDirectoryFiles("/bot/" .. config, true, false)
|
||||
local luaFiles = {}
|
||||
local uiFiles = {}
|
||||
for i, file in ipairs(configFiles) do
|
||||
local ext = file:split(".")
|
||||
if ext[#ext]:lower() == "lua" then
|
||||
table.insert(luaFiles, file)
|
||||
end
|
||||
if ext[#ext]:lower() == "ui" or ext[#ext]:lower() == "otui" then
|
||||
table.insert(uiFiles, file)
|
||||
end
|
||||
end
|
||||
|
||||
if #luaFiles == 0 then
|
||||
return error("Config (/bot/" .. config .. ") doesn't have lua files")
|
||||
end
|
||||
|
||||
-- init bot variables
|
||||
local context = {}
|
||||
context.configDir = "/bot/".. config
|
||||
context.tabs = tabs
|
||||
context.mainTab = context.tabs:addTab("Main", g_ui.createWidget('BotPanel')).tabPanel.content
|
||||
context.panel = context.mainTab
|
||||
context.saveConfig = saveConfigCallback
|
||||
context.reload = reloadCallback
|
||||
|
||||
context.storage = storage
|
||||
if context.storage._macros == nil then
|
||||
context.storage._macros = {} -- active macros
|
||||
end
|
||||
|
||||
-- websockets, macros, hotkeys, scheduler, icons, callbacks
|
||||
context._websockets = websockets
|
||||
context._macros = {}
|
||||
context._hotkeys = {}
|
||||
context._scheduler = {}
|
||||
context._callbacks = {
|
||||
onKeyDown = {},
|
||||
onKeyUp = {},
|
||||
onKeyPress = {},
|
||||
onTalk = {},
|
||||
onTextMessage = {},
|
||||
onLoginAdvice = {},
|
||||
onAddThing = {},
|
||||
onRemoveThing = {},
|
||||
onCreatureAppear = {},
|
||||
onCreatureDisappear = {},
|
||||
onCreaturePositionChange = {},
|
||||
onCreatureHealthPercentChange = {},
|
||||
onUse = {},
|
||||
onUseWith = {},
|
||||
onContainerOpen = {},
|
||||
onContainerClose = {},
|
||||
onContainerUpdateItem = {},
|
||||
onMissle = {},
|
||||
onAnimatedText = {},
|
||||
onStaticText = {},
|
||||
onChannelList = {},
|
||||
onOpenChannel = {},
|
||||
onCloseChannel = {},
|
||||
onChannelEvent = {},
|
||||
onTurn = {},
|
||||
onWalk = {},
|
||||
onImbuementWindow = {},
|
||||
onModalDialog = {}
|
||||
}
|
||||
|
||||
-- basic functions & classes
|
||||
context.print = print
|
||||
context.pairs = pairs
|
||||
context.ipairs = ipairs
|
||||
context.tostring = tostring
|
||||
context.math = math
|
||||
context.table = table
|
||||
context.string = string
|
||||
context.tonumber = tonumber
|
||||
context.type = type
|
||||
context.pcall = pcall
|
||||
context.os = {
|
||||
time = os.time,
|
||||
date = os.date,
|
||||
difftime = os.difftime,
|
||||
date = os.date,
|
||||
clock = os.clock
|
||||
}
|
||||
context.load = function(str) return assert(load(str, nil, nil, context)) end
|
||||
context.loadstring = context.load
|
||||
context.assert = assert
|
||||
context.dofile = function(file) assert(load(g_resources.readFileContents("/bot/" .. config .. "/" .. file), file, nil, context))() end
|
||||
context.gcinfo = gcinfo
|
||||
context.tr = tr
|
||||
context.json = json
|
||||
context.base64 = base64
|
||||
context.regexMatch = regexMatch
|
||||
context.getDistanceBetween = function(p1, p2)
|
||||
return math.max(math.abs(p1.x - p2.x), math.abs(p1.y - p2.y))
|
||||
end
|
||||
context.isMobile = g_app.isMobile
|
||||
context.getVersion = g_app.getVersion
|
||||
|
||||
-- classes
|
||||
context.g_resources = g_resources
|
||||
context.g_game = g_game
|
||||
context.g_map = g_map
|
||||
context.g_ui = g_ui
|
||||
context.g_sounds = g_sounds
|
||||
context.g_window = g_window
|
||||
context.g_mouse = g_mouse
|
||||
context.g_things = g_things
|
||||
context.g_platform = {
|
||||
openUrl = g_platform.openUrl,
|
||||
openDir = g_platform.openDir,
|
||||
}
|
||||
|
||||
context.Item = Item
|
||||
context.Creature = Creature
|
||||
context.ThingType = ThingType
|
||||
context.Effect = Effect
|
||||
context.Missile = Missile
|
||||
context.Player = Player
|
||||
context.Monster = Monster
|
||||
context.StaticText = StaticText
|
||||
context.HTTP = HTTP
|
||||
context.OutputMessage = OutputMessage
|
||||
context.modules = modules
|
||||
|
||||
-- log functions
|
||||
context.info = function(text) return msgCallback("info", tostring(text)) end
|
||||
context.warn = function(text) return msgCallback("warn", tostring(text)) end
|
||||
context.error = function(text) return msgCallback("error", tostring(text)) end
|
||||
context.warning = context.warn
|
||||
|
||||
-- init context
|
||||
context.now = g_clock.millis()
|
||||
context.time = g_clock.millis()
|
||||
context.player = g_game.getLocalPlayer()
|
||||
|
||||
-- init functions
|
||||
G.botContext = context
|
||||
dofiles("functions")
|
||||
context.Panels = {}
|
||||
dofiles("panels")
|
||||
G.botContext = nil
|
||||
|
||||
-- run ui scripts
|
||||
for i, file in ipairs(uiFiles) do
|
||||
g_ui.importStyle(file)
|
||||
end
|
||||
|
||||
-- run lua script
|
||||
for i, file in ipairs(luaFiles) do
|
||||
assert(load(g_resources.readFileContents(file), file, nil, context))()
|
||||
context.panel = context.mainTab -- reset default tab
|
||||
end
|
||||
|
||||
return {
|
||||
script = function()
|
||||
context.now = g_clock.millis()
|
||||
context.time = g_clock.millis()
|
||||
|
||||
for i, macro in ipairs(context._macros) do
|
||||
if macro.lastExecution + macro.timeout <= context.now and macro.enabled then
|
||||
local status, result = pcall(function()
|
||||
if macro.callback(macro) then
|
||||
macro.lastExecution = context.now
|
||||
end
|
||||
end)
|
||||
if not status then
|
||||
context.error("Macro: " .. macro.name .. " execution error: " .. result)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
while #context._scheduler > 0 and context._scheduler[1].execution <= g_clock.millis() do
|
||||
local status, result = pcall(function()
|
||||
context._scheduler[1].callback()
|
||||
end)
|
||||
if not status then
|
||||
context.error("Schedule execution error: " .. result)
|
||||
end
|
||||
table.remove(context._scheduler, 1)
|
||||
end
|
||||
end,
|
||||
callbacks = {
|
||||
onKeyDown = function(keyCode, keyboardModifiers)
|
||||
local keyDesc = determineKeyComboDesc(keyCode, keyboardModifiers)
|
||||
for i, macro in ipairs(context._macros) do
|
||||
if macro.switch and macro.hotkey == keyDesc then
|
||||
macro.switch:onClick()
|
||||
end
|
||||
end
|
||||
local hotkey = context._hotkeys[keyDesc]
|
||||
if hotkey then
|
||||
if hotkey.single then
|
||||
if hotkey.callback() then
|
||||
hotkey.lastExecution = context.now
|
||||
end
|
||||
end
|
||||
if hotkey.switch then
|
||||
hotkey.switch:setOn(true)
|
||||
end
|
||||
end
|
||||
for i, callback in ipairs(context._callbacks.onKeyDown) do
|
||||
callback(keyDesc)
|
||||
end
|
||||
end,
|
||||
onKeyUp = function(keyCode, keyboardModifiers)
|
||||
local keyDesc = determineKeyComboDesc(keyCode, keyboardModifiers)
|
||||
local hotkey = context._hotkeys[keyDesc]
|
||||
if hotkey then
|
||||
if hotkey.switch then
|
||||
hotkey.switch:setOn(false)
|
||||
end
|
||||
end
|
||||
for i, callback in ipairs(context._callbacks.onKeyUp) do
|
||||
callback(keyDesc)
|
||||
end
|
||||
end,
|
||||
onKeyPress = function(keyCode, keyboardModifiers, autoRepeatTicks)
|
||||
local keyDesc = determineKeyComboDesc(keyCode, keyboardModifiers)
|
||||
local hotkey = context._hotkeys[keyDesc]
|
||||
if hotkey and not hotkey.single then
|
||||
if hotkey.callback() then
|
||||
hotkey.lastExecution = context.now
|
||||
end
|
||||
end
|
||||
for i, callback in ipairs(context._callbacks.onKeyPress) do
|
||||
callback(keyDesc, autoRepeatTicks)
|
||||
end
|
||||
end,
|
||||
onTalk = function(name, level, mode, text, channelId, pos)
|
||||
for i, callback in ipairs(context._callbacks.onTalk) do
|
||||
callback(name, level, mode, text, channelId, pos)
|
||||
end
|
||||
end,
|
||||
onImbuementWindow = function(itemId, slots, activeSlots, imbuements, needItems)
|
||||
for i, callback in ipairs(context._callbacks.onImbuementWindow) do
|
||||
callback(itemId, slots, activeSlots, imbuements, needItems)
|
||||
end
|
||||
end,
|
||||
onTextMessage = function(mode, text)
|
||||
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
|
||||
callback(tile, thing)
|
||||
end
|
||||
end,
|
||||
onRemoveThing = function(tile, thing)
|
||||
for i, callback in ipairs(context._callbacks.onRemoveThing) do
|
||||
callback(tile, thing)
|
||||
end
|
||||
end,
|
||||
onCreatureAppear = function(creature)
|
||||
for i, callback in ipairs(context._callbacks.onCreatureAppear) do
|
||||
callback(creature)
|
||||
end
|
||||
end,
|
||||
onCreatureDisappear = function(creature)
|
||||
for i, callback in ipairs(context._callbacks.onCreatureDisappear) do
|
||||
callback(creature)
|
||||
end
|
||||
end,
|
||||
onCreaturePositionChange = function(creature, newPos, oldPos)
|
||||
for i, callback in ipairs(context._callbacks.onCreaturePositionChange) do
|
||||
callback(creature, newPos, oldPos)
|
||||
end
|
||||
end,
|
||||
onCreatureHealthPercentChange = function(creature, healthPercent)
|
||||
for i, callback in ipairs(context._callbacks.onCreatureHealthPercentChange) do
|
||||
callback(creature, healthPercent)
|
||||
end
|
||||
end,
|
||||
onUse = function(pos, itemId, stackPos, subType)
|
||||
for i, callback in ipairs(context._callbacks.onUse) do
|
||||
callback(pos, itemId, stackPos, subType)
|
||||
end
|
||||
end,
|
||||
onUseWith = function(pos, itemId, target, subType)
|
||||
for i, callback in ipairs(context._callbacks.onUseWith) do
|
||||
callback(pos, itemId, target, subType)
|
||||
end
|
||||
end,
|
||||
onContainerOpen = function(container, previousContainer)
|
||||
for i, callback in ipairs(context._callbacks.onContainerOpen) do
|
||||
callback(container, previousContainer)
|
||||
end
|
||||
end,
|
||||
onContainerClose = function(container)
|
||||
for i, callback in ipairs(context._callbacks.onContainerClose) do
|
||||
callback(container)
|
||||
end
|
||||
end,
|
||||
onContainerUpdateItem = function(container, slot, item)
|
||||
for i, callback in ipairs(context._callbacks.onContainerUpdateItem) do
|
||||
callback(container, slot, item)
|
||||
end
|
||||
end,
|
||||
onMissle = function(missle)
|
||||
for i, callback in ipairs(context._callbacks.onMissle) do
|
||||
callback(missle)
|
||||
end
|
||||
end,
|
||||
onAnimatedText = function(thing, text)
|
||||
for i, callback in ipairs(context._callbacks.onAnimatedText) do
|
||||
callback(thing, text)
|
||||
end
|
||||
end,
|
||||
onStaticText = function(thing, text)
|
||||
for i, callback in ipairs(context._callbacks.onStaticText) do
|
||||
callback(thing, text)
|
||||
end
|
||||
end,
|
||||
onChannelList = function(channels)
|
||||
for i, callback in ipairs(context._callbacks.onChannelList) do
|
||||
callback(channels)
|
||||
end
|
||||
end,
|
||||
onOpenChannel = function(channelId, channelName)
|
||||
for i, callback in ipairs(context._callbacks.onOpenChannel) do
|
||||
callback(channels)
|
||||
end
|
||||
end,
|
||||
onCloseChannel = function(channelId)
|
||||
for i, callback in ipairs(context._callbacks.onCloseChannel) do
|
||||
callback(channelId)
|
||||
end
|
||||
end,
|
||||
onChannelEvent = function(channelId, name, event)
|
||||
for i, callback in ipairs(context._callbacks.onChannelEvent) do
|
||||
callback(channelId, name, event)
|
||||
end
|
||||
end,
|
||||
onTurn = function(creature, direction)
|
||||
for i, callback in ipairs(context._callbacks.onTurn) do
|
||||
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,
|
||||
onModalDialog = function(id, title, message, buttons, enterButton, escapeButton, choices, priority)
|
||||
for i, callback in ipairs(context._callbacks.onModalDialog) do
|
||||
callback(id, title, message, buttons, enterButton, escapeButton, choices, priority)
|
||||
end
|
||||
end,
|
||||
}
|
||||
}
|
||||
end
|
@@ -1,207 +1,217 @@
|
||||
local context = G.botContext
|
||||
|
||||
-- callback(callbackType, callback)
|
||||
context.callback = function(callbackType, callback)
|
||||
if not context._callbacks[callbackType] then
|
||||
return error("Wrong callback type: " .. callbackType)
|
||||
end
|
||||
if callbackType == "onAddThing" or callbackType == "onRemoveThing" then
|
||||
g_game.enableTileThingLuaCallback(true)
|
||||
end
|
||||
|
||||
local desc = "lua"
|
||||
local info = debug.getinfo(2, "Sl")
|
||||
if info then
|
||||
desc = info.short_src .. ":" .. info.currentline
|
||||
end
|
||||
|
||||
local callbackData = {}
|
||||
table.insert(context._callbacks[callbackType], function(...)
|
||||
if not callbackData.delay or callbackData.delay < context.now then
|
||||
local prevExecution = context._currentExecution
|
||||
context._currentExecution = callbackData
|
||||
local start = g_clock.realMillis()
|
||||
callback(...)
|
||||
local executionTime = g_clock.realMillis() - start
|
||||
if executionTime > 100 then
|
||||
context.warning("Slow " .. callbackType .. " (" .. executionTime .. "ms): " .. desc)
|
||||
end
|
||||
context._currentExecution = prevExecution
|
||||
end
|
||||
end)
|
||||
local cb = context._callbacks[callbackType]
|
||||
return {
|
||||
remove = function()
|
||||
local index = nil
|
||||
for i, cb2 in ipairs(context._callbacks[callbackType]) do
|
||||
if cb == cb2 then
|
||||
index = i
|
||||
end
|
||||
end
|
||||
if index then
|
||||
table.remove(context._callbacks[callbackType], index)
|
||||
end
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
-- onKeyDown(callback) -- callback = function(keys)
|
||||
context.onKeyDown = function(callback)
|
||||
return context.callback("onKeyDown", callback)
|
||||
end
|
||||
|
||||
-- onKeyPress(callback) -- callback = function(keys)
|
||||
context.onKeyPress = function(callback)
|
||||
return context.callback("onKeyPress", callback)
|
||||
end
|
||||
|
||||
-- onKeyUp(callback) -- callback = function(keys)
|
||||
context.onKeyUp = function(callback)
|
||||
return context.callback("onKeyUp", callback)
|
||||
end
|
||||
|
||||
-- onTalk(callback) -- callback = function(name, level, mode, text, channelId, pos)
|
||||
context.onTalk = function(callback)
|
||||
return context.callback("onTalk", callback)
|
||||
end
|
||||
|
||||
-- onTextMessage(callback) -- callback = function(mode, text)
|
||||
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)
|
||||
end
|
||||
|
||||
-- onRemoveThing(callback) -- callback = function(tile, thing)
|
||||
context.onRemoveThing = function(callback)
|
||||
return context.callback("onRemoveThing", callback)
|
||||
end
|
||||
|
||||
-- onCreatureAppear(callback) -- callback = function(creature)
|
||||
context.onCreatureAppear = function(callback)
|
||||
return context.callback("onCreatureAppear", callback)
|
||||
end
|
||||
|
||||
-- onCreatureDisappear(callback) -- callback = function(creature)
|
||||
context.onCreatureDisappear = function(callback)
|
||||
return context.callback("onCreatureDisappear", callback)
|
||||
end
|
||||
|
||||
-- onCreaturePositionChange(callback) -- callback = function(creature, newPos, oldPos)
|
||||
context.onCreaturePositionChange = function(callback)
|
||||
return context.callback("onCreaturePositionChange", callback)
|
||||
end
|
||||
|
||||
-- onCreatureHealthPercentChange(callback) -- callback = function(creature, healthPercent)
|
||||
context.onCreatureHealthPercentChange = function(callback)
|
||||
return context.callback("onCreatureHealthPercentChange", callback)
|
||||
end
|
||||
|
||||
-- onUse(callback) -- callback = function(pos, itemId, stackPos, subType)
|
||||
context.onUse = function(callback)
|
||||
return context.callback("onUse", callback)
|
||||
end
|
||||
|
||||
-- onUseWith(callback) -- callback = function(pos, itemId, target, subType)
|
||||
context.onUseWith = function(callback)
|
||||
return context.callback("onUseWith", callback)
|
||||
end
|
||||
|
||||
-- onContainerOpen -- callback = function(container, previousContainer)
|
||||
context.onContainerOpen = function(callback)
|
||||
return context.callback("onContainerOpen", callback)
|
||||
end
|
||||
|
||||
-- onContainerClose -- callback = function(container)
|
||||
context.onContainerClose = function(callback)
|
||||
return context.callback("onContainerClose", callback)
|
||||
end
|
||||
|
||||
-- onContainerUpdateItem -- callback = function(container, slot, item)
|
||||
context.onContainerUpdateItem = function(callback)
|
||||
return context.callback("onContainerUpdateItem", callback)
|
||||
end
|
||||
|
||||
-- onMissle -- callback = function(missle)
|
||||
context.onMissle = function(callback)
|
||||
return context.callback("onMissle", callback)
|
||||
end
|
||||
|
||||
-- onAnimatedText -- callback = function(thing, text)
|
||||
context.onAnimatedText = function(callback)
|
||||
return context.callback("onAnimatedText", callback)
|
||||
end
|
||||
|
||||
-- onStaticText -- callback = function(thing, text)
|
||||
context.onStaticText = function(callback)
|
||||
return context.callback("onStaticText", callback)
|
||||
end
|
||||
|
||||
-- onChannelList -- callback = function(channels)
|
||||
context.onChannelList = function(callback)
|
||||
return context.callback("onChannelList", callback)
|
||||
end
|
||||
|
||||
-- onOpenChannel -- callback = function(channelId, name)
|
||||
context.onOpenChannel = function(callback)
|
||||
return context.callback("onOpenChannel", callback)
|
||||
end
|
||||
|
||||
-- onCloseChannel -- callback = function(channelId)
|
||||
context.onCloseChannel = function(callback)
|
||||
return context.callback("onCloseChannel", callback)
|
||||
end
|
||||
|
||||
-- onChannelEvent -- callback = function(channelId, name, event)
|
||||
context.onChannelEvent = function(callback)
|
||||
return context.callback("onChannelEvent", callback)
|
||||
end
|
||||
|
||||
-- onTurn -- callback = function(creature, direction)
|
||||
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
|
||||
|
||||
-- listen(name, callback) -- callback = function(text, channelId, pos)
|
||||
context.listen = function(name, callback)
|
||||
if not name then return context.error("listen: invalid name") end
|
||||
name = name:lower()
|
||||
return context.onTalk(function(name2, level, mode, text, channelId, pos)
|
||||
if name == name2:lower() then
|
||||
callback(text, channelId, pos)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- onPlayerPositionChange(callback) -- callback = function(newPos, oldPos)
|
||||
context.onPlayerPositionChange = function(callback)
|
||||
return context.onCreaturePositionChange(function(creature, newPos, oldPos)
|
||||
if creature == context.player then
|
||||
callback(newPos, oldPos)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- onPlayerHealthChange(callback) -- callback = function(healthPercent)
|
||||
context.onPlayerHealthChange = function(callback)
|
||||
return context.onCreatureHealthPercentChange(function(creature, healthPercent)
|
||||
if creature == context.player then
|
||||
callback(healthPercent)
|
||||
end
|
||||
end)
|
||||
local context = G.botContext
|
||||
|
||||
-- callback(callbackType, callback)
|
||||
context.callback = function(callbackType, callback)
|
||||
if not context._callbacks[callbackType] then
|
||||
return error("Wrong callback type: " .. callbackType)
|
||||
end
|
||||
if callbackType == "onAddThing" or callbackType == "onRemoveThing" then
|
||||
g_game.enableTileThingLuaCallback(true)
|
||||
end
|
||||
|
||||
local desc = "lua"
|
||||
local info = debug.getinfo(2, "Sl")
|
||||
if info then
|
||||
desc = info.short_src .. ":" .. info.currentline
|
||||
end
|
||||
|
||||
local callbackData = {}
|
||||
table.insert(context._callbacks[callbackType], function(...)
|
||||
if not callbackData.delay or callbackData.delay < context.now then
|
||||
local prevExecution = context._currentExecution
|
||||
context._currentExecution = callbackData
|
||||
local start = g_clock.realMillis()
|
||||
callback(...)
|
||||
local executionTime = g_clock.realMillis() - start
|
||||
if executionTime > 100 then
|
||||
context.warning("Slow " .. callbackType .. " (" .. executionTime .. "ms): " .. desc)
|
||||
end
|
||||
context._currentExecution = prevExecution
|
||||
end
|
||||
end)
|
||||
local cb = context._callbacks[callbackType]
|
||||
return {
|
||||
remove = function()
|
||||
local index = nil
|
||||
for i, cb2 in ipairs(context._callbacks[callbackType]) do
|
||||
if cb == cb2 then
|
||||
index = i
|
||||
end
|
||||
end
|
||||
if index then
|
||||
table.remove(context._callbacks[callbackType], index)
|
||||
end
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
-- onKeyDown(callback) -- callback = function(keys)
|
||||
context.onKeyDown = function(callback)
|
||||
return context.callback("onKeyDown", callback)
|
||||
end
|
||||
|
||||
-- onKeyPress(callback) -- callback = function(keys)
|
||||
context.onKeyPress = function(callback)
|
||||
return context.callback("onKeyPress", callback)
|
||||
end
|
||||
|
||||
-- onKeyUp(callback) -- callback = function(keys)
|
||||
context.onKeyUp = function(callback)
|
||||
return context.callback("onKeyUp", callback)
|
||||
end
|
||||
|
||||
-- onTalk(callback) -- callback = function(name, level, mode, text, channelId, pos)
|
||||
context.onTalk = function(callback)
|
||||
return context.callback("onTalk", callback)
|
||||
end
|
||||
|
||||
-- onTextMessage(callback) -- callback = function(mode, text)
|
||||
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)
|
||||
end
|
||||
|
||||
-- onRemoveThing(callback) -- callback = function(tile, thing)
|
||||
context.onRemoveThing = function(callback)
|
||||
return context.callback("onRemoveThing", callback)
|
||||
end
|
||||
|
||||
-- onCreatureAppear(callback) -- callback = function(creature)
|
||||
context.onCreatureAppear = function(callback)
|
||||
return context.callback("onCreatureAppear", callback)
|
||||
end
|
||||
|
||||
-- onCreatureDisappear(callback) -- callback = function(creature)
|
||||
context.onCreatureDisappear = function(callback)
|
||||
return context.callback("onCreatureDisappear", callback)
|
||||
end
|
||||
|
||||
-- onCreaturePositionChange(callback) -- callback = function(creature, newPos, oldPos)
|
||||
context.onCreaturePositionChange = function(callback)
|
||||
return context.callback("onCreaturePositionChange", callback)
|
||||
end
|
||||
|
||||
-- onCreatureHealthPercentChange(callback) -- callback = function(creature, healthPercent)
|
||||
context.onCreatureHealthPercentChange = function(callback)
|
||||
return context.callback("onCreatureHealthPercentChange", callback)
|
||||
end
|
||||
|
||||
-- onUse(callback) -- callback = function(pos, itemId, stackPos, subType)
|
||||
context.onUse = function(callback)
|
||||
return context.callback("onUse", callback)
|
||||
end
|
||||
|
||||
-- onUseWith(callback) -- callback = function(pos, itemId, target, subType)
|
||||
context.onUseWith = function(callback)
|
||||
return context.callback("onUseWith", callback)
|
||||
end
|
||||
|
||||
-- onContainerOpen -- callback = function(container, previousContainer)
|
||||
context.onContainerOpen = function(callback)
|
||||
return context.callback("onContainerOpen", callback)
|
||||
end
|
||||
|
||||
-- onContainerClose -- callback = function(container)
|
||||
context.onContainerClose = function(callback)
|
||||
return context.callback("onContainerClose", callback)
|
||||
end
|
||||
|
||||
-- onContainerUpdateItem -- callback = function(container, slot, item)
|
||||
context.onContainerUpdateItem = function(callback)
|
||||
return context.callback("onContainerUpdateItem", callback)
|
||||
end
|
||||
|
||||
-- onMissle -- callback = function(missle)
|
||||
context.onMissle = function(callback)
|
||||
return context.callback("onMissle", callback)
|
||||
end
|
||||
|
||||
-- onAnimatedText -- callback = function(thing, text)
|
||||
context.onAnimatedText = function(callback)
|
||||
return context.callback("onAnimatedText", callback)
|
||||
end
|
||||
|
||||
-- onStaticText -- callback = function(thing, text)
|
||||
context.onStaticText = function(callback)
|
||||
return context.callback("onStaticText", callback)
|
||||
end
|
||||
|
||||
-- onChannelList -- callback = function(channels)
|
||||
context.onChannelList = function(callback)
|
||||
return context.callback("onChannelList", callback)
|
||||
end
|
||||
|
||||
-- onOpenChannel -- callback = function(channelId, name)
|
||||
context.onOpenChannel = function(callback)
|
||||
return context.callback("onOpenChannel", callback)
|
||||
end
|
||||
|
||||
-- onCloseChannel -- callback = function(channelId)
|
||||
context.onCloseChannel = function(callback)
|
||||
return context.callback("onCloseChannel", callback)
|
||||
end
|
||||
|
||||
-- onChannelEvent -- callback = function(channelId, name, event)
|
||||
context.onChannelEvent = function(callback)
|
||||
return context.callback("onChannelEvent", callback)
|
||||
end
|
||||
|
||||
-- onTurn -- callback = function(creature, direction)
|
||||
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
|
||||
|
||||
-- onImbuementWindow -- callback = function(itemId, slots, activeSlots, imbuements, needItems)
|
||||
context.onImbuementWindow = function(callback)
|
||||
return context.callback("onImbuementWindow", callback)
|
||||
end
|
||||
|
||||
-- onModalDialog -- callback = function(id, title, message, buttons, enterButton, escapeButton, choices, priority) -- priority is unused, ignore it
|
||||
context.onModalDialog = function(callback)
|
||||
return context.callback("onModalDialog", callback)
|
||||
end
|
||||
|
||||
-- CUSTOM CALLBACKS
|
||||
|
||||
-- listen(name, callback) -- callback = function(text, channelId, pos)
|
||||
context.listen = function(name, callback)
|
||||
if not name then return context.error("listen: invalid name") end
|
||||
name = name:lower()
|
||||
return context.onTalk(function(name2, level, mode, text, channelId, pos)
|
||||
if name == name2:lower() then
|
||||
callback(text, channelId, pos)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- onPlayerPositionChange(callback) -- callback = function(newPos, oldPos)
|
||||
context.onPlayerPositionChange = function(callback)
|
||||
return context.onCreaturePositionChange(function(creature, newPos, oldPos)
|
||||
if creature == context.player then
|
||||
callback(newPos, oldPos)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- onPlayerHealthChange(callback) -- callback = function(healthPercent)
|
||||
context.onPlayerHealthChange = function(callback)
|
||||
return context.onCreatureHealthPercentChange(function(creature, healthPercent)
|
||||
if creature == context.player then
|
||||
callback(healthPercent)
|
||||
end
|
||||
end)
|
||||
end
|
@@ -1,266 +1,266 @@
|
||||
--[[
|
||||
Config - create, load and save config file (.json / .cfg)
|
||||
Used by cavebot and other things
|
||||
]]--
|
||||
|
||||
local context = G.botContext
|
||||
context.Config = {}
|
||||
local Config = context.Config
|
||||
|
||||
Config.exist = function(dir)
|
||||
return g_resources.directoryExists(context.configDir .. "/" .. dir)
|
||||
end
|
||||
|
||||
Config.create = function(dir)
|
||||
g_resources.makeDir(context.configDir .. "/" .. dir)
|
||||
return Config.exist(dir)
|
||||
end
|
||||
|
||||
Config.list = function(dir)
|
||||
if not Config.exist(dir) then
|
||||
if not Config.create(dir) then
|
||||
return contex.error("Can't create config dir: " .. context.configDir .. "/" .. dir)
|
||||
end
|
||||
end
|
||||
local list = g_resources.listDirectoryFiles(context.configDir .. "/" .. dir)
|
||||
local correctList = {}
|
||||
for k,v in ipairs(list) do -- filter files
|
||||
local nv = v:gsub(".json", ""):gsub(".cfg", "")
|
||||
if nv ~= v then
|
||||
table.insert(correctList, nv)
|
||||
end
|
||||
end
|
||||
return correctList
|
||||
end
|
||||
|
||||
-- load config from string insteaf of file
|
||||
Config.parse = function(data)
|
||||
local status, result = pcall(function()
|
||||
if data:len() < 2 then return {} end
|
||||
return json.decode(data)
|
||||
end)
|
||||
if status and type(result) == 'table' then
|
||||
return result
|
||||
end
|
||||
local status, result = pcall(function()
|
||||
return table.decodeStringPairList(data)
|
||||
end)
|
||||
if status and type(result) == 'table' then
|
||||
return result
|
||||
end
|
||||
return context.error("Invalid config format")
|
||||
end
|
||||
|
||||
Config.load = function(dir, name)
|
||||
local file = context.configDir .. "/" .. dir .. "/" .. name .. ".json"
|
||||
if g_resources.fileExists(file) then -- load json
|
||||
local status, result = pcall(function()
|
||||
local data = g_resources.readFileContents(file)
|
||||
if data:len() < 2 then return {} end
|
||||
return json.decode(data)
|
||||
end)
|
||||
if not status then
|
||||
context.error("Invalid json config (" .. name .. "): " .. result)
|
||||
return {}
|
||||
end
|
||||
return result
|
||||
end
|
||||
file = context.configDir .. "/" .. dir .. "/" .. name .. ".cfg"
|
||||
if g_resources.fileExists(file) then -- load cfg
|
||||
local status, result = pcall(function()
|
||||
return table.decodeStringPairList(g_resources.readFileContents(file))
|
||||
end)
|
||||
if not status then
|
||||
context.error("Invalid cfg config (" .. name .. "): " .. result)
|
||||
return {}
|
||||
end
|
||||
return result
|
||||
end
|
||||
return context.error("Config " .. file .. " doesn't exist")
|
||||
end
|
||||
|
||||
Config.loadRaw = function(dir, name)
|
||||
local file = context.configDir .. "/" .. dir .. "/" .. name .. ".json"
|
||||
if g_resources.fileExists(file) then -- load json
|
||||
return g_resources.readFileContents(file)
|
||||
end
|
||||
file = context.configDir .. "/" .. dir .. "/" .. name .. ".cfg"
|
||||
if g_resources.fileExists(file) then -- load cfg
|
||||
return g_resources.readFileContents(file)
|
||||
end
|
||||
return context.error("Config " .. file .. " doesn't exist")
|
||||
end
|
||||
|
||||
Config.save = function(dir, name, value, forcedExtension)
|
||||
if not Config.exist(dir) then
|
||||
if not Config.create(dir) then
|
||||
return contex.error("Can't create config dir: " .. context.configDir .. "/" .. dir)
|
||||
end
|
||||
end
|
||||
if type(value) ~= 'table' then
|
||||
return context.error("Invalid config value type: " .. type(value) .. ", should be table")
|
||||
end
|
||||
local file = context.configDir .. "/" .. dir .. "/" .. name
|
||||
if (table.isStringPairList(value) and forcedExtension ~= "json") or forcedExtension == "cfg" then -- cfg
|
||||
g_resources.writeFileContents(file .. ".cfg", table.encodeStringPairList(value))
|
||||
else
|
||||
g_resources.writeFileContents(file .. ".json", json.encode(value, 2))
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
Config.remove = function(dir, name)
|
||||
local file = context.configDir .. "/" .. dir .. "/" .. name .. ".json"
|
||||
local ret = false
|
||||
if g_resources.fileExists(file) then
|
||||
g_resources.deleteFile(file)
|
||||
ret = true
|
||||
end
|
||||
file = context.configDir .. "/" .. dir .. "/" .. name .. ".cfg"
|
||||
if g_resources.fileExists(file) then
|
||||
g_resources.deleteFile(file)
|
||||
ret = true
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
-- setup is used for BotConfig widget
|
||||
-- not done yet
|
||||
Config.setup = function(dir, widget, configExtension, callback)
|
||||
if type(dir) ~= 'string' or dir:len() == 0 then
|
||||
return context.error("Invalid config dir")
|
||||
end
|
||||
if not Config.exist(dir) and not Config.create(dir) then
|
||||
return context.error("Can't create config dir: " .. dir)
|
||||
end
|
||||
if type(context.storage._configs) ~= "table" then
|
||||
context.storage._configs = {}
|
||||
end
|
||||
if type(context.storage._configs[dir]) ~= "table" then
|
||||
context.storage._configs[dir] = {
|
||||
enabled = false,
|
||||
selected = ""
|
||||
}
|
||||
else
|
||||
widget.switch:setOn(context.storage._configs[dir].enabled)
|
||||
end
|
||||
|
||||
local isRefreshing = false
|
||||
local refresh = function()
|
||||
isRefreshing = true
|
||||
local configs = Config.list(dir)
|
||||
local configIndex = 1
|
||||
widget.list:clear()
|
||||
for v,k in ipairs(configs) do
|
||||
widget.list:addOption(k)
|
||||
if k == context.storage._configs[dir].selected then
|
||||
configIndex = v
|
||||
end
|
||||
end
|
||||
local data = nil
|
||||
if #configs > 0 then
|
||||
widget.list:setCurrentIndex(configIndex)
|
||||
context.storage._configs[dir].selected = widget.list:getCurrentOption().text
|
||||
data = Config.load(dir, configs[configIndex])
|
||||
else
|
||||
context.storage._configs[dir].selected = nil
|
||||
end
|
||||
context.storage._configs[dir].enabled = widget.switch:isOn()
|
||||
isRefreshing = false
|
||||
callback(context.storage._configs[dir].selected, widget.switch:isOn(), data)
|
||||
end
|
||||
|
||||
widget.list.onOptionChange = function(widget)
|
||||
if not isRefreshing then
|
||||
context.storage._configs[dir].selected = widget:getCurrentOption().text
|
||||
refresh()
|
||||
end
|
||||
end
|
||||
|
||||
widget.switch.onClick = function()
|
||||
widget.switch:setOn(not widget.switch:isOn())
|
||||
refresh()
|
||||
end
|
||||
|
||||
widget.add.onClick = function()
|
||||
context.UI.SinglelineEditorWindow("config_name", {title="Enter config name"}, function(name)
|
||||
name = name:gsub("%s+", "_")
|
||||
if name:len() == 0 or name:len() >= 30 or name:find("/") or name:find("\\") then
|
||||
return context.error("Invalid config name")
|
||||
end
|
||||
local file = context.configDir .. "/" .. dir .. "/" .. name .. "." .. configExtension
|
||||
if g_resources.fileExists(file) then
|
||||
return context.error("Config " .. name .. " already exist")
|
||||
end
|
||||
if configExtension == "json" then
|
||||
g_resources.writeFileContents(file, json.encode({}))
|
||||
else
|
||||
g_resources.writeFileContents(file, "")
|
||||
end
|
||||
context.storage._configs[dir].selected = name
|
||||
widget.switch:setOn(false)
|
||||
refresh()
|
||||
end)
|
||||
end
|
||||
|
||||
widget.edit.onClick = function()
|
||||
local name = context.storage._configs[dir].selected
|
||||
if not name then return end
|
||||
context.UI.MultilineEditorWindow(Config.loadRaw(dir, name), {title="Config editor - " .. name .. " in " .. dir}, function(newValue)
|
||||
local data = Config.parse(newValue)
|
||||
Config.save(dir, name, data, configExtension)
|
||||
refresh()
|
||||
end)
|
||||
end
|
||||
|
||||
widget.remove.onClick = function()
|
||||
local name = context.storage._configs[dir].selected
|
||||
if not name then return end
|
||||
context.UI.ConfirmationWindow("Config removal", "Do you want to remove config " .. name .. " from " .. dir .. "?", function()
|
||||
Config.remove(dir, name)
|
||||
widget.switch:setOn(false)
|
||||
refresh()
|
||||
end)
|
||||
end
|
||||
|
||||
refresh()
|
||||
|
||||
return {
|
||||
isOn = function()
|
||||
return widget.switch:isOn()
|
||||
end,
|
||||
isOff = function()
|
||||
return not widget.switch:isOn()
|
||||
end,
|
||||
setOn = function(val)
|
||||
if val == false then
|
||||
if widget.switch:isOn() then
|
||||
widget.switch:onClick()
|
||||
end
|
||||
return
|
||||
end
|
||||
if not widget.switch:isOn() then
|
||||
widget.switch:onClick()
|
||||
end
|
||||
end,
|
||||
setOff = function(val)
|
||||
if val == false then
|
||||
if not widget.switch:isOn() then
|
||||
widget.switch:onClick()
|
||||
end
|
||||
return
|
||||
end
|
||||
if widget.switch:isOn() then
|
||||
widget.switch:onClick()
|
||||
end
|
||||
end,
|
||||
save = function(data)
|
||||
Config.save(dir, context.storage._configs[dir].selected, data, configExtension)
|
||||
end,
|
||||
refresh = refresh,
|
||||
reload = refresh,
|
||||
getActiveConfigName = function()
|
||||
return context.storage._configs[dir].selected
|
||||
end
|
||||
}
|
||||
--[[
|
||||
Config - create, load and save config file (.json / .cfg)
|
||||
Used by cavebot and other things
|
||||
]]--
|
||||
|
||||
local context = G.botContext
|
||||
context.Config = {}
|
||||
local Config = context.Config
|
||||
|
||||
Config.exist = function(dir)
|
||||
return g_resources.directoryExists(context.configDir .. "/" .. dir)
|
||||
end
|
||||
|
||||
Config.create = function(dir)
|
||||
g_resources.makeDir(context.configDir .. "/" .. dir)
|
||||
return Config.exist(dir)
|
||||
end
|
||||
|
||||
Config.list = function(dir)
|
||||
if not Config.exist(dir) then
|
||||
if not Config.create(dir) then
|
||||
return contex.error("Can't create config dir: " .. context.configDir .. "/" .. dir)
|
||||
end
|
||||
end
|
||||
local list = g_resources.listDirectoryFiles(context.configDir .. "/" .. dir)
|
||||
local correctList = {}
|
||||
for k,v in ipairs(list) do -- filter files
|
||||
local nv = v:gsub(".json", ""):gsub(".cfg", "")
|
||||
if nv ~= v then
|
||||
table.insert(correctList, nv)
|
||||
end
|
||||
end
|
||||
return correctList
|
||||
end
|
||||
|
||||
-- load config from string insteaf of file
|
||||
Config.parse = function(data)
|
||||
local status, result = pcall(function()
|
||||
if data:len() < 2 then return {} end
|
||||
return json.decode(data)
|
||||
end)
|
||||
if status and type(result) == 'table' then
|
||||
return result
|
||||
end
|
||||
local status, result = pcall(function()
|
||||
return table.decodeStringPairList(data)
|
||||
end)
|
||||
if status and type(result) == 'table' then
|
||||
return result
|
||||
end
|
||||
return context.error("Invalid config format")
|
||||
end
|
||||
|
||||
Config.load = function(dir, name)
|
||||
local file = context.configDir .. "/" .. dir .. "/" .. name .. ".json"
|
||||
if g_resources.fileExists(file) then -- load json
|
||||
local status, result = pcall(function()
|
||||
local data = g_resources.readFileContents(file)
|
||||
if data:len() < 2 then return {} end
|
||||
return json.decode(data)
|
||||
end)
|
||||
if not status then
|
||||
context.error("Invalid json config (" .. name .. "): " .. result)
|
||||
return {}
|
||||
end
|
||||
return result
|
||||
end
|
||||
file = context.configDir .. "/" .. dir .. "/" .. name .. ".cfg"
|
||||
if g_resources.fileExists(file) then -- load cfg
|
||||
local status, result = pcall(function()
|
||||
return table.decodeStringPairList(g_resources.readFileContents(file))
|
||||
end)
|
||||
if not status then
|
||||
context.error("Invalid cfg config (" .. name .. "): " .. result)
|
||||
return {}
|
||||
end
|
||||
return result
|
||||
end
|
||||
return context.error("Config " .. file .. " doesn't exist")
|
||||
end
|
||||
|
||||
Config.loadRaw = function(dir, name)
|
||||
local file = context.configDir .. "/" .. dir .. "/" .. name .. ".json"
|
||||
if g_resources.fileExists(file) then -- load json
|
||||
return g_resources.readFileContents(file)
|
||||
end
|
||||
file = context.configDir .. "/" .. dir .. "/" .. name .. ".cfg"
|
||||
if g_resources.fileExists(file) then -- load cfg
|
||||
return g_resources.readFileContents(file)
|
||||
end
|
||||
return context.error("Config " .. file .. " doesn't exist")
|
||||
end
|
||||
|
||||
Config.save = function(dir, name, value, forcedExtension)
|
||||
if not Config.exist(dir) then
|
||||
if not Config.create(dir) then
|
||||
return contex.error("Can't create config dir: " .. context.configDir .. "/" .. dir)
|
||||
end
|
||||
end
|
||||
if type(value) ~= 'table' then
|
||||
return context.error("Invalid config value type: " .. type(value) .. ", should be table")
|
||||
end
|
||||
local file = context.configDir .. "/" .. dir .. "/" .. name
|
||||
if (table.isStringPairList(value) and forcedExtension ~= "json") or forcedExtension == "cfg" then -- cfg
|
||||
g_resources.writeFileContents(file .. ".cfg", table.encodeStringPairList(value))
|
||||
else
|
||||
g_resources.writeFileContents(file .. ".json", json.encode(value, 2))
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
Config.remove = function(dir, name)
|
||||
local file = context.configDir .. "/" .. dir .. "/" .. name .. ".json"
|
||||
local ret = false
|
||||
if g_resources.fileExists(file) then
|
||||
g_resources.deleteFile(file)
|
||||
ret = true
|
||||
end
|
||||
file = context.configDir .. "/" .. dir .. "/" .. name .. ".cfg"
|
||||
if g_resources.fileExists(file) then
|
||||
g_resources.deleteFile(file)
|
||||
ret = true
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
-- setup is used for BotConfig widget
|
||||
-- not done yet
|
||||
Config.setup = function(dir, widget, configExtension, callback)
|
||||
if type(dir) ~= 'string' or dir:len() == 0 then
|
||||
return context.error("Invalid config dir")
|
||||
end
|
||||
if not Config.exist(dir) and not Config.create(dir) then
|
||||
return context.error("Can't create config dir: " .. dir)
|
||||
end
|
||||
if type(context.storage._configs) ~= "table" then
|
||||
context.storage._configs = {}
|
||||
end
|
||||
if type(context.storage._configs[dir]) ~= "table" then
|
||||
context.storage._configs[dir] = {
|
||||
enabled = false,
|
||||
selected = ""
|
||||
}
|
||||
else
|
||||
widget.switch:setOn(context.storage._configs[dir].enabled)
|
||||
end
|
||||
|
||||
local isRefreshing = false
|
||||
local refresh = function()
|
||||
isRefreshing = true
|
||||
local configs = Config.list(dir)
|
||||
local configIndex = 1
|
||||
widget.list:clear()
|
||||
for v,k in ipairs(configs) do
|
||||
widget.list:addOption(k)
|
||||
if k == context.storage._configs[dir].selected then
|
||||
configIndex = v
|
||||
end
|
||||
end
|
||||
local data = nil
|
||||
if #configs > 0 then
|
||||
widget.list:setCurrentIndex(configIndex)
|
||||
context.storage._configs[dir].selected = widget.list:getCurrentOption().text
|
||||
data = Config.load(dir, configs[configIndex])
|
||||
else
|
||||
context.storage._configs[dir].selected = nil
|
||||
end
|
||||
context.storage._configs[dir].enabled = widget.switch:isOn()
|
||||
isRefreshing = false
|
||||
callback(context.storage._configs[dir].selected, widget.switch:isOn(), data)
|
||||
end
|
||||
|
||||
widget.list.onOptionChange = function(widget)
|
||||
if not isRefreshing then
|
||||
context.storage._configs[dir].selected = widget:getCurrentOption().text
|
||||
refresh()
|
||||
end
|
||||
end
|
||||
|
||||
widget.switch.onClick = function()
|
||||
widget.switch:setOn(not widget.switch:isOn())
|
||||
refresh()
|
||||
end
|
||||
|
||||
widget.add.onClick = function()
|
||||
context.UI.SinglelineEditorWindow("config_name", {title="Enter config name"}, function(name)
|
||||
name = name:gsub("%s+", "_")
|
||||
if name:len() == 0 or name:len() >= 30 or name:find("/") or name:find("\\") then
|
||||
return context.error("Invalid config name")
|
||||
end
|
||||
local file = context.configDir .. "/" .. dir .. "/" .. name .. "." .. configExtension
|
||||
if g_resources.fileExists(file) then
|
||||
return context.error("Config " .. name .. " already exist")
|
||||
end
|
||||
if configExtension == "json" then
|
||||
g_resources.writeFileContents(file, json.encode({}))
|
||||
else
|
||||
g_resources.writeFileContents(file, "")
|
||||
end
|
||||
context.storage._configs[dir].selected = name
|
||||
widget.switch:setOn(false)
|
||||
refresh()
|
||||
end)
|
||||
end
|
||||
|
||||
widget.edit.onClick = function()
|
||||
local name = context.storage._configs[dir].selected
|
||||
if not name then return end
|
||||
context.UI.MultilineEditorWindow(Config.loadRaw(dir, name), {title="Config editor - " .. name .. " in " .. dir}, function(newValue)
|
||||
local data = Config.parse(newValue)
|
||||
Config.save(dir, name, data, configExtension)
|
||||
refresh()
|
||||
end)
|
||||
end
|
||||
|
||||
widget.remove.onClick = function()
|
||||
local name = context.storage._configs[dir].selected
|
||||
if not name then return end
|
||||
context.UI.ConfirmationWindow("Config removal", "Do you want to remove config " .. name .. " from " .. dir .. "?", function()
|
||||
Config.remove(dir, name)
|
||||
widget.switch:setOn(false)
|
||||
refresh()
|
||||
end)
|
||||
end
|
||||
|
||||
refresh()
|
||||
|
||||
return {
|
||||
isOn = function()
|
||||
return widget.switch:isOn()
|
||||
end,
|
||||
isOff = function()
|
||||
return not widget.switch:isOn()
|
||||
end,
|
||||
setOn = function(val)
|
||||
if val == false then
|
||||
if widget.switch:isOn() then
|
||||
widget.switch:onClick()
|
||||
end
|
||||
return
|
||||
end
|
||||
if not widget.switch:isOn() then
|
||||
widget.switch:onClick()
|
||||
end
|
||||
end,
|
||||
setOff = function(val)
|
||||
if val == false then
|
||||
if not widget.switch:isOn() then
|
||||
widget.switch:onClick()
|
||||
end
|
||||
return
|
||||
end
|
||||
if widget.switch:isOn() then
|
||||
widget.switch:onClick()
|
||||
end
|
||||
end,
|
||||
save = function(data)
|
||||
Config.save(dir, context.storage._configs[dir].selected, data, configExtension)
|
||||
end,
|
||||
refresh = refresh,
|
||||
reload = refresh,
|
||||
getActiveConfigName = function()
|
||||
return context.storage._configs[dir].selected
|
||||
end
|
||||
}
|
||||
end
|
@@ -1,25 +1,25 @@
|
||||
local context = G.botContext
|
||||
|
||||
context.North = 0
|
||||
context.East = 1
|
||||
context.South = 2
|
||||
context.West = 3
|
||||
context.NorthEast = 4
|
||||
context.SouthEast = 5
|
||||
context.SouthWest = 6
|
||||
context.NorthWest = 7
|
||||
|
||||
context.InventorySlotOther = 0
|
||||
context.InventorySlotHead = 1
|
||||
context.InventorySlotNeck = 2
|
||||
context.InventorySlotBack = 3
|
||||
context.InventorySlotBody = 4
|
||||
context.InventorySlotRight = 5
|
||||
context.InventorySlotLeft = 6
|
||||
context.InventorySlotLeg = 7
|
||||
context.InventorySlotFeet = 8
|
||||
context.InventorySlotFinger = 9
|
||||
context.InventorySlotAmmo = 10
|
||||
context.InventorySlotPurse = 11
|
||||
context.InventorySlotFirst = 1
|
||||
context.InventorySlotLast = 10
|
||||
local context = G.botContext
|
||||
|
||||
context.North = 0
|
||||
context.East = 1
|
||||
context.South = 2
|
||||
context.West = 3
|
||||
context.NorthEast = 4
|
||||
context.SouthEast = 5
|
||||
context.SouthWest = 6
|
||||
context.NorthWest = 7
|
||||
|
||||
context.InventorySlotOther = 0
|
||||
context.InventorySlotHead = 1
|
||||
context.InventorySlotNeck = 2
|
||||
context.InventorySlotBack = 3
|
||||
context.InventorySlotBody = 4
|
||||
context.InventorySlotRight = 5
|
||||
context.InventorySlotLeft = 6
|
||||
context.InventorySlotLeg = 7
|
||||
context.InventorySlotFeet = 8
|
||||
context.InventorySlotFinger = 9
|
||||
context.InventorySlotAmmo = 10
|
||||
context.InventorySlotPurse = 11
|
||||
context.InventorySlotFirst = 1
|
||||
context.InventorySlotLast = 10
|
||||
|
@@ -1,176 +1,176 @@
|
||||
local context = G.botContext
|
||||
|
||||
local iconsWithoutPosition = 0
|
||||
|
||||
context.addIcon = function(id, options, callback)
|
||||
--[[
|
||||
Available options:
|
||||
item: {id=2160, count=100}
|
||||
outfit: outfit table ({})
|
||||
text: string
|
||||
x: float (0.0 - 1.0)
|
||||
y: float (0.0 - 1.0)
|
||||
hotkey: string
|
||||
switchable: true / false [default: true]
|
||||
movable: true / false [default: true]
|
||||
phantom: true / false [defaule: false]
|
||||
]]--
|
||||
local panel = modules.game_interface.gameMapPanel
|
||||
if type(id) ~= "string" or id:len() < 1 then
|
||||
return context.error("Invalid id for addIcon")
|
||||
end
|
||||
if options.switchable == false and type(callback) ~= 'function' then
|
||||
return context.error("Invalid callback for addIcon")
|
||||
end
|
||||
if type(context.storage._icons) ~= "table" then
|
||||
context.storage._icons = {}
|
||||
end
|
||||
if type(context.storage._icons[id]) ~= "table" then
|
||||
context.storage._icons[id] = {}
|
||||
end
|
||||
local config = context.storage._icons[id]
|
||||
local widget = g_ui.createWidget("BotIcon", panel)
|
||||
widget.botWidget = true
|
||||
widget.botIcon = true
|
||||
|
||||
if type(config.x) ~= 'number' and type(config.y) ~= 'number' then
|
||||
if type(options.x) == 'number' and type(options.y) == 'number' then
|
||||
config.x = math.min(1.0, math.max(0.0, options.x))
|
||||
config.y = math.min(1.0, math.max(0.0, options.y))
|
||||
else
|
||||
config.x = 0.01 + math.floor(iconsWithoutPosition / 5) / 10
|
||||
config.y = 0.05 + (iconsWithoutPosition % 5) / 5
|
||||
iconsWithoutPosition = iconsWithoutPosition + 1
|
||||
end
|
||||
end
|
||||
|
||||
if options.item then
|
||||
if type(options.item) == 'number' then
|
||||
widget.item:setItemId(options.item)
|
||||
else
|
||||
widget.item:setItemId(options.item.id)
|
||||
widget.item:setItemCount(options.item.count or 1)
|
||||
widget.item:setShowCount(false)
|
||||
end
|
||||
end
|
||||
|
||||
if options.outfit then
|
||||
widget.creature:setOutfit(options.outfit)
|
||||
end
|
||||
|
||||
if options.switchable == false then
|
||||
widget.status:hide()
|
||||
widget.status:setOn(true)
|
||||
else
|
||||
if config.enabled ~= true then
|
||||
config.enabled = false
|
||||
end
|
||||
widget.status:setOn(config.enabled)
|
||||
end
|
||||
|
||||
if options.text then
|
||||
if options.switchable ~= false then
|
||||
widget.status:hide()
|
||||
if widget.status:isOn() then
|
||||
widget.text:setColor('green')
|
||||
else
|
||||
widget.text:setColor('red')
|
||||
end
|
||||
end
|
||||
widget.text:setText(options.text)
|
||||
end
|
||||
|
||||
widget.setOn = function(val)
|
||||
widget.status:setOn(val)
|
||||
if widget.status:isOn() then
|
||||
widget.text:setColor('green')
|
||||
else
|
||||
widget.text:setColor('red')
|
||||
end
|
||||
config.enabled = widget.status:isOn()
|
||||
end
|
||||
|
||||
widget.onClick = function(widget)
|
||||
if options.switchable ~= false then
|
||||
widget.setOn(not widget.status:isOn())
|
||||
if type(callback) == 'table' then
|
||||
callback.setOn(config.enabled)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
callback(widget, widget.status:isOn())
|
||||
end
|
||||
|
||||
if options.hotkey then
|
||||
widget.hotkey:setText(options.hotkey)
|
||||
context.hotkey(options.hotkey, "", function()
|
||||
widget:onClick()
|
||||
end, nil, options.switchable ~= false)
|
||||
else
|
||||
widget.hotkey:hide()
|
||||
end
|
||||
|
||||
if options.movable ~= false then
|
||||
widget.onDragEnter = function(widget, mousePos)
|
||||
if not g_keyboard.isCtrlPressed() then
|
||||
return false
|
||||
end
|
||||
widget:breakAnchors()
|
||||
widget.movingReference = { x = mousePos.x - widget:getX(), y = mousePos.y - widget:getY() }
|
||||
return true
|
||||
end
|
||||
|
||||
widget.onDragMove = function(widget, mousePos, moved)
|
||||
local parentRect = widget:getParent():getRect()
|
||||
local x = math.min(math.max(parentRect.x, mousePos.x - widget.movingReference.x), parentRect.x + parentRect.width - widget:getWidth())
|
||||
local y = math.min(math.max(parentRect.y - widget:getParent():getMarginTop(), mousePos.y - widget.movingReference.y), parentRect.y + parentRect.height - widget:getHeight())
|
||||
widget:move(x, y)
|
||||
return true
|
||||
end
|
||||
|
||||
widget.onDragLeave = function(widget, pos)
|
||||
local parent = widget:getParent()
|
||||
local parentRect = parent:getRect()
|
||||
local x = widget:getX() - parentRect.x
|
||||
local y = widget:getY() - parentRect.y
|
||||
local width = parentRect.width - widget:getWidth()
|
||||
local height = parentRect.height - widget:getHeight()
|
||||
|
||||
config.x = math.min(1, math.max(0, x / width))
|
||||
config.y = math.min(1, math.max(0, y / height))
|
||||
|
||||
widget:addAnchor(AnchorHorizontalCenter, 'parent', AnchorHorizontalCenter)
|
||||
widget:addAnchor(AnchorVerticalCenter, 'parent', AnchorVerticalCenter)
|
||||
widget:setMarginTop(math.max(height * (-0.5) - parent:getMarginTop(), height * (-0.5 + config.y)))
|
||||
widget:setMarginLeft(width * (-0.5 + config.x))
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
widget.onGeometryChange = function(widget)
|
||||
if widget:isDragging() then return end
|
||||
local parent = widget:getParent()
|
||||
local parentRect = parent:getRect()
|
||||
local width = parentRect.width - widget:getWidth()
|
||||
local height = parentRect.height - widget:getHeight()
|
||||
widget:setMarginTop(math.max(height * (-0.5) - parent:getMarginTop(), height * (-0.5 + config.y)))
|
||||
widget:setMarginLeft(width * (-0.5 + config.x))
|
||||
end
|
||||
|
||||
if options.phantom ~= true then
|
||||
widget.onMouseRelease = function()
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
if options.switchable ~= false then
|
||||
if type(callback) == 'table' then
|
||||
callback.setOn(config.enabled)
|
||||
callback.icon = widget
|
||||
else
|
||||
callback(widget, widget.status:isOn())
|
||||
end
|
||||
end
|
||||
return widget
|
||||
local context = G.botContext
|
||||
|
||||
local iconsWithoutPosition = 0
|
||||
|
||||
context.addIcon = function(id, options, callback)
|
||||
--[[
|
||||
Available options:
|
||||
item: {id=2160, count=100}
|
||||
outfit: outfit table ({})
|
||||
text: string
|
||||
x: float (0.0 - 1.0)
|
||||
y: float (0.0 - 1.0)
|
||||
hotkey: string
|
||||
switchable: true / false [default: true]
|
||||
movable: true / false [default: true]
|
||||
phantom: true / false [defaule: false]
|
||||
]]--
|
||||
local panel = modules.game_interface.gameMapPanel
|
||||
if type(id) ~= "string" or id:len() < 1 then
|
||||
return context.error("Invalid id for addIcon")
|
||||
end
|
||||
if options.switchable == false and type(callback) ~= 'function' then
|
||||
return context.error("Invalid callback for addIcon")
|
||||
end
|
||||
if type(context.storage._icons) ~= "table" then
|
||||
context.storage._icons = {}
|
||||
end
|
||||
if type(context.storage._icons[id]) ~= "table" then
|
||||
context.storage._icons[id] = {}
|
||||
end
|
||||
local config = context.storage._icons[id]
|
||||
local widget = g_ui.createWidget("BotIcon", panel)
|
||||
widget.botWidget = true
|
||||
widget.botIcon = true
|
||||
|
||||
if type(config.x) ~= 'number' and type(config.y) ~= 'number' then
|
||||
if type(options.x) == 'number' and type(options.y) == 'number' then
|
||||
config.x = math.min(1.0, math.max(0.0, options.x))
|
||||
config.y = math.min(1.0, math.max(0.0, options.y))
|
||||
else
|
||||
config.x = 0.01 + math.floor(iconsWithoutPosition / 5) / 10
|
||||
config.y = 0.05 + (iconsWithoutPosition % 5) / 5
|
||||
iconsWithoutPosition = iconsWithoutPosition + 1
|
||||
end
|
||||
end
|
||||
|
||||
if options.item then
|
||||
if type(options.item) == 'number' then
|
||||
widget.item:setItemId(options.item)
|
||||
else
|
||||
widget.item:setItemId(options.item.id)
|
||||
widget.item:setItemCount(options.item.count or 1)
|
||||
widget.item:setShowCount(false)
|
||||
end
|
||||
end
|
||||
|
||||
if options.outfit then
|
||||
widget.creature:setOutfit(options.outfit)
|
||||
end
|
||||
|
||||
if options.switchable == false then
|
||||
widget.status:hide()
|
||||
widget.status:setOn(true)
|
||||
else
|
||||
if config.enabled ~= true then
|
||||
config.enabled = false
|
||||
end
|
||||
widget.status:setOn(config.enabled)
|
||||
end
|
||||
|
||||
if options.text then
|
||||
if options.switchable ~= false then
|
||||
widget.status:hide()
|
||||
if widget.status:isOn() then
|
||||
widget.text:setColor('green')
|
||||
else
|
||||
widget.text:setColor('red')
|
||||
end
|
||||
end
|
||||
widget.text:setText(options.text)
|
||||
end
|
||||
|
||||
widget.setOn = function(val)
|
||||
widget.status:setOn(val)
|
||||
if widget.status:isOn() then
|
||||
widget.text:setColor('green')
|
||||
else
|
||||
widget.text:setColor('red')
|
||||
end
|
||||
config.enabled = widget.status:isOn()
|
||||
end
|
||||
|
||||
widget.onClick = function(widget)
|
||||
if options.switchable ~= false then
|
||||
widget.setOn(not widget.status:isOn())
|
||||
if type(callback) == 'table' then
|
||||
callback.setOn(config.enabled)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
callback(widget, widget.status:isOn())
|
||||
end
|
||||
|
||||
if options.hotkey then
|
||||
widget.hotkey:setText(options.hotkey)
|
||||
context.hotkey(options.hotkey, "", function()
|
||||
widget:onClick()
|
||||
end, nil, options.switchable ~= false)
|
||||
else
|
||||
widget.hotkey:hide()
|
||||
end
|
||||
|
||||
if options.movable ~= false then
|
||||
widget.onDragEnter = function(widget, mousePos)
|
||||
if not g_keyboard.isCtrlPressed() then
|
||||
return false
|
||||
end
|
||||
widget:breakAnchors()
|
||||
widget.movingReference = { x = mousePos.x - widget:getX(), y = mousePos.y - widget:getY() }
|
||||
return true
|
||||
end
|
||||
|
||||
widget.onDragMove = function(widget, mousePos, moved)
|
||||
local parentRect = widget:getParent():getRect()
|
||||
local x = math.min(math.max(parentRect.x, mousePos.x - widget.movingReference.x), parentRect.x + parentRect.width - widget:getWidth())
|
||||
local y = math.min(math.max(parentRect.y - widget:getParent():getMarginTop(), mousePos.y - widget.movingReference.y), parentRect.y + parentRect.height - widget:getHeight())
|
||||
widget:move(x, y)
|
||||
return true
|
||||
end
|
||||
|
||||
widget.onDragLeave = function(widget, pos)
|
||||
local parent = widget:getParent()
|
||||
local parentRect = parent:getRect()
|
||||
local x = widget:getX() - parentRect.x
|
||||
local y = widget:getY() - parentRect.y
|
||||
local width = parentRect.width - widget:getWidth()
|
||||
local height = parentRect.height - widget:getHeight()
|
||||
|
||||
config.x = math.min(1, math.max(0, x / width))
|
||||
config.y = math.min(1, math.max(0, y / height))
|
||||
|
||||
widget:addAnchor(AnchorHorizontalCenter, 'parent', AnchorHorizontalCenter)
|
||||
widget:addAnchor(AnchorVerticalCenter, 'parent', AnchorVerticalCenter)
|
||||
widget:setMarginTop(math.max(height * (-0.5) - parent:getMarginTop(), height * (-0.5 + config.y)))
|
||||
widget:setMarginLeft(width * (-0.5 + config.x))
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
widget.onGeometryChange = function(widget)
|
||||
if widget:isDragging() then return end
|
||||
local parent = widget:getParent()
|
||||
local parentRect = parent:getRect()
|
||||
local width = parentRect.width - widget:getWidth()
|
||||
local height = parentRect.height - widget:getHeight()
|
||||
widget:setMarginTop(math.max(height * (-0.5) - parent:getMarginTop(), height * (-0.5 + config.y)))
|
||||
widget:setMarginLeft(width * (-0.5 + config.x))
|
||||
end
|
||||
|
||||
if options.phantom ~= true then
|
||||
widget.onMouseRelease = function()
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
if options.switchable ~= false then
|
||||
if type(callback) == 'table' then
|
||||
callback.setOn(config.enabled)
|
||||
callback.icon = widget
|
||||
else
|
||||
callback(widget, widget.status:isOn())
|
||||
end
|
||||
end
|
||||
return widget
|
||||
end
|
@@ -1,211 +1,211 @@
|
||||
local context = G.botContext
|
||||
|
||||
-- MAIN BOT FUNCTION
|
||||
-- macro(timeout, callback)
|
||||
-- macro(timeout, name, callback)
|
||||
-- macro(timeout, name, callback, parent)
|
||||
-- macro(timeout, name, hotkey, callback)
|
||||
-- macro(timeout, name, hotkey, callback, parent)
|
||||
context.macro = function(timeout, name, hotkey, callback, parent)
|
||||
if type(timeout) ~= 'number' or timeout < 1 then
|
||||
error("Invalid timeout for macro: " .. tostring(timeout))
|
||||
end
|
||||
if type(name) == 'function' then
|
||||
callback = name
|
||||
name = ""
|
||||
hotkey = ""
|
||||
elseif type(hotkey) == 'function' then
|
||||
parent = callback
|
||||
callback = hotkey
|
||||
hotkey = ""
|
||||
elseif type(callback) ~= 'function' then
|
||||
error("Invalid callback for macro: " .. tostring(callback))
|
||||
end
|
||||
if hotkey == nil then
|
||||
hotkey = ""
|
||||
end
|
||||
if type(name) ~= 'string' or type(hotkey) ~= 'string' then
|
||||
error("Invalid name or hotkey for macro")
|
||||
end
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
if hotkey:len() > 0 then
|
||||
hotkey = retranslateKeyComboDesc(hotkey)
|
||||
end
|
||||
|
||||
-- min timeout is 50, to avoid lags
|
||||
if timeout < 50 then
|
||||
timeout = 50
|
||||
end
|
||||
|
||||
table.insert(context._macros, {
|
||||
enabled = false,
|
||||
name = name,
|
||||
timeout = timeout,
|
||||
lastExecution = context.now + math.random(0, 100),
|
||||
hotkey = hotkey,
|
||||
})
|
||||
local macro = context._macros[#context._macros]
|
||||
|
||||
macro.isOn = function()
|
||||
return macro.enabled
|
||||
end
|
||||
macro.isOff = function()
|
||||
return not macro.enabled
|
||||
end
|
||||
macro.toggle = function(widget)
|
||||
if macro.isOn() then
|
||||
macro.setOff()
|
||||
else
|
||||
macro.setOn()
|
||||
end
|
||||
end
|
||||
macro.setOn = function(val)
|
||||
if val == false then
|
||||
return macro.setOff()
|
||||
end
|
||||
macro.enabled = true
|
||||
context.storage._macros[name] = true
|
||||
if macro.switch then
|
||||
macro.switch:setOn(true)
|
||||
end
|
||||
if macro.icon then
|
||||
macro.icon.setOn(true)
|
||||
end
|
||||
end
|
||||
macro.setOff = function(val)
|
||||
if val == false then
|
||||
return macro.setOn()
|
||||
end
|
||||
macro.enabled = false
|
||||
context.storage._macros[name] = false
|
||||
if macro.switch then
|
||||
macro.switch:setOn(false)
|
||||
end
|
||||
if macro.icon then
|
||||
macro.icon.setOn(false)
|
||||
end
|
||||
end
|
||||
|
||||
if name:len() > 0 then
|
||||
-- creature switch
|
||||
local text = name
|
||||
if hotkey:len() > 0 then
|
||||
text = name .. " [" .. hotkey .. "]"
|
||||
end
|
||||
macro.switch = context.addSwitch("macro_" .. (#context._macros + 1), text, macro.toggle, parent)
|
||||
|
||||
-- load state
|
||||
if context.storage._macros[name] == true then
|
||||
macro.setOn()
|
||||
end
|
||||
else
|
||||
macro.enabled = true -- unnamed macros are enabled by default
|
||||
end
|
||||
|
||||
local desc = "lua"
|
||||
local info = debug.getinfo(2, "Sl")
|
||||
if info then
|
||||
desc = info.short_src .. ":" .. info.currentline
|
||||
end
|
||||
|
||||
macro.callback = function(macro)
|
||||
if not macro.delay or macro.delay < context.now then
|
||||
context._currentExecution = macro
|
||||
local start = g_clock.realMillis()
|
||||
callback(macro)
|
||||
local executionTime = g_clock.realMillis() - start
|
||||
if executionTime > 100 then
|
||||
context.warning("Slow macro (" .. executionTime .. "ms): " .. macro.name .. " - " .. desc)
|
||||
end
|
||||
context._currentExecution = nil
|
||||
return true
|
||||
end
|
||||
end
|
||||
return macro
|
||||
end
|
||||
|
||||
-- hotkey(keys, callback)
|
||||
-- hotkey(keys, name, callback)
|
||||
-- hotkey(keys, name, callback, parent)
|
||||
context.hotkey = function(keys, name, callback, parent, single)
|
||||
if type(name) == 'function' then
|
||||
callback = name
|
||||
name = ""
|
||||
end
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
keys = retranslateKeyComboDesc(keys)
|
||||
if not keys or #keys == 0 then
|
||||
return context.error("Invalid hotkey keys " .. tostring(name))
|
||||
end
|
||||
if context._hotkeys[keys] then
|
||||
return context.error("Duplicated hotkey: " .. keys)
|
||||
end
|
||||
|
||||
local switch = nil
|
||||
if name:len() > 0 then
|
||||
switch = context._addHotkeySwitch(name, keys, parent)
|
||||
end
|
||||
|
||||
context._hotkeys[keys] = {
|
||||
name = name,
|
||||
lastExecution = context.now,
|
||||
switch = switch,
|
||||
single = single
|
||||
}
|
||||
|
||||
local desc = "lua"
|
||||
local info = debug.getinfo(2, "Sl")
|
||||
if info then
|
||||
desc = info.short_src .. ":" .. info.currentline
|
||||
end
|
||||
|
||||
local hotkeyData = context._hotkeys[keys]
|
||||
hotkeyData.callback = function()
|
||||
if not hotkeyData.delay or hotkeyData.delay < context.now then
|
||||
context._currentExecution = hotkeyData
|
||||
local start = g_clock.realMillis()
|
||||
callback()
|
||||
local executionTime = g_clock.realMillis() - start
|
||||
if executionTime > 100 then
|
||||
context.warning("Slow hotkey (" .. executionTime .. "ms): " .. hotkeyData.name .. " - " .. desc)
|
||||
end
|
||||
context._currentExecution = nil
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return hotkeyData
|
||||
end
|
||||
|
||||
-- singlehotkey(keys, callback)
|
||||
-- singlehotkey(keys, name, callback)
|
||||
-- singlehotkey(keys, name, callback, parent)
|
||||
context.singlehotkey = function(keys, name, callback, parent)
|
||||
if type(name) == 'function' then
|
||||
callback = name
|
||||
name = ""
|
||||
end
|
||||
return context.hotkey(keys, name, callback, parent, true)
|
||||
end
|
||||
|
||||
-- schedule(timeout, callback)
|
||||
context.schedule = function(timeout, callback)
|
||||
local extecute_time = g_clock.millis() + timeout
|
||||
table.insert(context._scheduler, {
|
||||
execution = extecute_time,
|
||||
callback = callback
|
||||
})
|
||||
table.sort(context._scheduler, function(a, b) return a.execution < b.execution end)
|
||||
end
|
||||
|
||||
-- delay(duration) -- block execution of current macro/hotkey/callback for x milliseconds
|
||||
context.delay = function(duration)
|
||||
if not context._currentExecution then
|
||||
return context.error("Invalid usage of delay function, it should be used inside callbacks")
|
||||
end
|
||||
context._currentExecution.delay = context.now + duration
|
||||
local context = G.botContext
|
||||
|
||||
-- MAIN BOT FUNCTION
|
||||
-- macro(timeout, callback)
|
||||
-- macro(timeout, name, callback)
|
||||
-- macro(timeout, name, callback, parent)
|
||||
-- macro(timeout, name, hotkey, callback)
|
||||
-- macro(timeout, name, hotkey, callback, parent)
|
||||
context.macro = function(timeout, name, hotkey, callback, parent)
|
||||
if type(timeout) ~= 'number' or timeout < 1 then
|
||||
error("Invalid timeout for macro: " .. tostring(timeout))
|
||||
end
|
||||
if type(name) == 'function' then
|
||||
callback = name
|
||||
name = ""
|
||||
hotkey = ""
|
||||
elseif type(hotkey) == 'function' then
|
||||
parent = callback
|
||||
callback = hotkey
|
||||
hotkey = ""
|
||||
elseif type(callback) ~= 'function' then
|
||||
error("Invalid callback for macro: " .. tostring(callback))
|
||||
end
|
||||
if hotkey == nil then
|
||||
hotkey = ""
|
||||
end
|
||||
if type(name) ~= 'string' or type(hotkey) ~= 'string' then
|
||||
error("Invalid name or hotkey for macro")
|
||||
end
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
if hotkey:len() > 0 then
|
||||
hotkey = retranslateKeyComboDesc(hotkey)
|
||||
end
|
||||
|
||||
-- min timeout is 50, to avoid lags
|
||||
if timeout < 50 then
|
||||
timeout = 50
|
||||
end
|
||||
|
||||
table.insert(context._macros, {
|
||||
enabled = false,
|
||||
name = name,
|
||||
timeout = timeout,
|
||||
lastExecution = context.now + math.random(0, 100),
|
||||
hotkey = hotkey,
|
||||
})
|
||||
local macro = context._macros[#context._macros]
|
||||
|
||||
macro.isOn = function()
|
||||
return macro.enabled
|
||||
end
|
||||
macro.isOff = function()
|
||||
return not macro.enabled
|
||||
end
|
||||
macro.toggle = function(widget)
|
||||
if macro.isOn() then
|
||||
macro.setOff()
|
||||
else
|
||||
macro.setOn()
|
||||
end
|
||||
end
|
||||
macro.setOn = function(val)
|
||||
if val == false then
|
||||
return macro.setOff()
|
||||
end
|
||||
macro.enabled = true
|
||||
context.storage._macros[name] = true
|
||||
if macro.switch then
|
||||
macro.switch:setOn(true)
|
||||
end
|
||||
if macro.icon then
|
||||
macro.icon.setOn(true)
|
||||
end
|
||||
end
|
||||
macro.setOff = function(val)
|
||||
if val == false then
|
||||
return macro.setOn()
|
||||
end
|
||||
macro.enabled = false
|
||||
context.storage._macros[name] = false
|
||||
if macro.switch then
|
||||
macro.switch:setOn(false)
|
||||
end
|
||||
if macro.icon then
|
||||
macro.icon.setOn(false)
|
||||
end
|
||||
end
|
||||
|
||||
if name:len() > 0 then
|
||||
-- creature switch
|
||||
local text = name
|
||||
if hotkey:len() > 0 then
|
||||
text = name .. " [" .. hotkey .. "]"
|
||||
end
|
||||
macro.switch = context.addSwitch("macro_" .. (#context._macros + 1), text, macro.toggle, parent)
|
||||
|
||||
-- load state
|
||||
if context.storage._macros[name] == true then
|
||||
macro.setOn()
|
||||
end
|
||||
else
|
||||
macro.enabled = true -- unnamed macros are enabled by default
|
||||
end
|
||||
|
||||
local desc = "lua"
|
||||
local info = debug.getinfo(2, "Sl")
|
||||
if info then
|
||||
desc = info.short_src .. ":" .. info.currentline
|
||||
end
|
||||
|
||||
macro.callback = function(macro)
|
||||
if not macro.delay or macro.delay < context.now then
|
||||
context._currentExecution = macro
|
||||
local start = g_clock.realMillis()
|
||||
callback(macro)
|
||||
local executionTime = g_clock.realMillis() - start
|
||||
if executionTime > 100 then
|
||||
context.warning("Slow macro (" .. executionTime .. "ms): " .. macro.name .. " - " .. desc)
|
||||
end
|
||||
context._currentExecution = nil
|
||||
return true
|
||||
end
|
||||
end
|
||||
return macro
|
||||
end
|
||||
|
||||
-- hotkey(keys, callback)
|
||||
-- hotkey(keys, name, callback)
|
||||
-- hotkey(keys, name, callback, parent)
|
||||
context.hotkey = function(keys, name, callback, parent, single)
|
||||
if type(name) == 'function' then
|
||||
callback = name
|
||||
name = ""
|
||||
end
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
keys = retranslateKeyComboDesc(keys)
|
||||
if not keys or #keys == 0 then
|
||||
return context.error("Invalid hotkey keys " .. tostring(name))
|
||||
end
|
||||
if context._hotkeys[keys] then
|
||||
return context.error("Duplicated hotkey: " .. keys)
|
||||
end
|
||||
|
||||
local switch = nil
|
||||
if name:len() > 0 then
|
||||
switch = context._addHotkeySwitch(name, keys, parent)
|
||||
end
|
||||
|
||||
context._hotkeys[keys] = {
|
||||
name = name,
|
||||
lastExecution = context.now,
|
||||
switch = switch,
|
||||
single = single
|
||||
}
|
||||
|
||||
local desc = "lua"
|
||||
local info = debug.getinfo(2, "Sl")
|
||||
if info then
|
||||
desc = info.short_src .. ":" .. info.currentline
|
||||
end
|
||||
|
||||
local hotkeyData = context._hotkeys[keys]
|
||||
hotkeyData.callback = function()
|
||||
if not hotkeyData.delay or hotkeyData.delay < context.now then
|
||||
context._currentExecution = hotkeyData
|
||||
local start = g_clock.realMillis()
|
||||
callback()
|
||||
local executionTime = g_clock.realMillis() - start
|
||||
if executionTime > 100 then
|
||||
context.warning("Slow hotkey (" .. executionTime .. "ms): " .. hotkeyData.name .. " - " .. desc)
|
||||
end
|
||||
context._currentExecution = nil
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return hotkeyData
|
||||
end
|
||||
|
||||
-- singlehotkey(keys, callback)
|
||||
-- singlehotkey(keys, name, callback)
|
||||
-- singlehotkey(keys, name, callback, parent)
|
||||
context.singlehotkey = function(keys, name, callback, parent)
|
||||
if type(name) == 'function' then
|
||||
callback = name
|
||||
name = ""
|
||||
end
|
||||
return context.hotkey(keys, name, callback, parent, true)
|
||||
end
|
||||
|
||||
-- schedule(timeout, callback)
|
||||
context.schedule = function(timeout, callback)
|
||||
local extecute_time = g_clock.millis() + timeout
|
||||
table.insert(context._scheduler, {
|
||||
execution = extecute_time,
|
||||
callback = callback
|
||||
})
|
||||
table.sort(context._scheduler, function(a, b) return a.execution < b.execution end)
|
||||
end
|
||||
|
||||
-- delay(duration) -- block execution of current macro/hotkey/callback for x milliseconds
|
||||
context.delay = function(duration)
|
||||
if not context._currentExecution then
|
||||
return context.error("Invalid usage of delay function, it should be used inside callbacks")
|
||||
end
|
||||
context._currentExecution.delay = context.now + duration
|
||||
end
|
@@ -1,256 +1,256 @@
|
||||
local context = G.botContext
|
||||
|
||||
context.getMapView = function() return modules.game_interface.getMapPanel() end
|
||||
context.getMapPanel = context.getMapView
|
||||
context.zoomIn = function() modules.game_interface.getMapPanel():zoomIn() end
|
||||
context.zoomOut = function() modules.game_interface.getMapPanel():zoomOut() end
|
||||
|
||||
context.getSpectators = function(param1, param2)
|
||||
--[[
|
||||
if param1 is table (position) then it's used for central position, then param2 is used as param1
|
||||
if param1 is creature, then creature position and direction of creature is used, then param2 is used as param1
|
||||
if param1 is true/false then it's used for multifloor, example: getSpectators(true)
|
||||
if param1 is string then it's used for getSpectatorsByPattern
|
||||
]]--
|
||||
local pos = context.player:getPosition()
|
||||
local direction = context.player:getDirection()
|
||||
if type(param1) == 'table' then
|
||||
pos = param1
|
||||
direction = 8 -- invalid direction
|
||||
param1 = param2
|
||||
end
|
||||
if type(param1) == 'userdata' then
|
||||
pos = param1:getPosition()
|
||||
direction = param1:getDirection()
|
||||
param1 = param2
|
||||
end
|
||||
|
||||
if type(param1) == 'string' then
|
||||
return g_map.getSpectatorsByPattern(pos, param1, direction)
|
||||
end
|
||||
|
||||
local multifloor = false
|
||||
if type(param1) == 'boolean' and param1 == true then
|
||||
multifloor = true
|
||||
end
|
||||
return g_map.getSpectators(pos, multifloor)
|
||||
end
|
||||
|
||||
context.getCreatureById = function(id, multifloor)
|
||||
if type(id) ~= 'number' then return nil end
|
||||
if multifloor ~= true then
|
||||
multifloor = false
|
||||
end
|
||||
for i, spec in ipairs(g_map.getSpectators(context.player:getPosition(), multifloor)) do
|
||||
if spec:getId() == id then
|
||||
return spec
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
context.getCreatureByName = function(name, multifloor)
|
||||
if not name then return nil end
|
||||
name = name:lower()
|
||||
if multifloor ~= true then
|
||||
multifloor = false
|
||||
end
|
||||
for i, spec in ipairs(g_map.getSpectators(context.player:getPosition(), multifloor)) do
|
||||
if spec:getName():lower() == name then
|
||||
return spec
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
context.getPlayerByName = function(name, multifloor)
|
||||
if not name then return nil end
|
||||
name = name:lower()
|
||||
if multifloor ~= true then
|
||||
multifloor = false
|
||||
end
|
||||
for i, spec in ipairs(g_map.getSpectators(context.player:getPosition(), multifloor)) do
|
||||
if spec:isPlayer() and spec:getName():lower() == name then
|
||||
return spec
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
context.findAllPaths = function(start, maxDist, params)
|
||||
--[[
|
||||
Available params:
|
||||
ignoreLastCreature
|
||||
ignoreCreatures
|
||||
ignoreNonPathable
|
||||
ignoreNonWalkable
|
||||
ignoreStairs
|
||||
ignoreCost
|
||||
allowUnseen
|
||||
allowOnlyVisibleTiles
|
||||
]]--
|
||||
if type(params) ~= 'table' then
|
||||
params = {}
|
||||
end
|
||||
for key, value in pairs(params) do
|
||||
if value == nil or value == false then
|
||||
params[key] = 0
|
||||
elseif value == true then
|
||||
params[key] = 1
|
||||
end
|
||||
end
|
||||
return g_map.findEveryPath(start, maxDist, params)
|
||||
end
|
||||
context.findEveryPath = context.findAllPaths
|
||||
|
||||
context.translateAllPathsToPath = function(paths, destPos)
|
||||
local predirections = {}
|
||||
local directions = {}
|
||||
local destPosStr = destPos
|
||||
if type(destPos) ~= 'string' then
|
||||
destPosStr = destPos.x .. "," .. destPos.y .. "," .. destPos.z
|
||||
end
|
||||
|
||||
while destPosStr:len() > 0 do
|
||||
local node = paths[destPosStr]
|
||||
if not node then
|
||||
break
|
||||
end
|
||||
if node[3] < 0 then
|
||||
break
|
||||
end
|
||||
table.insert(predirections, node[3])
|
||||
destPosStr = node[4]
|
||||
end
|
||||
-- reverse
|
||||
for i=#predirections,1,-1 do
|
||||
table.insert(directions, predirections[i])
|
||||
end
|
||||
return directions
|
||||
end
|
||||
context.translateEveryPathToPath = context.translateAllPathsToPath
|
||||
|
||||
|
||||
context.findPath = function(startPos, destPos, maxDist, params)
|
||||
--[[
|
||||
Available params:
|
||||
ignoreLastCreature
|
||||
ignoreCreatures
|
||||
ignoreNonPathable
|
||||
ignoreNonWalkable
|
||||
ignoreStairs
|
||||
ignoreCost
|
||||
allowUnseen
|
||||
allowOnlyVisibleTiles
|
||||
precision
|
||||
marginMin
|
||||
marginMax
|
||||
]]--
|
||||
if not destPos or startPos.z ~= destPos.z then
|
||||
return
|
||||
end
|
||||
if type(maxDist) ~= 'number' then
|
||||
maxDist = 100
|
||||
end
|
||||
if type(params) ~= 'table' then
|
||||
params = {}
|
||||
end
|
||||
local destPosStr = destPos.x .. "," .. destPos.y .. "," .. destPos.z
|
||||
params["destination"] = destPosStr
|
||||
local paths = context.findAllPaths(startPos, maxDist, params)
|
||||
local marginMin = params.marginMin or params.minMargin
|
||||
local marginMax = params.marginMax or params.maxMargin
|
||||
if type(marginMin) == 'number' and type(marginMax) == 'number' then
|
||||
local bestCandidate = nil
|
||||
local bestCandidatePos = nil
|
||||
for x = -marginMax, marginMax do
|
||||
for y = -marginMax, marginMax do
|
||||
if math.abs(x) >= marginMin or math.abs(y) >= marginMin then
|
||||
local dest = (destPos.x + x) .. "," .. (destPos.y + y) .. "," .. destPos.z
|
||||
local node = paths[dest]
|
||||
if node and (not bestCandidate or bestCandidate[1] > node[1]) then
|
||||
bestCandidate = node
|
||||
bestCandidatePos = dest
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if bestCandidate then
|
||||
return context.translateAllPathsToPath(paths, bestCandidatePos)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if not paths[destPosStr] then
|
||||
local precision = params.precision
|
||||
if type(precision) == 'number' then
|
||||
for p = 1, precision do
|
||||
local bestCandidate = nil
|
||||
local bestCandidatePos = nil
|
||||
for x = -p, p do
|
||||
for y = -p, p do
|
||||
local dest = (destPos.x + x) .. "," .. (destPos.y + y) .. "," .. destPos.z
|
||||
local node = paths[dest]
|
||||
if node and (not bestCandidate or bestCandidate[1] > node[1]) then
|
||||
bestCandidate = node
|
||||
bestCandidatePos = dest
|
||||
end
|
||||
end
|
||||
end
|
||||
if bestCandidate then
|
||||
return context.translateAllPathsToPath(paths, bestCandidatePos)
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
return context.translateAllPathsToPath(paths, destPos)
|
||||
end
|
||||
context.getPath = context.findPath
|
||||
|
||||
-- also works as autoWalk(dirs) where dirs is a list eg.: {1,2,3,0,1,1,2,}
|
||||
context.autoWalk = function(destination, maxDist, params)
|
||||
if type(destination) == "table" and table.isList(destination) and not maxDist and not params then
|
||||
g_game.autoWalk(destination, {x=0,y=0,z=0})
|
||||
return true
|
||||
end
|
||||
|
||||
-- Available params same as for findPath
|
||||
local path = context.findPath(context.player:getPosition(), destination, maxDist, params)
|
||||
if not path then
|
||||
return false
|
||||
end
|
||||
-- autowalk without prewalk animation
|
||||
g_game.autoWalk(path, {x=0,y=0,z=0})
|
||||
return true
|
||||
end
|
||||
|
||||
context.getTileUnderCursor = function()
|
||||
if not modules.game_interface.gameMapPanel.mousePos then return end
|
||||
return modules.game_interface.gameMapPanel:getTile(modules.game_interface.gameMapPanel.mousePos)
|
||||
end
|
||||
|
||||
context.canShoot = function(pos, distance)
|
||||
if not distance then distance = 5 end
|
||||
local tile = g_map.getTile(pos, distance)
|
||||
if tile then
|
||||
return tile:canShoot(distance)
|
||||
end
|
||||
return false
|
||||
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
|
||||
local context = G.botContext
|
||||
|
||||
context.getMapView = function() return modules.game_interface.getMapPanel() end
|
||||
context.getMapPanel = context.getMapView
|
||||
context.zoomIn = function() modules.game_interface.getMapPanel():zoomIn() end
|
||||
context.zoomOut = function() modules.game_interface.getMapPanel():zoomOut() end
|
||||
|
||||
context.getSpectators = function(param1, param2)
|
||||
--[[
|
||||
if param1 is table (position) then it's used for central position, then param2 is used as param1
|
||||
if param1 is creature, then creature position and direction of creature is used, then param2 is used as param1
|
||||
if param1 is true/false then it's used for multifloor, example: getSpectators(true)
|
||||
if param1 is string then it's used for getSpectatorsByPattern
|
||||
]]--
|
||||
local pos = context.player:getPosition()
|
||||
local direction = context.player:getDirection()
|
||||
if type(param1) == 'table' then
|
||||
pos = param1
|
||||
direction = 8 -- invalid direction
|
||||
param1 = param2
|
||||
end
|
||||
if type(param1) == 'userdata' then
|
||||
pos = param1:getPosition()
|
||||
direction = param1:getDirection()
|
||||
param1 = param2
|
||||
end
|
||||
|
||||
if type(param1) == 'string' then
|
||||
return g_map.getSpectatorsByPattern(pos, param1, direction)
|
||||
end
|
||||
|
||||
local multifloor = false
|
||||
if type(param1) == 'boolean' and param1 == true then
|
||||
multifloor = true
|
||||
end
|
||||
return g_map.getSpectators(pos, multifloor)
|
||||
end
|
||||
|
||||
context.getCreatureById = function(id, multifloor)
|
||||
if type(id) ~= 'number' then return nil end
|
||||
if multifloor ~= true then
|
||||
multifloor = false
|
||||
end
|
||||
for i, spec in ipairs(g_map.getSpectators(context.player:getPosition(), multifloor)) do
|
||||
if spec:getId() == id then
|
||||
return spec
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
context.getCreatureByName = function(name, multifloor)
|
||||
if not name then return nil end
|
||||
name = name:lower()
|
||||
if multifloor ~= true then
|
||||
multifloor = false
|
||||
end
|
||||
for i, spec in ipairs(g_map.getSpectators(context.player:getPosition(), multifloor)) do
|
||||
if spec:getName():lower() == name then
|
||||
return spec
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
context.getPlayerByName = function(name, multifloor)
|
||||
if not name then return nil end
|
||||
name = name:lower()
|
||||
if multifloor ~= true then
|
||||
multifloor = false
|
||||
end
|
||||
for i, spec in ipairs(g_map.getSpectators(context.player:getPosition(), multifloor)) do
|
||||
if spec:isPlayer() and spec:getName():lower() == name then
|
||||
return spec
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
context.findAllPaths = function(start, maxDist, params)
|
||||
--[[
|
||||
Available params:
|
||||
ignoreLastCreature
|
||||
ignoreCreatures
|
||||
ignoreNonPathable
|
||||
ignoreNonWalkable
|
||||
ignoreStairs
|
||||
ignoreCost
|
||||
allowUnseen
|
||||
allowOnlyVisibleTiles
|
||||
]]--
|
||||
if type(params) ~= 'table' then
|
||||
params = {}
|
||||
end
|
||||
for key, value in pairs(params) do
|
||||
if value == nil or value == false then
|
||||
params[key] = 0
|
||||
elseif value == true then
|
||||
params[key] = 1
|
||||
end
|
||||
end
|
||||
return g_map.findEveryPath(start, maxDist, params)
|
||||
end
|
||||
context.findEveryPath = context.findAllPaths
|
||||
|
||||
context.translateAllPathsToPath = function(paths, destPos)
|
||||
local predirections = {}
|
||||
local directions = {}
|
||||
local destPosStr = destPos
|
||||
if type(destPos) ~= 'string' then
|
||||
destPosStr = destPos.x .. "," .. destPos.y .. "," .. destPos.z
|
||||
end
|
||||
|
||||
while destPosStr:len() > 0 do
|
||||
local node = paths[destPosStr]
|
||||
if not node then
|
||||
break
|
||||
end
|
||||
if node[3] < 0 then
|
||||
break
|
||||
end
|
||||
table.insert(predirections, node[3])
|
||||
destPosStr = node[4]
|
||||
end
|
||||
-- reverse
|
||||
for i=#predirections,1,-1 do
|
||||
table.insert(directions, predirections[i])
|
||||
end
|
||||
return directions
|
||||
end
|
||||
context.translateEveryPathToPath = context.translateAllPathsToPath
|
||||
|
||||
|
||||
context.findPath = function(startPos, destPos, maxDist, params)
|
||||
--[[
|
||||
Available params:
|
||||
ignoreLastCreature
|
||||
ignoreCreatures
|
||||
ignoreNonPathable
|
||||
ignoreNonWalkable
|
||||
ignoreStairs
|
||||
ignoreCost
|
||||
allowUnseen
|
||||
allowOnlyVisibleTiles
|
||||
precision
|
||||
marginMin
|
||||
marginMax
|
||||
]]--
|
||||
if not destPos or startPos.z ~= destPos.z then
|
||||
return
|
||||
end
|
||||
if type(maxDist) ~= 'number' then
|
||||
maxDist = 100
|
||||
end
|
||||
if type(params) ~= 'table' then
|
||||
params = {}
|
||||
end
|
||||
local destPosStr = destPos.x .. "," .. destPos.y .. "," .. destPos.z
|
||||
params["destination"] = destPosStr
|
||||
local paths = context.findAllPaths(startPos, maxDist, params)
|
||||
local marginMin = params.marginMin or params.minMargin
|
||||
local marginMax = params.marginMax or params.maxMargin
|
||||
if type(marginMin) == 'number' and type(marginMax) == 'number' then
|
||||
local bestCandidate = nil
|
||||
local bestCandidatePos = nil
|
||||
for x = -marginMax, marginMax do
|
||||
for y = -marginMax, marginMax do
|
||||
if math.abs(x) >= marginMin or math.abs(y) >= marginMin then
|
||||
local dest = (destPos.x + x) .. "," .. (destPos.y + y) .. "," .. destPos.z
|
||||
local node = paths[dest]
|
||||
if node and (not bestCandidate or bestCandidate[1] > node[1]) then
|
||||
bestCandidate = node
|
||||
bestCandidatePos = dest
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if bestCandidate then
|
||||
return context.translateAllPathsToPath(paths, bestCandidatePos)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if not paths[destPosStr] then
|
||||
local precision = params.precision
|
||||
if type(precision) == 'number' then
|
||||
for p = 1, precision do
|
||||
local bestCandidate = nil
|
||||
local bestCandidatePos = nil
|
||||
for x = -p, p do
|
||||
for y = -p, p do
|
||||
local dest = (destPos.x + x) .. "," .. (destPos.y + y) .. "," .. destPos.z
|
||||
local node = paths[dest]
|
||||
if node and (not bestCandidate or bestCandidate[1] > node[1]) then
|
||||
bestCandidate = node
|
||||
bestCandidatePos = dest
|
||||
end
|
||||
end
|
||||
end
|
||||
if bestCandidate then
|
||||
return context.translateAllPathsToPath(paths, bestCandidatePos)
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
return context.translateAllPathsToPath(paths, destPos)
|
||||
end
|
||||
context.getPath = context.findPath
|
||||
|
||||
-- also works as autoWalk(dirs) where dirs is a list eg.: {1,2,3,0,1,1,2,}
|
||||
context.autoWalk = function(destination, maxDist, params)
|
||||
if type(destination) == "table" and table.isList(destination) and not maxDist and not params then
|
||||
g_game.autoWalk(destination, {x=0,y=0,z=0})
|
||||
return true
|
||||
end
|
||||
|
||||
-- Available params same as for findPath
|
||||
local path = context.findPath(context.player:getPosition(), destination, maxDist, params)
|
||||
if not path then
|
||||
return false
|
||||
end
|
||||
-- autowalk without prewalk animation
|
||||
g_game.autoWalk(path, {x=0,y=0,z=0})
|
||||
return true
|
||||
end
|
||||
|
||||
context.getTileUnderCursor = function()
|
||||
if not modules.game_interface.gameMapPanel.mousePos then return end
|
||||
return modules.game_interface.gameMapPanel:getTile(modules.game_interface.gameMapPanel.mousePos)
|
||||
end
|
||||
|
||||
context.canShoot = function(pos, distance)
|
||||
if not distance then distance = 5 end
|
||||
local tile = g_map.getTile(pos, distance)
|
||||
if tile then
|
||||
return tile:canShoot(distance)
|
||||
end
|
||||
return false
|
||||
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
|
||||
|
@@ -1,130 +1,130 @@
|
||||
local context = G.botContext
|
||||
|
||||
context.NPC = {}
|
||||
|
||||
context.NPC.talk = function(text)
|
||||
if g_game.getClientVersion() >= 810 then
|
||||
g_game.talkChannel(11, 0, text)
|
||||
else
|
||||
return context.say(text)
|
||||
end
|
||||
end
|
||||
context.NPC.say = context.NPC.talk
|
||||
|
||||
context.NPC.isTrading = function()
|
||||
return modules.game_npctrade.npcWindow and modules.game_npctrade.npcWindow:isVisible()
|
||||
end
|
||||
context.NPC.hasTrade = context.NPC.isTrading
|
||||
context.NPC.hasTradeWindow = context.NPC.isTrading
|
||||
context.NPC.isTradeOpen = context.NPC.isTrading
|
||||
|
||||
context.NPC.getSellItems = function()
|
||||
if not context.NPC.isTrading() then return {} end
|
||||
local items = {}
|
||||
for i, item in ipairs(modules.game_npctrade.tradeItems[modules.game_npctrade.SELL]) do
|
||||
table.insert(items, {
|
||||
item = item.ptr,
|
||||
id = item.ptr:getId(),
|
||||
count = item.ptr:getCount(),
|
||||
name = item.name,
|
||||
subType = item.ptr:getSubType(),
|
||||
weight = item.weight / 100,
|
||||
price = item.price
|
||||
})
|
||||
end
|
||||
return items
|
||||
end
|
||||
|
||||
context.NPC.getBuyItems = function()
|
||||
if not context.NPC.isTrading() then return {} end
|
||||
local items = {}
|
||||
for i, item in ipairs(modules.game_npctrade.tradeItems[modules.game_npctrade.BUY]) do
|
||||
table.insert(items, {
|
||||
item = item.ptr,
|
||||
id = item.ptr:getId(),
|
||||
count = item.ptr:getCount(),
|
||||
name = item.name,
|
||||
subType = item.ptr:getSubType(),
|
||||
weight = item.weight / 100,
|
||||
price = item.price
|
||||
})
|
||||
end
|
||||
return items
|
||||
end
|
||||
|
||||
context.NPC.getSellQuantity = function(item)
|
||||
if not context.NPC.isTrading() then return 0 end
|
||||
if type(item) == 'number' then
|
||||
item = Item.create(item)
|
||||
end
|
||||
return modules.game_npctrade.getSellQuantity(item)
|
||||
end
|
||||
|
||||
context.NPC.canTradeItem = function(item)
|
||||
if not context.NPC.isTrading() then return false end
|
||||
if type(item) == 'number' then
|
||||
item = Item.create(item)
|
||||
end
|
||||
return modules.game_npctrade.canTradeItem(item)
|
||||
end
|
||||
|
||||
context.NPC.sell = function(item, count, ignoreEquipped)
|
||||
if type(item) == 'number' then
|
||||
for i, entry in ipairs(context.NPC.getSellItems()) do
|
||||
if entry.id == item then
|
||||
item = entry.item
|
||||
break
|
||||
end
|
||||
end
|
||||
if type(item) == 'number' then
|
||||
item = Item.create(item)
|
||||
end
|
||||
end
|
||||
if count == 0 then
|
||||
count = 1
|
||||
end
|
||||
if count == nil or count == -1 then
|
||||
count = context.NPC.getSellQuantity(item)
|
||||
end
|
||||
if ignoreEquipped == nil then
|
||||
ignoreEquipped = true
|
||||
end
|
||||
g_game.sellItem(item, count, ignoreEquipped)
|
||||
end
|
||||
|
||||
context.NPC.buy = function(item, count, ignoreCapacity, withBackpack)
|
||||
if type(item) == 'number' then
|
||||
for i, entry in ipairs(context.NPC.getBuyItems()) do
|
||||
if entry.id == item then
|
||||
item = entry.item
|
||||
break
|
||||
end
|
||||
end
|
||||
if type(item) == 'number' then
|
||||
item = Item.create(item)
|
||||
end
|
||||
end
|
||||
if count == nil or count <= 0 then
|
||||
count = 1
|
||||
end
|
||||
if ignoreCapacity == nil then
|
||||
ignoreCapacity = false
|
||||
end
|
||||
if withBackpack == nil then
|
||||
withBackpack = false
|
||||
end
|
||||
g_game.buyItem(item, count, ignoreCapacity, withBackpack)
|
||||
end
|
||||
|
||||
context.NPC.sellAll = function()
|
||||
if not context.NPC.isTrading() then return false end
|
||||
modules.game_npctrade.sellAll()
|
||||
end
|
||||
|
||||
context.NPC.closeTrade = function()
|
||||
modules.game_npctrade.closeNpcTrade()
|
||||
end
|
||||
context.NPC.close = context.NPC.closeTrade
|
||||
context.NPC.finish = context.NPC.closeTrade
|
||||
context.NPC.endTrade = context.NPC.closeTrade
|
||||
local context = G.botContext
|
||||
|
||||
context.NPC = {}
|
||||
|
||||
context.NPC.talk = function(text)
|
||||
if g_game.getClientVersion() >= 810 then
|
||||
g_game.talkChannel(11, 0, text)
|
||||
else
|
||||
return context.say(text)
|
||||
end
|
||||
end
|
||||
context.NPC.say = context.NPC.talk
|
||||
|
||||
context.NPC.isTrading = function()
|
||||
return modules.game_npctrade.npcWindow and modules.game_npctrade.npcWindow:isVisible()
|
||||
end
|
||||
context.NPC.hasTrade = context.NPC.isTrading
|
||||
context.NPC.hasTradeWindow = context.NPC.isTrading
|
||||
context.NPC.isTradeOpen = context.NPC.isTrading
|
||||
|
||||
context.NPC.getSellItems = function()
|
||||
if not context.NPC.isTrading() then return {} end
|
||||
local items = {}
|
||||
for i, item in ipairs(modules.game_npctrade.tradeItems[modules.game_npctrade.SELL]) do
|
||||
table.insert(items, {
|
||||
item = item.ptr,
|
||||
id = item.ptr:getId(),
|
||||
count = item.ptr:getCount(),
|
||||
name = item.name,
|
||||
subType = item.ptr:getSubType(),
|
||||
weight = item.weight / 100,
|
||||
price = item.price
|
||||
})
|
||||
end
|
||||
return items
|
||||
end
|
||||
|
||||
context.NPC.getBuyItems = function()
|
||||
if not context.NPC.isTrading() then return {} end
|
||||
local items = {}
|
||||
for i, item in ipairs(modules.game_npctrade.tradeItems[modules.game_npctrade.BUY]) do
|
||||
table.insert(items, {
|
||||
item = item.ptr,
|
||||
id = item.ptr:getId(),
|
||||
count = item.ptr:getCount(),
|
||||
name = item.name,
|
||||
subType = item.ptr:getSubType(),
|
||||
weight = item.weight / 100,
|
||||
price = item.price
|
||||
})
|
||||
end
|
||||
return items
|
||||
end
|
||||
|
||||
context.NPC.getSellQuantity = function(item)
|
||||
if not context.NPC.isTrading() then return 0 end
|
||||
if type(item) == 'number' then
|
||||
item = Item.create(item)
|
||||
end
|
||||
return modules.game_npctrade.getSellQuantity(item)
|
||||
end
|
||||
|
||||
context.NPC.canTradeItem = function(item)
|
||||
if not context.NPC.isTrading() then return false end
|
||||
if type(item) == 'number' then
|
||||
item = Item.create(item)
|
||||
end
|
||||
return modules.game_npctrade.canTradeItem(item)
|
||||
end
|
||||
|
||||
context.NPC.sell = function(item, count, ignoreEquipped)
|
||||
if type(item) == 'number' then
|
||||
for i, entry in ipairs(context.NPC.getSellItems()) do
|
||||
if entry.id == item then
|
||||
item = entry.item
|
||||
break
|
||||
end
|
||||
end
|
||||
if type(item) == 'number' then
|
||||
item = Item.create(item)
|
||||
end
|
||||
end
|
||||
if count == 0 then
|
||||
count = 1
|
||||
end
|
||||
if count == nil or count == -1 then
|
||||
count = context.NPC.getSellQuantity(item)
|
||||
end
|
||||
if ignoreEquipped == nil then
|
||||
ignoreEquipped = true
|
||||
end
|
||||
g_game.sellItem(item, count, ignoreEquipped)
|
||||
end
|
||||
|
||||
context.NPC.buy = function(item, count, ignoreCapacity, withBackpack)
|
||||
if type(item) == 'number' then
|
||||
for i, entry in ipairs(context.NPC.getBuyItems()) do
|
||||
if entry.id == item then
|
||||
item = entry.item
|
||||
break
|
||||
end
|
||||
end
|
||||
if type(item) == 'number' then
|
||||
item = Item.create(item)
|
||||
end
|
||||
end
|
||||
if count == nil or count <= 0 then
|
||||
count = 1
|
||||
end
|
||||
if ignoreCapacity == nil then
|
||||
ignoreCapacity = false
|
||||
end
|
||||
if withBackpack == nil then
|
||||
withBackpack = false
|
||||
end
|
||||
g_game.buyItem(item, count, ignoreCapacity, withBackpack)
|
||||
end
|
||||
|
||||
context.NPC.sellAll = function()
|
||||
if not context.NPC.isTrading() then return false end
|
||||
modules.game_npctrade.sellAll()
|
||||
end
|
||||
|
||||
context.NPC.closeTrade = function()
|
||||
modules.game_npctrade.closeNpcTrade()
|
||||
end
|
||||
context.NPC.close = context.NPC.closeTrade
|
||||
context.NPC.finish = context.NPC.closeTrade
|
||||
context.NPC.endTrade = context.NPC.closeTrade
|
||||
context.NPC.finishTrade = context.NPC.closeTrade
|
@@ -1,167 +1,167 @@
|
||||
local context = G.botContext
|
||||
|
||||
context.name = function() return context.player:getName() end
|
||||
|
||||
context.hp = function() return context.player:getHealth() end
|
||||
context.mana = function() return context.player:getMana() end
|
||||
context.hppercent = function() return context.player:getHealthPercent() end
|
||||
context.manapercent = function() if context.player:getMaxMana() <= 1 then return 100 else return math.floor(context.player:getMana() * 100 / context.player:getMaxMana()) end end
|
||||
context.maxhp = function() return context.player:getMaxHealth() end
|
||||
context.maxmana = function() return context.player:getMaxMana() end
|
||||
context.hpmax = function() return context.player:getMaxHealth() end
|
||||
context.manamax = function() return context.player:getMaxMana() end
|
||||
|
||||
context.cap = function() return context.player:getCapacity() end
|
||||
context.freecap = function() return context.player:getFreeCapacity() end
|
||||
context.maxcap = function() return context.player:getTotalCapacity() end
|
||||
context.capmax = function() return context.player:getTotalCapacity() end
|
||||
|
||||
context.exp = function() return context.player:getExperience() end
|
||||
context.lvl = function() return context.player:getLevel() end
|
||||
context.level = function() return context.player:getLevel() end
|
||||
|
||||
context.mlev = function() return context.player:getMagicLevel() end
|
||||
context.magic = function() return context.player:getMagicLevel() end
|
||||
context.mlevel = function() return context.player:getMagicLevel() end
|
||||
|
||||
context.soul = function() return context.player:getSoul() end
|
||||
context.stamina = function() return context.player:getStamina() end
|
||||
context.voc = function() return context.player:getVocation() end
|
||||
context.vocation = function() return context.player:getVocation() end
|
||||
|
||||
context.bless = function() return context.player:getBlessings() end
|
||||
context.blesses = function() return context.player:getBlessings() end
|
||||
context.blessings = function() return context.player:getBlessings() end
|
||||
|
||||
|
||||
context.pos = function() return context.player:getPosition() end
|
||||
context.posx = function() return context.player:getPosition().x end
|
||||
context.posy = function() return context.player:getPosition().y end
|
||||
context.posz = function() return context.player:getPosition().z end
|
||||
|
||||
context.direction = function() return context.player:getDirection() end
|
||||
context.speed = function() return context.player:getSpeed() end
|
||||
context.skull = function() return context.player:getSkull() end
|
||||
context.outfit = function() return context.player:getOutfit() end
|
||||
|
||||
context.setOutfit = function(outfit)
|
||||
modules.game_outfit.ignoreNextOutfitWindow = g_clock.millis()
|
||||
g_game.requestOutfit()
|
||||
context.schedule(100, function()
|
||||
g_game.changeOutfit(outfit)
|
||||
end)
|
||||
end
|
||||
context.changeOutfit = context.setOutfit
|
||||
context.setSpeed = function(value) context.player:setSpeed(value) end
|
||||
|
||||
context.walk = function(dir) return modules.game_walking.walk(dir) end
|
||||
context.turn = function(dir) return g_game.turn(dir) end
|
||||
|
||||
-- game releated
|
||||
context.getChannels = function()
|
||||
-- return { channelId = channelName }
|
||||
return modules.game_console.channels
|
||||
end
|
||||
context.getChannelId = function(name)
|
||||
for id, channel in pairs(context.getChannels()) do
|
||||
if name:lower() == channel:lower() then
|
||||
return id
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
context.getChannel = context.getChannelId
|
||||
|
||||
context.say = g_game.talk
|
||||
context.talk = g_game.talk
|
||||
context.yell = function(text) g_game.talkChannel(3, 0, text) end
|
||||
context.talkChannel = function(channel, text) g_game.talkChannel(7, channel, text) end
|
||||
context.sayChannel = context.talkChannel
|
||||
context.talkPrivate = function(receiver, text) g_game.talkPrivate(5, receiver, text) end
|
||||
context.sayPrivate = context.talkPrivate
|
||||
|
||||
context.talkNpc = function(text)
|
||||
if g_game.getClientVersion() >= 810 then
|
||||
g_game.talkChannel(11, 0, text)
|
||||
else
|
||||
return context.say(text)
|
||||
end
|
||||
end
|
||||
context.sayNpc = context.talkNpc
|
||||
context.sayNPC = context.talkNpc
|
||||
context.talkNPC = context.talkNpc
|
||||
|
||||
context.saySpell = function(text, lastSpellTimeout)
|
||||
if not text or text:len() < 1 then
|
||||
return
|
||||
end
|
||||
if context.lastSpell == nil then
|
||||
context.lastSpell = 0
|
||||
end
|
||||
if not lastSpellTimeout then
|
||||
lastSpellTimeout = 1000
|
||||
end
|
||||
if context.lastSpell + lastSpellTimeout > context.now then
|
||||
return false
|
||||
end
|
||||
context.say(text)
|
||||
context.lastSpell = context.now
|
||||
return true
|
||||
end
|
||||
|
||||
context.setSpellTimeout = function()
|
||||
context.lastSpell = context.now
|
||||
end
|
||||
|
||||
context.use = function(thing, subtype)
|
||||
if type(thing) == 'number' then
|
||||
return g_game.useInventoryItem(thing, subtype)
|
||||
else
|
||||
return g_game.use(thing)
|
||||
end
|
||||
end
|
||||
context.usewith = function(thing, target, subtype)
|
||||
if type(thing) == 'number' then
|
||||
return g_game.useInventoryItemWith(thing, target, subtype)
|
||||
else
|
||||
return g_game.useWith(item, target, subtype)
|
||||
end
|
||||
end
|
||||
context.useWith = context.usewith
|
||||
|
||||
context.useRune = function(itemid, target, lastSpellTimeout)
|
||||
if context.lastRuneUse == nil then
|
||||
context.lastRuneUse = 0
|
||||
end
|
||||
if not lastRuneTimeout then
|
||||
lastRuneTimeout = 1000
|
||||
end
|
||||
if context.lastRuneUse + lastRuneTimeout > context.now then
|
||||
return false
|
||||
end
|
||||
context.usewith(itemid, target)
|
||||
context.lastRuneUse = context.now
|
||||
return true
|
||||
end
|
||||
context.userune = context.useRune
|
||||
|
||||
context.findItem = function(itemId, subType)
|
||||
if subType == nil then
|
||||
subType = -1
|
||||
end
|
||||
return g_game.findItemInContainers(itemId, subType)
|
||||
end
|
||||
|
||||
context.attack = g_game.attack
|
||||
context.cancelAttack = g_game.cancelAttack
|
||||
context.follow = g_game.follow
|
||||
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)
|
||||
modules.game_cooldown.isCooldownIconActive(id)
|
||||
|
||||
local context = G.botContext
|
||||
|
||||
context.name = function() return context.player:getName() end
|
||||
|
||||
context.hp = function() return context.player:getHealth() end
|
||||
context.mana = function() return context.player:getMana() end
|
||||
context.hppercent = function() return context.player:getHealthPercent() end
|
||||
context.manapercent = function() if context.player:getMaxMana() <= 1 then return 100 else return math.floor(context.player:getMana() * 100 / context.player:getMaxMana()) end end
|
||||
context.maxhp = function() return context.player:getMaxHealth() end
|
||||
context.maxmana = function() return context.player:getMaxMana() end
|
||||
context.hpmax = function() return context.player:getMaxHealth() end
|
||||
context.manamax = function() return context.player:getMaxMana() end
|
||||
|
||||
context.cap = function() return context.player:getCapacity() end
|
||||
context.freecap = function() return context.player:getFreeCapacity() end
|
||||
context.maxcap = function() return context.player:getTotalCapacity() end
|
||||
context.capmax = function() return context.player:getTotalCapacity() end
|
||||
|
||||
context.exp = function() return context.player:getExperience() end
|
||||
context.lvl = function() return context.player:getLevel() end
|
||||
context.level = function() return context.player:getLevel() end
|
||||
|
||||
context.mlev = function() return context.player:getMagicLevel() end
|
||||
context.magic = function() return context.player:getMagicLevel() end
|
||||
context.mlevel = function() return context.player:getMagicLevel() end
|
||||
|
||||
context.soul = function() return context.player:getSoul() end
|
||||
context.stamina = function() return context.player:getStamina() end
|
||||
context.voc = function() return context.player:getVocation() end
|
||||
context.vocation = function() return context.player:getVocation() end
|
||||
|
||||
context.bless = function() return context.player:getBlessings() end
|
||||
context.blesses = function() return context.player:getBlessings() end
|
||||
context.blessings = function() return context.player:getBlessings() end
|
||||
|
||||
|
||||
context.pos = function() return context.player:getPosition() end
|
||||
context.posx = function() return context.player:getPosition().x end
|
||||
context.posy = function() return context.player:getPosition().y end
|
||||
context.posz = function() return context.player:getPosition().z end
|
||||
|
||||
context.direction = function() return context.player:getDirection() end
|
||||
context.speed = function() return context.player:getSpeed() end
|
||||
context.skull = function() return context.player:getSkull() end
|
||||
context.outfit = function() return context.player:getOutfit() end
|
||||
|
||||
context.setOutfit = function(outfit)
|
||||
modules.game_outfit.ignoreNextOutfitWindow = g_clock.millis()
|
||||
g_game.requestOutfit()
|
||||
context.schedule(100, function()
|
||||
g_game.changeOutfit(outfit)
|
||||
end)
|
||||
end
|
||||
context.changeOutfit = context.setOutfit
|
||||
context.setSpeed = function(value) context.player:setSpeed(value) end
|
||||
|
||||
context.walk = function(dir) return modules.game_walking.walk(dir) end
|
||||
context.turn = function(dir) return g_game.turn(dir) end
|
||||
|
||||
-- game releated
|
||||
context.getChannels = function()
|
||||
-- return { channelId = channelName }
|
||||
return modules.game_console.channels
|
||||
end
|
||||
context.getChannelId = function(name)
|
||||
for id, channel in pairs(context.getChannels()) do
|
||||
if name:lower() == channel:lower() then
|
||||
return id
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
context.getChannel = context.getChannelId
|
||||
|
||||
context.say = g_game.talk
|
||||
context.talk = g_game.talk
|
||||
context.yell = function(text) g_game.talkChannel(3, 0, text) end
|
||||
context.talkChannel = function(channel, text) g_game.talkChannel(7, channel, text) end
|
||||
context.sayChannel = context.talkChannel
|
||||
context.talkPrivate = function(receiver, text) g_game.talkPrivate(5, receiver, text) end
|
||||
context.sayPrivate = context.talkPrivate
|
||||
|
||||
context.talkNpc = function(text)
|
||||
if g_game.getClientVersion() >= 810 then
|
||||
g_game.talkChannel(11, 0, text)
|
||||
else
|
||||
return context.say(text)
|
||||
end
|
||||
end
|
||||
context.sayNpc = context.talkNpc
|
||||
context.sayNPC = context.talkNpc
|
||||
context.talkNPC = context.talkNpc
|
||||
|
||||
context.saySpell = function(text, lastSpellTimeout)
|
||||
if not text or text:len() < 1 then
|
||||
return
|
||||
end
|
||||
if context.lastSpell == nil then
|
||||
context.lastSpell = 0
|
||||
end
|
||||
if not lastSpellTimeout then
|
||||
lastSpellTimeout = 1000
|
||||
end
|
||||
if context.lastSpell + lastSpellTimeout > context.now then
|
||||
return false
|
||||
end
|
||||
context.say(text)
|
||||
context.lastSpell = context.now
|
||||
return true
|
||||
end
|
||||
|
||||
context.setSpellTimeout = function()
|
||||
context.lastSpell = context.now
|
||||
end
|
||||
|
||||
context.use = function(thing, subtype)
|
||||
if type(thing) == 'number' then
|
||||
return g_game.useInventoryItem(thing, subtype)
|
||||
else
|
||||
return g_game.use(thing)
|
||||
end
|
||||
end
|
||||
context.usewith = function(thing, target, subtype)
|
||||
if type(thing) == 'number' then
|
||||
return g_game.useInventoryItemWith(thing, target, subtype)
|
||||
else
|
||||
return g_game.useWith(item, target, subtype)
|
||||
end
|
||||
end
|
||||
context.useWith = context.usewith
|
||||
|
||||
context.useRune = function(itemid, target, lastSpellTimeout)
|
||||
if context.lastRuneUse == nil then
|
||||
context.lastRuneUse = 0
|
||||
end
|
||||
if not lastRuneTimeout then
|
||||
lastRuneTimeout = 1000
|
||||
end
|
||||
if context.lastRuneUse + lastRuneTimeout > context.now then
|
||||
return false
|
||||
end
|
||||
context.usewith(itemid, target)
|
||||
context.lastRuneUse = context.now
|
||||
return true
|
||||
end
|
||||
context.userune = context.useRune
|
||||
|
||||
context.findItem = function(itemId, subType)
|
||||
if subType == nil then
|
||||
subType = -1
|
||||
end
|
||||
return g_game.findItemInContainers(itemId, subType)
|
||||
end
|
||||
|
||||
context.attack = g_game.attack
|
||||
context.cancelAttack = g_game.cancelAttack
|
||||
context.follow = g_game.follow
|
||||
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)
|
||||
modules.game_cooldown.isCooldownIconActive(id)
|
||||
|
||||
|
@@ -1,32 +1,32 @@
|
||||
local context = G.botContext
|
||||
|
||||
for i, state in ipairs(PlayerStates) do
|
||||
context[state] = state
|
||||
end
|
||||
|
||||
context.hasCondition = function(condition) return bit.band(context.player:getStates(), condition) > 0 end
|
||||
|
||||
context.isPoisioned = function() return context.hasCondition(PlayerStates.Poison) end
|
||||
context.isBurnining = function() return context.hasCondition(PlayerStates.Burn) end
|
||||
context.isEnergized = function() return context.hasCondition(PlayerStates.Energy) end
|
||||
context.isDrunk = function() return context.hasCondition(PlayerStates.Drunk) end
|
||||
context.hasManaShield = function() return context.hasCondition(PlayerStates.ManaShield) end
|
||||
context.isParalyzed = function() return context.hasCondition(PlayerStates.Paralyze) end
|
||||
context.hasHaste = function() return context.hasCondition(PlayerStates.Haste) end
|
||||
context.hasSwords = function() return context.hasCondition(PlayerStates.Swords) end
|
||||
context.isInFight = function() return context.hasCondition(PlayerStates.Swords) end
|
||||
context.canLogout = function() return not context.hasCondition(PlayerStates.Swords) end
|
||||
context.isDrowning = function() return context.hasCondition(PlayerStates.Drowning) end
|
||||
context.isFreezing = function() return context.hasCondition(PlayerStates.Freezing) end
|
||||
context.isDazzled = function() return context.hasCondition(PlayerStates.Dazzled) end
|
||||
context.isCursed = function() return context.hasCondition(PlayerStates.Cursed) end
|
||||
context.hasPartyBuff = function() return context.hasCondition(PlayerStates.PartyBuff) end
|
||||
context.hasPzLock = function() return context.hasCondition(PlayerStates.PzBlock) end
|
||||
context.hasPzBlock = function() return context.hasCondition(PlayerStates.PzBlock) end
|
||||
context.isPzLocked = function() return context.hasCondition(PlayerStates.PzBlock) end
|
||||
context.isPzBlocked = function() return context.hasCondition(PlayerStates.PzBlock) end
|
||||
context.isInProtectionZone = function() return context.hasCondition(PlayerStates.Pz) end
|
||||
context.hasPz = function() return context.hasCondition(PlayerStates.Pz) end
|
||||
context.isInPz = function() return context.hasCondition(PlayerStates.Pz) end
|
||||
context.isBleeding = function() return context.hasCondition(PlayerStates.Bleeding) end
|
||||
context.isHungry = function() return context.hasCondition(PlayerStates.Hungry) end
|
||||
local context = G.botContext
|
||||
|
||||
for i, state in ipairs(PlayerStates) do
|
||||
context[state] = state
|
||||
end
|
||||
|
||||
context.hasCondition = function(condition) return bit.band(context.player:getStates(), condition) > 0 end
|
||||
|
||||
context.isPoisioned = function() return context.hasCondition(PlayerStates.Poison) end
|
||||
context.isBurnining = function() return context.hasCondition(PlayerStates.Burn) end
|
||||
context.isEnergized = function() return context.hasCondition(PlayerStates.Energy) end
|
||||
context.isDrunk = function() return context.hasCondition(PlayerStates.Drunk) end
|
||||
context.hasManaShield = function() return context.hasCondition(PlayerStates.ManaShield) end
|
||||
context.isParalyzed = function() return context.hasCondition(PlayerStates.Paralyze) end
|
||||
context.hasHaste = function() return context.hasCondition(PlayerStates.Haste) end
|
||||
context.hasSwords = function() return context.hasCondition(PlayerStates.Swords) end
|
||||
context.isInFight = function() return context.hasCondition(PlayerStates.Swords) end
|
||||
context.canLogout = function() return not context.hasCondition(PlayerStates.Swords) end
|
||||
context.isDrowning = function() return context.hasCondition(PlayerStates.Drowning) end
|
||||
context.isFreezing = function() return context.hasCondition(PlayerStates.Freezing) end
|
||||
context.isDazzled = function() return context.hasCondition(PlayerStates.Dazzled) end
|
||||
context.isCursed = function() return context.hasCondition(PlayerStates.Cursed) end
|
||||
context.hasPartyBuff = function() return context.hasCondition(PlayerStates.PartyBuff) end
|
||||
context.hasPzLock = function() return context.hasCondition(PlayerStates.PzBlock) end
|
||||
context.hasPzBlock = function() return context.hasCondition(PlayerStates.PzBlock) end
|
||||
context.isPzLocked = function() return context.hasCondition(PlayerStates.PzBlock) end
|
||||
context.isPzBlocked = function() return context.hasCondition(PlayerStates.PzBlock) end
|
||||
context.isInProtectionZone = function() return context.hasCondition(PlayerStates.Pz) end
|
||||
context.hasPz = function() return context.hasCondition(PlayerStates.Pz) end
|
||||
context.isInPz = function() return context.hasCondition(PlayerStates.Pz) end
|
||||
context.isBleeding = function() return context.hasCondition(PlayerStates.Bleeding) end
|
||||
context.isHungry = function() return context.hasCondition(PlayerStates.Hungry) end
|
||||
|
@@ -1,45 +1,45 @@
|
||||
local context = G.botContext
|
||||
|
||||
context.SlotOther = InventorySlotOther
|
||||
context.SlotHead = InventorySlotHead
|
||||
context.SlotNeck = InventorySlotNeck
|
||||
context.SlotBack = InventorySlotBack
|
||||
context.SlotBody = InventorySlotBody
|
||||
context.SlotRight = InventorySlotRight
|
||||
context.SlotLeft = InventorySlotLeft
|
||||
context.SlotLeg = InventorySlotLeg
|
||||
context.SlotFeet = InventorySlotFeet
|
||||
context.SlotFinger = InventorySlotFinger
|
||||
context.SlotAmmo = InventorySlotAmmo
|
||||
context.SlotPurse = InventorySlotPurse
|
||||
|
||||
context.getInventoryItem = function(slot) return context.player:getInventoryItem(slot) end
|
||||
context.getSlot = context.getInventoryItem
|
||||
|
||||
context.getHead = function() return context.getInventoryItem(context.SlotHead) end
|
||||
context.getNeck = function() return context.getInventoryItem(context.SlotNeck) end
|
||||
context.getBack = function() return context.getInventoryItem(context.SlotBack) end
|
||||
context.getBody = function() return context.getInventoryItem(context.SlotBody) end
|
||||
context.getRight = function() return context.getInventoryItem(context.SlotRight) end
|
||||
context.getLeft = function() return context.getInventoryItem(context.SlotLeft) end
|
||||
context.getLeg = function() return context.getInventoryItem(context.SlotLeg) end
|
||||
context.getFeet = function() return context.getInventoryItem(context.SlotFeet) end
|
||||
context.getFinger = function() return context.getInventoryItem(context.SlotFinger) end
|
||||
context.getAmmo = function() return context.getInventoryItem(context.SlotAmmo) end
|
||||
context.getPurse = function() return context.getInventoryItem(context.SlotPurse) end
|
||||
|
||||
context.getContainers = function() return g_game.getContainers() end
|
||||
context.getContainer = function(index) return g_game.getContainer(index) end
|
||||
|
||||
context.moveToSlot = function(item, slot, count)
|
||||
if type(item) == 'number' then
|
||||
item = context.findItem(item)
|
||||
end
|
||||
if not item then
|
||||
return
|
||||
end
|
||||
if count == nil then
|
||||
count = item:getCount()
|
||||
end
|
||||
return g_game.move(item, {x=65535, y=slot, z=0}, count)
|
||||
local context = G.botContext
|
||||
|
||||
context.SlotOther = InventorySlotOther
|
||||
context.SlotHead = InventorySlotHead
|
||||
context.SlotNeck = InventorySlotNeck
|
||||
context.SlotBack = InventorySlotBack
|
||||
context.SlotBody = InventorySlotBody
|
||||
context.SlotRight = InventorySlotRight
|
||||
context.SlotLeft = InventorySlotLeft
|
||||
context.SlotLeg = InventorySlotLeg
|
||||
context.SlotFeet = InventorySlotFeet
|
||||
context.SlotFinger = InventorySlotFinger
|
||||
context.SlotAmmo = InventorySlotAmmo
|
||||
context.SlotPurse = InventorySlotPurse
|
||||
|
||||
context.getInventoryItem = function(slot) return context.player:getInventoryItem(slot) end
|
||||
context.getSlot = context.getInventoryItem
|
||||
|
||||
context.getHead = function() return context.getInventoryItem(context.SlotHead) end
|
||||
context.getNeck = function() return context.getInventoryItem(context.SlotNeck) end
|
||||
context.getBack = function() return context.getInventoryItem(context.SlotBack) end
|
||||
context.getBody = function() return context.getInventoryItem(context.SlotBody) end
|
||||
context.getRight = function() return context.getInventoryItem(context.SlotRight) end
|
||||
context.getLeft = function() return context.getInventoryItem(context.SlotLeft) end
|
||||
context.getLeg = function() return context.getInventoryItem(context.SlotLeg) end
|
||||
context.getFeet = function() return context.getInventoryItem(context.SlotFeet) end
|
||||
context.getFinger = function() return context.getInventoryItem(context.SlotFinger) end
|
||||
context.getAmmo = function() return context.getInventoryItem(context.SlotAmmo) end
|
||||
context.getPurse = function() return context.getInventoryItem(context.SlotPurse) end
|
||||
|
||||
context.getContainers = function() return g_game.getContainers() end
|
||||
context.getContainer = function(index) return g_game.getContainer(index) end
|
||||
|
||||
context.moveToSlot = function(item, slot, count)
|
||||
if type(item) == 'number' then
|
||||
item = context.findItem(item)
|
||||
end
|
||||
if not item then
|
||||
return
|
||||
end
|
||||
if count == nil then
|
||||
count = item:getCount()
|
||||
end
|
||||
return g_game.move(item, {x=65535, y=slot, z=0}, count)
|
||||
end
|
@@ -1,59 +1,59 @@
|
||||
local context = G.botContext
|
||||
|
||||
context.loadScript = function(path, onLoadCallback)
|
||||
if type(path) ~= 'string' then
|
||||
return context.error("Invalid path for loadScript: " .. tostring(path))
|
||||
end
|
||||
if path:lower():find("http") == 1 then
|
||||
return context.loadRemoteScript(path)
|
||||
end
|
||||
if not g_resources.fileExists(path) then
|
||||
return context.error("File " .. path .. " doesn't exist")
|
||||
end
|
||||
|
||||
local status, result = pcall(function()
|
||||
assert(load(g_resources.readFileContents(path), path, nil, context))()
|
||||
end)
|
||||
if not status then
|
||||
return context.error("Error while loading script from: " .. path .. ":\n" .. result)
|
||||
end
|
||||
if onLoadCallback then
|
||||
onLoadCallback()
|
||||
end
|
||||
end
|
||||
|
||||
context.loadRemoteScript = function(url, onLoadCallback)
|
||||
if type(url) ~= 'string' or url:lower():find("http") ~= 1 then
|
||||
return context.error("Invalid url for loadRemoteScript: " .. tostring(url))
|
||||
end
|
||||
|
||||
HTTP.get(url, function(data, err)
|
||||
if err or data:len() == 0 then
|
||||
-- try to load from cache
|
||||
if type(context.storage.scriptsCache) ~= 'table' then
|
||||
context.storage.scriptsCache = {}
|
||||
end
|
||||
local cache = context.storage.scriptsCache[url]
|
||||
if cache and type(cache) == 'string' and cache:len() > 0 then
|
||||
data = cache
|
||||
else
|
||||
return context.error("Can't load script from: " .. url .. ", error: " .. err)
|
||||
end
|
||||
end
|
||||
|
||||
local status, result = pcall(function()
|
||||
assert(load(data, url, nil, context))()
|
||||
end)
|
||||
if not status then
|
||||
return context.error("Error while loading script from: " .. url .. ":\n" .. result)
|
||||
end
|
||||
-- cache script
|
||||
if type(context.storage.scriptsCache) ~= 'table' then
|
||||
context.storage.scriptsCache = {}
|
||||
end
|
||||
context.storage.scriptsCache[url] = data
|
||||
if onLoadCallback then
|
||||
onLoadCallback()
|
||||
end
|
||||
end)
|
||||
end
|
||||
local context = G.botContext
|
||||
|
||||
context.loadScript = function(path, onLoadCallback)
|
||||
if type(path) ~= 'string' then
|
||||
return context.error("Invalid path for loadScript: " .. tostring(path))
|
||||
end
|
||||
if path:lower():find("http") == 1 then
|
||||
return context.loadRemoteScript(path)
|
||||
end
|
||||
if not g_resources.fileExists(path) then
|
||||
return context.error("File " .. path .. " doesn't exist")
|
||||
end
|
||||
|
||||
local status, result = pcall(function()
|
||||
assert(load(g_resources.readFileContents(path), path, nil, context))()
|
||||
end)
|
||||
if not status then
|
||||
return context.error("Error while loading script from: " .. path .. ":\n" .. result)
|
||||
end
|
||||
if onLoadCallback then
|
||||
onLoadCallback()
|
||||
end
|
||||
end
|
||||
|
||||
context.loadRemoteScript = function(url, onLoadCallback)
|
||||
if type(url) ~= 'string' or url:lower():find("http") ~= 1 then
|
||||
return context.error("Invalid url for loadRemoteScript: " .. tostring(url))
|
||||
end
|
||||
|
||||
HTTP.get(url, function(data, err)
|
||||
if err or data:len() == 0 then
|
||||
-- try to load from cache
|
||||
if type(context.storage.scriptsCache) ~= 'table' then
|
||||
context.storage.scriptsCache = {}
|
||||
end
|
||||
local cache = context.storage.scriptsCache[url]
|
||||
if cache and type(cache) == 'string' and cache:len() > 0 then
|
||||
data = cache
|
||||
else
|
||||
return context.error("Can't load script from: " .. url .. ", error: " .. err)
|
||||
end
|
||||
end
|
||||
|
||||
local status, result = pcall(function()
|
||||
assert(load(data, url, nil, context))()
|
||||
end)
|
||||
if not status then
|
||||
return context.error("Error while loading script from: " .. url .. ":\n" .. result)
|
||||
end
|
||||
-- cache script
|
||||
if type(context.storage.scriptsCache) ~= 'table' then
|
||||
context.storage.scriptsCache = {}
|
||||
end
|
||||
context.storage.scriptsCache[url] = data
|
||||
if onLoadCallback then
|
||||
onLoadCallback()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
@@ -1,91 +1,91 @@
|
||||
local context = G.botContext
|
||||
|
||||
context.BotServer = {}
|
||||
context.BotServer.url = "ws://bot.otclient.ovh:8000/"
|
||||
context.BotServer.timeout = 3
|
||||
context.BotServer.ping = 0
|
||||
context.BotServer._callbacks = {}
|
||||
context.BotServer._lastMessageId = 0
|
||||
context.BotServer._wasConnected = true -- show first warning
|
||||
|
||||
context.BotServer.init = function(name, channel)
|
||||
if not channel or not name or channel:len() < 1 or name:len() < 1 then
|
||||
return context.error("Invalid params for BotServer.init")
|
||||
end
|
||||
if context.BotServer._websocket then
|
||||
return context.error("BotServer is already initialized")
|
||||
end
|
||||
context.BotServer._websocket = HTTP.WebSocketJSON(context.BotServer.url, {
|
||||
onMessage = function(message, socketId)
|
||||
if not context._websockets[socketId] then
|
||||
return g_http.cancel(socketId)
|
||||
end
|
||||
if not context.BotServer._websocket or context.BotServer._websocket.id ~= socketId then
|
||||
return g_http.cancel(socketId)
|
||||
end
|
||||
context.BotServer._wasConnected = true
|
||||
if message["type"] == "ping" then
|
||||
context.BotServer.ping = message["ping"]
|
||||
return context.BotServer._websocket.send({type="ping"})
|
||||
end
|
||||
if message["type"] == "message" then
|
||||
context.BotServer._lastMessageId = message["id"]
|
||||
local topics = context.BotServer._callbacks[message["topic"]]
|
||||
if topics then
|
||||
for i=1,#topics do
|
||||
topics[i](message["name"], message["message"], message["topic"])
|
||||
end
|
||||
end
|
||||
topics = context.BotServer._callbacks["*"]
|
||||
if topics then
|
||||
for i=1,#topics do
|
||||
topics[i](message["name"], message["message"], message["topic"])
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
end,
|
||||
onClose = function(message, socketId)
|
||||
if not context._websockets[socketId] then
|
||||
return
|
||||
end
|
||||
context._websockets[socketId] = nil
|
||||
if not context.BotServer._websocket or context.BotServer._websocket.id ~= socketId then
|
||||
return
|
||||
end
|
||||
if context.BotServer._wasConnected then
|
||||
context.warn("BotServer disconnected")
|
||||
end
|
||||
context.BotServer._wasConnected = false
|
||||
context.BotServer._websocket = nil
|
||||
context.BotServer.ping = 0
|
||||
context.BotServer.init(name, channel)
|
||||
end
|
||||
}, context.BotServer.timeout)
|
||||
context._websockets[context.BotServer._websocket.id] = 1
|
||||
context.BotServer._websocket.send({type="init", name=name, channel=channel, lastMessage=context.BotServer._lastMessageId})
|
||||
end
|
||||
|
||||
context.BotServer.terminate = function()
|
||||
if context.BotServer._websocket then
|
||||
context.BotServer._websocket:close()
|
||||
context.BotServer._websocket = nil
|
||||
end
|
||||
end
|
||||
|
||||
context.BotServer.listen = function(topic, callback) -- callback = function(name, message, topic) -- message is parsed json = table
|
||||
if not context.BotServer._websocket then
|
||||
return context.error("BotServer is not initialized")
|
||||
end
|
||||
if not context.BotServer._callbacks[topic] then
|
||||
context.BotServer._callbacks[topic] = {}
|
||||
end
|
||||
table.insert(context.BotServer._callbacks[topic], callback)
|
||||
end
|
||||
|
||||
context.BotServer.send = function(topic, message)
|
||||
if not context.BotServer._websocket then
|
||||
return context.error("BotServer is not initialized")
|
||||
end
|
||||
context.BotServer._websocket.send({type="message", topic=topic, message=message})
|
||||
end
|
||||
local context = G.botContext
|
||||
|
||||
context.BotServer = {}
|
||||
context.BotServer.url = "ws://bot.otclient.ovh:8000/"
|
||||
context.BotServer.timeout = 3
|
||||
context.BotServer.ping = 0
|
||||
context.BotServer._callbacks = {}
|
||||
context.BotServer._lastMessageId = 0
|
||||
context.BotServer._wasConnected = true -- show first warning
|
||||
|
||||
context.BotServer.init = function(name, channel)
|
||||
if not channel or not name or channel:len() < 1 or name:len() < 1 then
|
||||
return context.error("Invalid params for BotServer.init")
|
||||
end
|
||||
if context.BotServer._websocket then
|
||||
return context.error("BotServer is already initialized")
|
||||
end
|
||||
context.BotServer._websocket = HTTP.WebSocketJSON(context.BotServer.url, {
|
||||
onMessage = function(message, socketId)
|
||||
if not context._websockets[socketId] then
|
||||
return g_http.cancel(socketId)
|
||||
end
|
||||
if not context.BotServer._websocket or context.BotServer._websocket.id ~= socketId then
|
||||
return g_http.cancel(socketId)
|
||||
end
|
||||
context.BotServer._wasConnected = true
|
||||
if message["type"] == "ping" then
|
||||
context.BotServer.ping = message["ping"]
|
||||
return context.BotServer._websocket.send({type="ping"})
|
||||
end
|
||||
if message["type"] == "message" then
|
||||
context.BotServer._lastMessageId = message["id"]
|
||||
local topics = context.BotServer._callbacks[message["topic"]]
|
||||
if topics then
|
||||
for i=1,#topics do
|
||||
topics[i](message["name"], message["message"], message["topic"])
|
||||
end
|
||||
end
|
||||
topics = context.BotServer._callbacks["*"]
|
||||
if topics then
|
||||
for i=1,#topics do
|
||||
topics[i](message["name"], message["message"], message["topic"])
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
end,
|
||||
onClose = function(message, socketId)
|
||||
if not context._websockets[socketId] then
|
||||
return
|
||||
end
|
||||
context._websockets[socketId] = nil
|
||||
if not context.BotServer._websocket or context.BotServer._websocket.id ~= socketId then
|
||||
return
|
||||
end
|
||||
if context.BotServer._wasConnected then
|
||||
context.warn("BotServer disconnected")
|
||||
end
|
||||
context.BotServer._wasConnected = false
|
||||
context.BotServer._websocket = nil
|
||||
context.BotServer.ping = 0
|
||||
context.BotServer.init(name, channel)
|
||||
end
|
||||
}, context.BotServer.timeout)
|
||||
context._websockets[context.BotServer._websocket.id] = 1
|
||||
context.BotServer._websocket.send({type="init", name=name, channel=channel, lastMessage=context.BotServer._lastMessageId})
|
||||
end
|
||||
|
||||
context.BotServer.terminate = function()
|
||||
if context.BotServer._websocket then
|
||||
context.BotServer._websocket:close()
|
||||
context.BotServer._websocket = nil
|
||||
end
|
||||
end
|
||||
|
||||
context.BotServer.listen = function(topic, callback) -- callback = function(name, message, topic) -- message is parsed json = table
|
||||
if not context.BotServer._websocket then
|
||||
return context.error("BotServer is not initialized")
|
||||
end
|
||||
if not context.BotServer._callbacks[topic] then
|
||||
context.BotServer._callbacks[topic] = {}
|
||||
end
|
||||
table.insert(context.BotServer._callbacks[topic], callback)
|
||||
end
|
||||
|
||||
context.BotServer.send = function(topic, message)
|
||||
if not context.BotServer._websocket then
|
||||
return context.error("BotServer is not initialized")
|
||||
end
|
||||
context.BotServer._websocket.send({type="message", topic=topic, message=message})
|
||||
end
|
||||
|
@@ -1,31 +1,31 @@
|
||||
local context = G.botContext
|
||||
|
||||
context.getSoundChannel = function()
|
||||
if not g_sounds then
|
||||
return
|
||||
end
|
||||
return g_sounds.getChannel(SoundChannels.Bot)
|
||||
end
|
||||
|
||||
context.playSound = function(file)
|
||||
local botSoundChannel = context.getSoundChannel()
|
||||
if not botSoundChannel then
|
||||
return
|
||||
end
|
||||
botSoundChannel:setEnabled(true)
|
||||
botSoundChannel:stop(0)
|
||||
botSoundChannel:play(file, 0, 1.0)
|
||||
return botSoundChannel
|
||||
end
|
||||
|
||||
context.stopSound = function()
|
||||
local botSoundChannel = context.getSoundChannel()
|
||||
if not botSoundChannel then
|
||||
return
|
||||
end
|
||||
botSoundChannel:stop()
|
||||
end
|
||||
|
||||
context.playAlarm = function()
|
||||
return context.playSound("/sounds/alarm.ogg")
|
||||
end
|
||||
local context = G.botContext
|
||||
|
||||
context.getSoundChannel = function()
|
||||
if not g_sounds then
|
||||
return
|
||||
end
|
||||
return g_sounds.getChannel(SoundChannels.Bot)
|
||||
end
|
||||
|
||||
context.playSound = function(file)
|
||||
local botSoundChannel = context.getSoundChannel()
|
||||
if not botSoundChannel then
|
||||
return
|
||||
end
|
||||
botSoundChannel:setEnabled(true)
|
||||
botSoundChannel:stop(0)
|
||||
botSoundChannel:play(file, 0, 1.0)
|
||||
return botSoundChannel
|
||||
end
|
||||
|
||||
context.stopSound = function()
|
||||
local botSoundChannel = context.getSoundChannel()
|
||||
if not botSoundChannel then
|
||||
return
|
||||
end
|
||||
botSoundChannel:stop()
|
||||
end
|
||||
|
||||
context.playAlarm = function()
|
||||
return context.playSound("/sounds/alarm.ogg")
|
||||
end
|
||||
|
@@ -1,3 +1,3 @@
|
||||
local context = G.botContext
|
||||
|
||||
local context = G.botContext
|
||||
|
||||
context.test = function() return context.info("test") end
|
@@ -1,19 +1,19 @@
|
||||
local context = G.botContext
|
||||
|
||||
context.encode = function(data, indent) return json.encode(data, indent or 2) end
|
||||
context.decode = function(text) local status, result = pcall(function() return json.decode(text) end) if status then return result end return {} end
|
||||
|
||||
context.displayGeneralBox = function(title, message, buttons, onEnterCallback, onEscapeCallback)
|
||||
local box = displayGeneralBox(title, message, buttons, onEnterCallback, onEscapeCallback)
|
||||
box.botWidget = true
|
||||
return box
|
||||
end
|
||||
|
||||
context.doScreenshot = function(filename)
|
||||
g_app.doScreenshot(filename)
|
||||
end
|
||||
context.screenshot = context.doScreenshot
|
||||
|
||||
context.getVersion = function()
|
||||
return g_app.getVersion()
|
||||
local context = G.botContext
|
||||
|
||||
context.encode = function(data, indent) return json.encode(data, indent or 2) end
|
||||
context.decode = function(text) local status, result = pcall(function() return json.decode(text) end) if status then return result end return {} end
|
||||
|
||||
context.displayGeneralBox = function(title, message, buttons, onEnterCallback, onEscapeCallback)
|
||||
local box = displayGeneralBox(title, message, buttons, onEnterCallback, onEscapeCallback)
|
||||
box.botWidget = true
|
||||
return box
|
||||
end
|
||||
|
||||
context.doScreenshot = function(filename)
|
||||
g_app.doScreenshot(filename)
|
||||
end
|
||||
context.screenshot = context.doScreenshot
|
||||
|
||||
context.getVersion = function()
|
||||
return g_app.getVersion()
|
||||
end
|
@@ -1,24 +1,24 @@
|
||||
local context = G.botContext
|
||||
if type(context.UI) ~= "table" then
|
||||
context.UI = {}
|
||||
end
|
||||
local UI = context.UI
|
||||
|
||||
UI.createWidget = function(name, parent)
|
||||
if parent == nil then
|
||||
parent = context.panel
|
||||
end
|
||||
local widget = g_ui.createWidget(name, parent)
|
||||
widget.botWidget = true
|
||||
return widget
|
||||
end
|
||||
|
||||
UI.createWindow = function(name)
|
||||
local widget = g_ui.createWidget(name, g_ui.getRootWidget())
|
||||
widget.botWidget = true
|
||||
widget:show()
|
||||
widget:raise()
|
||||
widget:focus()
|
||||
return widget
|
||||
end
|
||||
|
||||
local context = G.botContext
|
||||
if type(context.UI) ~= "table" then
|
||||
context.UI = {}
|
||||
end
|
||||
local UI = context.UI
|
||||
|
||||
UI.createWidget = function(name, parent)
|
||||
if parent == nil then
|
||||
parent = context.panel
|
||||
end
|
||||
local widget = g_ui.createWidget(name, parent)
|
||||
widget.botWidget = true
|
||||
return widget
|
||||
end
|
||||
|
||||
UI.createWindow = function(name)
|
||||
local widget = g_ui.createWidget(name, g_ui.getRootWidget())
|
||||
widget.botWidget = true
|
||||
widget:show()
|
||||
widget:raise()
|
||||
widget:focus()
|
||||
return widget
|
||||
end
|
||||
|
||||
|
@@ -1,273 +1,273 @@
|
||||
local context = G.botContext
|
||||
if type(context.UI) ~= "table" then
|
||||
context.UI = {}
|
||||
end
|
||||
local UI = context.UI
|
||||
|
||||
UI.Button = function(text, callback, parent)
|
||||
local widget = UI.createWidget("BotButton", parent)
|
||||
widget:setText(text)
|
||||
widget.onClick = callback
|
||||
return widget
|
||||
end
|
||||
|
||||
|
||||
UI.Config = function(parent)
|
||||
return UI.createWidget("BotConfig", parent)
|
||||
end
|
||||
|
||||
-- call :setItems(table) to set items, call :getItems() to get them
|
||||
-- unique if true, won't allow duplicates
|
||||
-- callback (can be nil) gets table with new item list, eg: {{id=2160, count=1}, {id=268, count=100}, {id=269, count=20}}
|
||||
UI.Container = function(callback, unique, parent, widget)
|
||||
if not widget then
|
||||
widget = UI.createWidget("BotContainer", parent)
|
||||
end
|
||||
|
||||
local oldItems = {}
|
||||
|
||||
local updateItems = function()
|
||||
local items = widget:getItems()
|
||||
|
||||
-- callback part
|
||||
local somethingNew = (#items ~= #oldItems)
|
||||
for i, item in ipairs(items) do
|
||||
if type(oldItems[i]) ~= "table" then
|
||||
somethingNew = true
|
||||
break
|
||||
end
|
||||
if oldItems[i].id ~= item.id or oldItems[i].count ~= item.count then
|
||||
somethingNew = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if somethingNew then
|
||||
oldItems = items
|
||||
callback(widget, items)
|
||||
end
|
||||
|
||||
widget:setItems(items)
|
||||
end
|
||||
|
||||
widget.setItems = function(self, items)
|
||||
if type(self) == 'table' then
|
||||
items = self
|
||||
end
|
||||
local itemsToShow = math.max(10, #items + 2)
|
||||
if itemsToShow % 5 ~= 0 then
|
||||
itemsToShow = itemsToShow + 5 - itemsToShow % 5
|
||||
end
|
||||
widget.items:destroyChildren()
|
||||
for i = 1, itemsToShow do
|
||||
local widget = g_ui.createWidget("BotItem", widget.items)
|
||||
if type(items[i]) == 'number' then
|
||||
items[i] = {id=items[i], count=1}
|
||||
end
|
||||
if type(items[i]) == 'table' then
|
||||
widget:setItem(Item.create(items[i].id, items[i].count))
|
||||
end
|
||||
end
|
||||
oldItems = items
|
||||
for i, child in ipairs(widget.items:getChildren()) do
|
||||
child.onItemChange = updateItems
|
||||
end
|
||||
end
|
||||
|
||||
widget.getItems = function()
|
||||
local items = {}
|
||||
local duplicates = {}
|
||||
for i, child in ipairs(widget.items:getChildren()) do
|
||||
if child:getItemId() >= 100 then
|
||||
if not duplicates[child:getItemId()] or not unique then
|
||||
table.insert(items, {id=child:getItemId(), count=child:getItemCountOrSubType()})
|
||||
duplicates[child:getItemId()] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
return items
|
||||
end
|
||||
|
||||
widget:setItems({})
|
||||
|
||||
return widget
|
||||
end
|
||||
|
||||
UI.DualScrollPanel = function(params, callback, parent) -- callback = function(widget, newParams)
|
||||
--[[ params:
|
||||
on - bool,
|
||||
text - string,
|
||||
title - string,
|
||||
min - number,
|
||||
max - number,
|
||||
]]
|
||||
params.title = params.title or "title"
|
||||
params.text = params.text or ""
|
||||
params.min = params.min or 20
|
||||
params.max = params.max or 80
|
||||
|
||||
local widget = UI.createWidget('DualScrollPanel', parent)
|
||||
|
||||
widget.title:setOn(params.on)
|
||||
widget.title.onClick = function()
|
||||
params.on = not params.on
|
||||
widget.title:setOn(params.on)
|
||||
if callback then
|
||||
callback(widget, params)
|
||||
end
|
||||
end
|
||||
|
||||
widget.text:setText(params.text or "")
|
||||
widget.text.onTextChange = function(widget, text)
|
||||
params.text = text
|
||||
if callback then
|
||||
callback(widget, params)
|
||||
end
|
||||
end
|
||||
|
||||
local update = function(dontSignal)
|
||||
widget.title:setText("" .. params.min .. "% <= " .. params.title .. " <= " .. params.max .. "%")
|
||||
if callback and not dontSignal then
|
||||
callback(widget, params)
|
||||
end
|
||||
end
|
||||
|
||||
widget.scroll1:setValue(params.min)
|
||||
widget.scroll2:setValue(params.max)
|
||||
|
||||
widget.scroll1.onValueChange = function(scroll, value)
|
||||
params.min = value
|
||||
update()
|
||||
end
|
||||
widget.scroll2.onValueChange = function(scroll, value)
|
||||
params.max = value
|
||||
update()
|
||||
end
|
||||
update(true)
|
||||
end
|
||||
|
||||
UI.DualScrollItemPanel = function(params, callback, parent) -- callback = function(widget, newParams)
|
||||
--[[ params:
|
||||
on - bool,
|
||||
item - number,
|
||||
subType - number,
|
||||
title - string,
|
||||
min - number,
|
||||
max - number,
|
||||
]]
|
||||
params.title = params.title or "title"
|
||||
params.item = params.item or 0
|
||||
params.subType = params.subType or 0
|
||||
params.min = params.min or 20
|
||||
params.max = params.max or 80
|
||||
|
||||
local widget = UI.createWidget('DualScrollItemPanel', parent)
|
||||
|
||||
widget.title:setOn(params.on)
|
||||
widget.title.onClick = function()
|
||||
params.on = not params.on
|
||||
widget.title:setOn(params.on)
|
||||
if callback then
|
||||
callback(widget, params)
|
||||
end
|
||||
end
|
||||
|
||||
widget.item:setItem(Item.create(params.item, params.subType))
|
||||
widget.item.onItemChange = function()
|
||||
params.item = widget.item:getItemId()
|
||||
params.subType = widget.item:getItemSubType()
|
||||
if callback then
|
||||
callback(widget, params)
|
||||
end
|
||||
end
|
||||
|
||||
local update = function(dontSignal)
|
||||
widget.title:setText("" .. params.min .. "% <= " .. params.title .. " <= " .. params.max .. "%")
|
||||
if callback and not dontSignal then
|
||||
callback(widget, params)
|
||||
end
|
||||
end
|
||||
|
||||
widget.scroll1:setValue(params.min)
|
||||
widget.scroll2:setValue(params.max)
|
||||
|
||||
widget.scroll1.onValueChange = function(scroll, value)
|
||||
params.min = value
|
||||
update()
|
||||
end
|
||||
widget.scroll2.onValueChange = function(scroll, value)
|
||||
params.max = value
|
||||
update()
|
||||
end
|
||||
update(true)
|
||||
end
|
||||
|
||||
UI.Label = function(text, parent)
|
||||
local label = UI.createWidget('BotLabel', parent)
|
||||
label:setText(text)
|
||||
return label
|
||||
end
|
||||
|
||||
UI.Separator = function(parent)
|
||||
local separator = UI.createWidget('BotSeparator', parent)
|
||||
return separator
|
||||
end
|
||||
|
||||
UI.TextEdit = function(text, callback, parent)
|
||||
local widget = UI.createWidget('BotTextEdit', parent)
|
||||
widget.onTextChange = callback
|
||||
widget:setText(text)
|
||||
return widget
|
||||
end
|
||||
|
||||
UI.TwoItemsAndSlotPanel = function(params, callback, parent)
|
||||
--[[ params:
|
||||
on - bool,
|
||||
title - string,
|
||||
item1 - number,
|
||||
item2 - number,
|
||||
slot - number,
|
||||
]]
|
||||
params.title = params.title or "title"
|
||||
params.item1 = params.item1 or 0
|
||||
params.item2 = params.item2 or 0
|
||||
params.slot = params.slot or 1
|
||||
|
||||
local widget = UI.createWidget("TwoItemsAndSlotPanel", parent)
|
||||
|
||||
widget.title:setText(params.title)
|
||||
widget.title:setOn(params.on)
|
||||
widget.title.onClick = function()
|
||||
params.on = not params.on
|
||||
widget.title:setOn(params.on)
|
||||
if callback then
|
||||
callback(widget, params)
|
||||
end
|
||||
end
|
||||
|
||||
widget.slot:setCurrentIndex(params.slot)
|
||||
widget.slot.onOptionChange = function()
|
||||
params.slot = widget.slot.currentIndex
|
||||
if callback then
|
||||
callback(widget, params)
|
||||
end
|
||||
end
|
||||
|
||||
widget.item1:setItemId(params.item1)
|
||||
widget.item1.onItemChange = function()
|
||||
params.item1 = widget.item1:getItemId()
|
||||
if callback then
|
||||
callback(widget, params)
|
||||
end
|
||||
end
|
||||
|
||||
widget.item2:setItemId(params.item2)
|
||||
widget.item2.onItemChange = function()
|
||||
params.item2 = widget.item2:getItemId()
|
||||
if callback then
|
||||
callback(widget, params)
|
||||
end
|
||||
end
|
||||
|
||||
return widget
|
||||
end
|
||||
local context = G.botContext
|
||||
if type(context.UI) ~= "table" then
|
||||
context.UI = {}
|
||||
end
|
||||
local UI = context.UI
|
||||
|
||||
UI.Button = function(text, callback, parent)
|
||||
local widget = UI.createWidget("BotButton", parent)
|
||||
widget:setText(text)
|
||||
widget.onClick = callback
|
||||
return widget
|
||||
end
|
||||
|
||||
|
||||
UI.Config = function(parent)
|
||||
return UI.createWidget("BotConfig", parent)
|
||||
end
|
||||
|
||||
-- call :setItems(table) to set items, call :getItems() to get them
|
||||
-- unique if true, won't allow duplicates
|
||||
-- callback (can be nil) gets table with new item list, eg: {{id=2160, count=1}, {id=268, count=100}, {id=269, count=20}}
|
||||
UI.Container = function(callback, unique, parent, widget)
|
||||
if not widget then
|
||||
widget = UI.createWidget("BotContainer", parent)
|
||||
end
|
||||
|
||||
local oldItems = {}
|
||||
|
||||
local updateItems = function()
|
||||
local items = widget:getItems()
|
||||
|
||||
-- callback part
|
||||
local somethingNew = (#items ~= #oldItems)
|
||||
for i, item in ipairs(items) do
|
||||
if type(oldItems[i]) ~= "table" then
|
||||
somethingNew = true
|
||||
break
|
||||
end
|
||||
if oldItems[i].id ~= item.id or oldItems[i].count ~= item.count then
|
||||
somethingNew = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if somethingNew then
|
||||
oldItems = items
|
||||
callback(widget, items)
|
||||
end
|
||||
|
||||
widget:setItems(items)
|
||||
end
|
||||
|
||||
widget.setItems = function(self, items)
|
||||
if type(self) == 'table' then
|
||||
items = self
|
||||
end
|
||||
local itemsToShow = math.max(10, #items + 2)
|
||||
if itemsToShow % 5 ~= 0 then
|
||||
itemsToShow = itemsToShow + 5 - itemsToShow % 5
|
||||
end
|
||||
widget.items:destroyChildren()
|
||||
for i = 1, itemsToShow do
|
||||
local widget = g_ui.createWidget("BotItem", widget.items)
|
||||
if type(items[i]) == 'number' then
|
||||
items[i] = {id=items[i], count=1}
|
||||
end
|
||||
if type(items[i]) == 'table' then
|
||||
widget:setItem(Item.create(items[i].id, items[i].count))
|
||||
end
|
||||
end
|
||||
oldItems = items
|
||||
for i, child in ipairs(widget.items:getChildren()) do
|
||||
child.onItemChange = updateItems
|
||||
end
|
||||
end
|
||||
|
||||
widget.getItems = function()
|
||||
local items = {}
|
||||
local duplicates = {}
|
||||
for i, child in ipairs(widget.items:getChildren()) do
|
||||
if child:getItemId() >= 100 then
|
||||
if not duplicates[child:getItemId()] or not unique then
|
||||
table.insert(items, {id=child:getItemId(), count=child:getItemCountOrSubType()})
|
||||
duplicates[child:getItemId()] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
return items
|
||||
end
|
||||
|
||||
widget:setItems({})
|
||||
|
||||
return widget
|
||||
end
|
||||
|
||||
UI.DualScrollPanel = function(params, callback, parent) -- callback = function(widget, newParams)
|
||||
--[[ params:
|
||||
on - bool,
|
||||
text - string,
|
||||
title - string,
|
||||
min - number,
|
||||
max - number,
|
||||
]]
|
||||
params.title = params.title or "title"
|
||||
params.text = params.text or ""
|
||||
params.min = params.min or 20
|
||||
params.max = params.max or 80
|
||||
|
||||
local widget = UI.createWidget('DualScrollPanel', parent)
|
||||
|
||||
widget.title:setOn(params.on)
|
||||
widget.title.onClick = function()
|
||||
params.on = not params.on
|
||||
widget.title:setOn(params.on)
|
||||
if callback then
|
||||
callback(widget, params)
|
||||
end
|
||||
end
|
||||
|
||||
widget.text:setText(params.text or "")
|
||||
widget.text.onTextChange = function(widget, text)
|
||||
params.text = text
|
||||
if callback then
|
||||
callback(widget, params)
|
||||
end
|
||||
end
|
||||
|
||||
local update = function(dontSignal)
|
||||
widget.title:setText("" .. params.min .. "% <= " .. params.title .. " <= " .. params.max .. "%")
|
||||
if callback and not dontSignal then
|
||||
callback(widget, params)
|
||||
end
|
||||
end
|
||||
|
||||
widget.scroll1:setValue(params.min)
|
||||
widget.scroll2:setValue(params.max)
|
||||
|
||||
widget.scroll1.onValueChange = function(scroll, value)
|
||||
params.min = value
|
||||
update()
|
||||
end
|
||||
widget.scroll2.onValueChange = function(scroll, value)
|
||||
params.max = value
|
||||
update()
|
||||
end
|
||||
update(true)
|
||||
end
|
||||
|
||||
UI.DualScrollItemPanel = function(params, callback, parent) -- callback = function(widget, newParams)
|
||||
--[[ params:
|
||||
on - bool,
|
||||
item - number,
|
||||
subType - number,
|
||||
title - string,
|
||||
min - number,
|
||||
max - number,
|
||||
]]
|
||||
params.title = params.title or "title"
|
||||
params.item = params.item or 0
|
||||
params.subType = params.subType or 0
|
||||
params.min = params.min or 20
|
||||
params.max = params.max or 80
|
||||
|
||||
local widget = UI.createWidget('DualScrollItemPanel', parent)
|
||||
|
||||
widget.title:setOn(params.on)
|
||||
widget.title.onClick = function()
|
||||
params.on = not params.on
|
||||
widget.title:setOn(params.on)
|
||||
if callback then
|
||||
callback(widget, params)
|
||||
end
|
||||
end
|
||||
|
||||
widget.item:setItem(Item.create(params.item, params.subType))
|
||||
widget.item.onItemChange = function()
|
||||
params.item = widget.item:getItemId()
|
||||
params.subType = widget.item:getItemSubType()
|
||||
if callback then
|
||||
callback(widget, params)
|
||||
end
|
||||
end
|
||||
|
||||
local update = function(dontSignal)
|
||||
widget.title:setText("" .. params.min .. "% <= " .. params.title .. " <= " .. params.max .. "%")
|
||||
if callback and not dontSignal then
|
||||
callback(widget, params)
|
||||
end
|
||||
end
|
||||
|
||||
widget.scroll1:setValue(params.min)
|
||||
widget.scroll2:setValue(params.max)
|
||||
|
||||
widget.scroll1.onValueChange = function(scroll, value)
|
||||
params.min = value
|
||||
update()
|
||||
end
|
||||
widget.scroll2.onValueChange = function(scroll, value)
|
||||
params.max = value
|
||||
update()
|
||||
end
|
||||
update(true)
|
||||
end
|
||||
|
||||
UI.Label = function(text, parent)
|
||||
local label = UI.createWidget('BotLabel', parent)
|
||||
label:setText(text)
|
||||
return label
|
||||
end
|
||||
|
||||
UI.Separator = function(parent)
|
||||
local separator = UI.createWidget('BotSeparator', parent)
|
||||
return separator
|
||||
end
|
||||
|
||||
UI.TextEdit = function(text, callback, parent)
|
||||
local widget = UI.createWidget('BotTextEdit', parent)
|
||||
widget.onTextChange = callback
|
||||
widget:setText(text)
|
||||
return widget
|
||||
end
|
||||
|
||||
UI.TwoItemsAndSlotPanel = function(params, callback, parent)
|
||||
--[[ params:
|
||||
on - bool,
|
||||
title - string,
|
||||
item1 - number,
|
||||
item2 - number,
|
||||
slot - number,
|
||||
]]
|
||||
params.title = params.title or "title"
|
||||
params.item1 = params.item1 or 0
|
||||
params.item2 = params.item2 or 0
|
||||
params.slot = params.slot or 1
|
||||
|
||||
local widget = UI.createWidget("TwoItemsAndSlotPanel", parent)
|
||||
|
||||
widget.title:setText(params.title)
|
||||
widget.title:setOn(params.on)
|
||||
widget.title.onClick = function()
|
||||
params.on = not params.on
|
||||
widget.title:setOn(params.on)
|
||||
if callback then
|
||||
callback(widget, params)
|
||||
end
|
||||
end
|
||||
|
||||
widget.slot:setCurrentIndex(params.slot)
|
||||
widget.slot.onOptionChange = function()
|
||||
params.slot = widget.slot.currentIndex
|
||||
if callback then
|
||||
callback(widget, params)
|
||||
end
|
||||
end
|
||||
|
||||
widget.item1:setItemId(params.item1)
|
||||
widget.item1.onItemChange = function()
|
||||
params.item1 = widget.item1:getItemId()
|
||||
if callback then
|
||||
callback(widget, params)
|
||||
end
|
||||
end
|
||||
|
||||
widget.item2:setItemId(params.item2)
|
||||
widget.item2.onItemChange = function()
|
||||
params.item2 = widget.item2:getItemId()
|
||||
if callback then
|
||||
callback(widget, params)
|
||||
end
|
||||
end
|
||||
|
||||
return widget
|
||||
end
|
||||
|
@@ -1,135 +1,135 @@
|
||||
local context = G.botContext
|
||||
|
||||
-- DO NOT USE THIS CODE.
|
||||
-- IT'S ONLY HERE FOR BACKWARD COMPATIBILITY, MAY BE REMOVED IN THE FUTURE
|
||||
|
||||
context.createWidget = function(name, parent)
|
||||
if parent == nil then
|
||||
parent = context.panel
|
||||
end
|
||||
g_ui.createWidget(name, parent)
|
||||
end
|
||||
|
||||
context.setupUI = function(otml, parent)
|
||||
if parent == nil then
|
||||
parent = context.panel
|
||||
end
|
||||
local widget = g_ui.loadUIFromString(otml, parent)
|
||||
widget.botWidget = true
|
||||
return widget
|
||||
end
|
||||
|
||||
context.importStyle = function(otml)
|
||||
if type(otml) ~= "string" then
|
||||
return error("Invalid parameter for importStyle, should be string")
|
||||
end
|
||||
if otml:find(".otui") and not otml:find("\n") then
|
||||
return g_ui.importStyle(context.configDir .. "/" .. otml)
|
||||
end
|
||||
return g_ui.importStyleFromString(otml)
|
||||
end
|
||||
|
||||
context.addTab = function(name)
|
||||
local tab = context.tabs:getTab(name)
|
||||
if tab then -- return existing tab
|
||||
return tab.tabPanel.content
|
||||
end
|
||||
|
||||
local smallTabs = #(context.tabs.tabs) >= 5
|
||||
local newTab = context.tabs:addTab(name, g_ui.createWidget('BotPanel')).tabPanel.content
|
||||
context.tabs:setOn(true)
|
||||
if smallTabs then
|
||||
for k,tab in pairs(context.tabs.tabs) do
|
||||
tab:setFont('small-9px')
|
||||
end
|
||||
end
|
||||
|
||||
return newTab
|
||||
end
|
||||
context.getTab = context.addTab
|
||||
|
||||
context.setDefaultTab = function(name)
|
||||
local tab = context.addTab(name)
|
||||
context.panel = tab
|
||||
end
|
||||
|
||||
context.addSwitch = function(id, text, onClickCallback, parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
local switch = g_ui.createWidget('BotSwitch', parent)
|
||||
switch:setId(id)
|
||||
switch:setText(text)
|
||||
switch.onClick = onClickCallback
|
||||
return switch
|
||||
end
|
||||
|
||||
context.addButton = function(id, text, onClickCallback, parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
local button = g_ui.createWidget('BotButton', parent)
|
||||
button:setId(id)
|
||||
button:setText(text)
|
||||
button.onClick = onClickCallback
|
||||
return button
|
||||
end
|
||||
|
||||
context.addLabel = function(id, text, parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
local label = g_ui.createWidget('BotLabel', parent)
|
||||
label:setId(id)
|
||||
label:setText(text)
|
||||
return label
|
||||
end
|
||||
|
||||
context.addTextEdit = function(id, text, onTextChangeCallback, parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
local widget = g_ui.createWidget('BotTextEdit', parent)
|
||||
widget:setId(id)
|
||||
widget.onTextChange = onTextChangeCallback
|
||||
widget:setText(text)
|
||||
return widget
|
||||
end
|
||||
|
||||
context.addSeparator = function(id, parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
local separator = g_ui.createWidget('BotSeparator', parent)
|
||||
separator:setId(id)
|
||||
return separator
|
||||
end
|
||||
|
||||
context._addMacroSwitch = function(name, keys, parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
local text = name
|
||||
if keys:len() > 0 then
|
||||
text = name .. " [" .. keys .. "]"
|
||||
end
|
||||
local switch = context.addSwitch("macro_" .. #context._macros, text, function(widget)
|
||||
context.storage._macros[name] = not context.storage._macros[name]
|
||||
widget:setOn(context.storage._macros[name])
|
||||
end, parent)
|
||||
switch:setOn(context.storage._macros[name])
|
||||
return switch
|
||||
end
|
||||
|
||||
context._addHotkeySwitch = function(name, keys, parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
local text = name
|
||||
if keys:len() > 0 then
|
||||
text = name .. " [" .. keys .. "]"
|
||||
end
|
||||
local switch = context.addSwitch("hotkey_" .. #context._hotkeys, text, nil, parent)
|
||||
switch:setOn(false)
|
||||
return switch
|
||||
local context = G.botContext
|
||||
|
||||
-- DO NOT USE THIS CODE.
|
||||
-- IT'S ONLY HERE FOR BACKWARD COMPATIBILITY, MAY BE REMOVED IN THE FUTURE
|
||||
|
||||
context.createWidget = function(name, parent)
|
||||
if parent == nil then
|
||||
parent = context.panel
|
||||
end
|
||||
g_ui.createWidget(name, parent)
|
||||
end
|
||||
|
||||
context.setupUI = function(otml, parent)
|
||||
if parent == nil then
|
||||
parent = context.panel
|
||||
end
|
||||
local widget = g_ui.loadUIFromString(otml, parent)
|
||||
widget.botWidget = true
|
||||
return widget
|
||||
end
|
||||
|
||||
context.importStyle = function(otml)
|
||||
if type(otml) ~= "string" then
|
||||
return error("Invalid parameter for importStyle, should be string")
|
||||
end
|
||||
if otml:find(".otui") and not otml:find("\n") then
|
||||
return g_ui.importStyle(context.configDir .. "/" .. otml)
|
||||
end
|
||||
return g_ui.importStyleFromString(otml)
|
||||
end
|
||||
|
||||
context.addTab = function(name)
|
||||
local tab = context.tabs:getTab(name)
|
||||
if tab then -- return existing tab
|
||||
return tab.tabPanel.content
|
||||
end
|
||||
|
||||
local smallTabs = #(context.tabs.tabs) >= 5
|
||||
local newTab = context.tabs:addTab(name, g_ui.createWidget('BotPanel')).tabPanel.content
|
||||
context.tabs:setOn(true)
|
||||
if smallTabs then
|
||||
for k,tab in pairs(context.tabs.tabs) do
|
||||
tab:setFont('small-9px')
|
||||
end
|
||||
end
|
||||
|
||||
return newTab
|
||||
end
|
||||
context.getTab = context.addTab
|
||||
|
||||
context.setDefaultTab = function(name)
|
||||
local tab = context.addTab(name)
|
||||
context.panel = tab
|
||||
end
|
||||
|
||||
context.addSwitch = function(id, text, onClickCallback, parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
local switch = g_ui.createWidget('BotSwitch', parent)
|
||||
switch:setId(id)
|
||||
switch:setText(text)
|
||||
switch.onClick = onClickCallback
|
||||
return switch
|
||||
end
|
||||
|
||||
context.addButton = function(id, text, onClickCallback, parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
local button = g_ui.createWidget('BotButton', parent)
|
||||
button:setId(id)
|
||||
button:setText(text)
|
||||
button.onClick = onClickCallback
|
||||
return button
|
||||
end
|
||||
|
||||
context.addLabel = function(id, text, parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
local label = g_ui.createWidget('BotLabel', parent)
|
||||
label:setId(id)
|
||||
label:setText(text)
|
||||
return label
|
||||
end
|
||||
|
||||
context.addTextEdit = function(id, text, onTextChangeCallback, parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
local widget = g_ui.createWidget('BotTextEdit', parent)
|
||||
widget:setId(id)
|
||||
widget.onTextChange = onTextChangeCallback
|
||||
widget:setText(text)
|
||||
return widget
|
||||
end
|
||||
|
||||
context.addSeparator = function(id, parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
local separator = g_ui.createWidget('BotSeparator', parent)
|
||||
separator:setId(id)
|
||||
return separator
|
||||
end
|
||||
|
||||
context._addMacroSwitch = function(name, keys, parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
local text = name
|
||||
if keys:len() > 0 then
|
||||
text = name .. " [" .. keys .. "]"
|
||||
end
|
||||
local switch = context.addSwitch("macro_" .. #context._macros, text, function(widget)
|
||||
context.storage._macros[name] = not context.storage._macros[name]
|
||||
widget:setOn(context.storage._macros[name])
|
||||
end, parent)
|
||||
switch:setOn(context.storage._macros[name])
|
||||
return switch
|
||||
end
|
||||
|
||||
context._addHotkeySwitch = function(name, keys, parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
local text = name
|
||||
if keys:len() > 0 then
|
||||
text = name .. " [" .. keys .. "]"
|
||||
end
|
||||
local switch = context.addSwitch("hotkey_" .. #context._hotkeys, text, nil, parent)
|
||||
switch:setOn(false)
|
||||
return switch
|
||||
end
|
@@ -1,49 +1,49 @@
|
||||
local context = G.botContext
|
||||
if type(context.UI) ~= "table" then
|
||||
context.UI = {}
|
||||
end
|
||||
local UI = context.UI
|
||||
|
||||
UI.EditorWindow = function(text, options, callback)
|
||||
--[[
|
||||
Available options:
|
||||
title = text
|
||||
description = text
|
||||
multiline = true / false
|
||||
width = number
|
||||
validation = text (regex)
|
||||
examples = {{name, text}, {name, text}}
|
||||
]]--
|
||||
local window = modules.client_textedit.edit(text, options, callback)
|
||||
window.botWidget = true
|
||||
return window
|
||||
end
|
||||
|
||||
UI.SinglelineEditorWindow = function(text, options, callback)
|
||||
options = options or {}
|
||||
options.multiline = false
|
||||
return UI.EditorWindow(text, options, callback)
|
||||
end
|
||||
|
||||
UI.MultilineEditorWindow = function(text, options, callback)
|
||||
options = options or {}
|
||||
options.multiline = true
|
||||
return UI.EditorWindow(text, options, callback)
|
||||
end
|
||||
|
||||
UI.ConfirmationWindow = function(title, question, callback)
|
||||
local window = nil
|
||||
local onConfirm = function()
|
||||
window:destroy()
|
||||
callback()
|
||||
end
|
||||
local closeWindow = function()
|
||||
window:destroy()
|
||||
end
|
||||
window = context.displayGeneralBox(title, question, {
|
||||
{ text=tr('Yes'), callback=onConfirm },
|
||||
{ text=tr('No'), callback=closeWindow },
|
||||
anchor=AnchorHorizontalCenter}, onConfirm, closeWindow)
|
||||
window.botWidget = true
|
||||
return window
|
||||
local context = G.botContext
|
||||
if type(context.UI) ~= "table" then
|
||||
context.UI = {}
|
||||
end
|
||||
local UI = context.UI
|
||||
|
||||
UI.EditorWindow = function(text, options, callback)
|
||||
--[[
|
||||
Available options:
|
||||
title = text
|
||||
description = text
|
||||
multiline = true / false
|
||||
width = number
|
||||
validation = text (regex)
|
||||
examples = {{name, text}, {name, text}}
|
||||
]]--
|
||||
local window = modules.client_textedit.edit(text, options, callback)
|
||||
window.botWidget = true
|
||||
return window
|
||||
end
|
||||
|
||||
UI.SinglelineEditorWindow = function(text, options, callback)
|
||||
options = options or {}
|
||||
options.multiline = false
|
||||
return UI.EditorWindow(text, options, callback)
|
||||
end
|
||||
|
||||
UI.MultilineEditorWindow = function(text, options, callback)
|
||||
options = options or {}
|
||||
options.multiline = true
|
||||
return UI.EditorWindow(text, options, callback)
|
||||
end
|
||||
|
||||
UI.ConfirmationWindow = function(title, question, callback)
|
||||
local window = nil
|
||||
local onConfirm = function()
|
||||
window:destroy()
|
||||
callback()
|
||||
end
|
||||
local closeWindow = function()
|
||||
window:destroy()
|
||||
end
|
||||
window = context.displayGeneralBox(title, question, {
|
||||
{ text=tr('Yes'), callback=onConfirm },
|
||||
{ text=tr('No'), callback=closeWindow },
|
||||
anchor=AnchorHorizontalCenter}, onConfirm, closeWindow)
|
||||
window.botWidget = true
|
||||
return window
|
||||
end
|
File diff suppressed because it is too large
Load Diff
@@ -1,57 +1,57 @@
|
||||
local context = G.botContext
|
||||
local Panels = context.Panels
|
||||
|
||||
Panels.Turning = function(parent)
|
||||
context.macro(1000, "Turning / AntiIdle", nil, function()
|
||||
context.turn(math.random(1, 4))
|
||||
end, parent)
|
||||
end
|
||||
Panels.AntiIdle = Panels.Turning
|
||||
|
||||
Panels.AttackSpell = function(parent)
|
||||
context.macro(500, "Auto attack spell", nil, function()
|
||||
local target = g_game.getAttackingCreature()
|
||||
if target and context.getCreatureById(target:getId()) and context.storage.autoAttackText:len() > 0 then
|
||||
if context.saySpell(context.storage.autoAttackText, 1000) then
|
||||
context.delay(1000)
|
||||
end
|
||||
end
|
||||
end, parent)
|
||||
context.addTextEdit("autoAttackText", context.storage.autoAttackText or "exori vis", function(widget, text)
|
||||
context.storage.autoAttackText = text
|
||||
end, parent)
|
||||
end
|
||||
|
||||
Panels.AttackItem = function(parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
|
||||
local panelName = "attackItem"
|
||||
local ui = g_ui.createWidget("ItemAndButtonPanel", parent)
|
||||
ui:setId(panelName)
|
||||
|
||||
ui.title:setText("Auto attack item")
|
||||
|
||||
if not context.storage.attackItem then
|
||||
context.storage.attackItem = {}
|
||||
end
|
||||
|
||||
ui.title:setOn(context.storage.attackItem.enabled)
|
||||
ui.title.onClick = function(widget)
|
||||
context.storage.attackItem.enabled = not context.storage.attackItem.enabled
|
||||
widget:setOn(context.storage.attackItem.enabled)
|
||||
end
|
||||
|
||||
ui.item.onItemChange = function(widget)
|
||||
context.storage.attackItem.item = widget:getItemId()
|
||||
end
|
||||
ui.item:setItemId(context.storage.attackItem.item or 3155)
|
||||
|
||||
context.macro(500, function()
|
||||
local target = g_game.getAttackingCreature()
|
||||
if context.storage.attackItem.enabled and target and context.getCreatureById(target:getId()) and context.storage.attackItem.item and context.storage.attackItem.item >= 100 then
|
||||
context.useWith(context.storage.attackItem.item, target)
|
||||
end
|
||||
end)
|
||||
end
|
||||
local context = G.botContext
|
||||
local Panels = context.Panels
|
||||
|
||||
Panels.Turning = function(parent)
|
||||
context.macro(1000, "Turning / AntiIdle", nil, function()
|
||||
context.turn(math.random(1, 4))
|
||||
end, parent)
|
||||
end
|
||||
Panels.AntiIdle = Panels.Turning
|
||||
|
||||
Panels.AttackSpell = function(parent)
|
||||
context.macro(500, "Auto attack spell", nil, function()
|
||||
local target = g_game.getAttackingCreature()
|
||||
if target and context.getCreatureById(target:getId()) and context.storage.autoAttackText:len() > 0 then
|
||||
if context.saySpell(context.storage.autoAttackText, 1000) then
|
||||
context.delay(1000)
|
||||
end
|
||||
end
|
||||
end, parent)
|
||||
context.addTextEdit("autoAttackText", context.storage.autoAttackText or "exori vis", function(widget, text)
|
||||
context.storage.autoAttackText = text
|
||||
end, parent)
|
||||
end
|
||||
|
||||
Panels.AttackItem = function(parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
|
||||
local panelName = "attackItem"
|
||||
local ui = g_ui.createWidget("ItemAndButtonPanel", parent)
|
||||
ui:setId(panelName)
|
||||
|
||||
ui.title:setText("Auto attack item")
|
||||
|
||||
if not context.storage.attackItem then
|
||||
context.storage.attackItem = {}
|
||||
end
|
||||
|
||||
ui.title:setOn(context.storage.attackItem.enabled)
|
||||
ui.title.onClick = function(widget)
|
||||
context.storage.attackItem.enabled = not context.storage.attackItem.enabled
|
||||
widget:setOn(context.storage.attackItem.enabled)
|
||||
end
|
||||
|
||||
ui.item.onItemChange = function(widget)
|
||||
context.storage.attackItem.item = widget:getItemId()
|
||||
end
|
||||
ui.item:setItemId(context.storage.attackItem.item or 3155)
|
||||
|
||||
context.macro(500, function()
|
||||
local target = g_game.getAttackingCreature()
|
||||
if context.storage.attackItem.enabled and target and context.getCreatureById(target:getId()) and context.storage.attackItem.item and context.storage.attackItem.item >= 100 then
|
||||
context.useWith(context.storage.attackItem.item, target)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
@@ -1,346 +1,346 @@
|
||||
local context = G.botContext
|
||||
local Panels = context.Panels
|
||||
|
||||
Panels.Haste = function(parent)
|
||||
context.macro(500, "Auto Haste", nil, function()
|
||||
if not context.hasHaste() and context.storage.autoHasteText:len() > 0 then
|
||||
if context.saySpell(context.storage.autoHasteText, 2500) then
|
||||
context.delay(5000)
|
||||
end
|
||||
end
|
||||
end, parent)
|
||||
context.addTextEdit("autoHasteText", context.storage.autoHasteText or "utani hur", function(widget, text)
|
||||
context.storage.autoHasteText = text
|
||||
end, parent)
|
||||
end
|
||||
|
||||
Panels.ManaShield = function(parent)
|
||||
local lastManaShield = 0
|
||||
context.macro(100, "Auto Mana Shield", nil, function()
|
||||
if not context.hasManaShield() or context.now > lastManaShield + 90000 then
|
||||
if context.saySpell("utamo vita", 200) then
|
||||
lastManaShield = context.now
|
||||
end
|
||||
end
|
||||
end, parent)
|
||||
end
|
||||
|
||||
Panels.AntiParalyze = function(parent)
|
||||
context.macro(100, "Anti Paralyze", nil, function()
|
||||
if context.isParalyzed() and context.storage.autoAntiParalyzeText:len() > 0 then
|
||||
context.saySpell(context.storage.autoAntiParalyzeText, 750)
|
||||
end
|
||||
end, parent)
|
||||
context.addTextEdit("autoAntiParalyzeText", context.storage.autoAntiParalyzeText or "utani hur", function(widget, text)
|
||||
context.storage.autoAntiParalyzeText = text
|
||||
end, parent)
|
||||
end
|
||||
|
||||
|
||||
Panels.Health = function(parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
|
||||
local panelName = "autoHealthPanel"
|
||||
local panelId = 1
|
||||
while parent:getChildById(panelName .. panelId) do
|
||||
panelId = panelId + 1
|
||||
end
|
||||
panelName = panelName .. panelId
|
||||
|
||||
local ui = g_ui.createWidget("DualScrollPanel", parent)
|
||||
ui:setId(panelName)
|
||||
|
||||
if not context.storage[panelName] then
|
||||
context.storage[panelName] = {
|
||||
item = 266,
|
||||
min = 20,
|
||||
max = 80,
|
||||
text = "exura"
|
||||
}
|
||||
end
|
||||
|
||||
ui.title:setOn(context.storage[panelName].enabled)
|
||||
ui.title.onClick = function(widget)
|
||||
context.storage[panelName].enabled = not context.storage[panelName].enabled
|
||||
widget:setOn(context.storage[panelName].enabled)
|
||||
end
|
||||
|
||||
ui.text.onTextChange = function(widget, text)
|
||||
context.storage[panelName].text = text
|
||||
end
|
||||
ui.text:setText(context.storage[panelName].text or "exura")
|
||||
|
||||
local updateText = function()
|
||||
ui.title:setText("" .. context.storage[panelName].min .. "% <= hp <= " .. context.storage[panelName].max .. "%")
|
||||
end
|
||||
|
||||
ui.scroll1.onValueChange = function(scroll, value)
|
||||
context.storage[panelName].min = value
|
||||
updateText()
|
||||
end
|
||||
ui.scroll2.onValueChange = function(scroll, value)
|
||||
context.storage[panelName].max = value
|
||||
updateText()
|
||||
end
|
||||
|
||||
ui.scroll1:setValue(context.storage[panelName].min)
|
||||
ui.scroll2:setValue(context.storage[panelName].max)
|
||||
|
||||
context.macro(25, function()
|
||||
if context.storage[panelName].enabled and context.storage[panelName].text:len() > 0 and context.storage[panelName].min <= context.hppercent() and context.hppercent() <= context.storage[panelName].max then
|
||||
if context.saySpell(context.storage[panelName].text, 500) then
|
||||
context.delay(200)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
Panels.HealthItem = function(parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
|
||||
local panelName = "autoHealthItemPanel"
|
||||
local panelId = 1
|
||||
while parent:getChildById(panelName .. panelId) do
|
||||
panelId = panelId + 1
|
||||
end
|
||||
panelName = panelName .. panelId
|
||||
|
||||
local ui = g_ui.createWidget("DualScrollItemPanel", parent)
|
||||
ui:setId(panelName)
|
||||
|
||||
if not context.storage[panelName] then
|
||||
context.storage[panelName] = {
|
||||
item = 266,
|
||||
min = 0,
|
||||
max = 60
|
||||
}
|
||||
end
|
||||
|
||||
ui.title:setOn(context.storage[panelName].enabled)
|
||||
ui.title.onClick = function(widget)
|
||||
context.storage[panelName].enabled = not context.storage[panelName].enabled
|
||||
widget:setOn(context.storage[panelName].enabled)
|
||||
end
|
||||
|
||||
ui.item.onItemChange = function(widget)
|
||||
context.storage[panelName].item = widget:getItemId()
|
||||
end
|
||||
ui.item:setItemId(context.storage[panelName].item)
|
||||
|
||||
local updateText = function()
|
||||
ui.title:setText("" .. (context.storage[panelName].min or "") .. "% <= hp <= " .. (context.storage[panelName].max or "") .. "%")
|
||||
end
|
||||
|
||||
ui.scroll1.onValueChange = function(scroll, value)
|
||||
context.storage[panelName].min = value
|
||||
updateText()
|
||||
end
|
||||
ui.scroll2.onValueChange = function(scroll, value)
|
||||
context.storage[panelName].max = value
|
||||
updateText()
|
||||
end
|
||||
|
||||
ui.scroll1:setValue(context.storage[panelName].min)
|
||||
ui.scroll2:setValue(context.storage[panelName].max)
|
||||
|
||||
context.macro(25, function()
|
||||
if context.storage[panelName].enabled and context.storage[panelName].item >= 100 and context.storage[panelName].min <= context.hppercent() and context.hppercent() <= context.storage[panelName].max then
|
||||
if context.useRune(context.storage[panelName].item, context.player, 500) then
|
||||
context.delay(300)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
Panels.Mana = function(parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
|
||||
local panelName = "autoManaItemPanel"
|
||||
local panelId = 1
|
||||
while parent:getChildById(panelName .. panelId) do
|
||||
panelId = panelId + 1
|
||||
end
|
||||
panelName = panelName .. panelId
|
||||
|
||||
local ui = g_ui.createWidget("DualScrollItemPanel", parent)
|
||||
ui:setId(panelName)
|
||||
|
||||
if not context.storage[panelName] then
|
||||
context.storage[panelName] = {
|
||||
item = 268,
|
||||
min = 0,
|
||||
max = 60
|
||||
}
|
||||
end
|
||||
|
||||
ui.title:setOn(context.storage[panelName].enabled)
|
||||
ui.title.onClick = function(widget)
|
||||
context.storage[panelName].enabled = not context.storage[panelName].enabled
|
||||
widget:setOn(context.storage[panelName].enabled)
|
||||
end
|
||||
|
||||
ui.item.onItemChange = function(widget)
|
||||
context.storage[panelName].item = widget:getItemId()
|
||||
end
|
||||
ui.item:setItemId(context.storage[panelName].item)
|
||||
|
||||
local updateText = function()
|
||||
ui.title:setText("" .. (context.storage[panelName].min or "") .. "% <= mana <= " .. (context.storage[panelName].max or "") .. "%")
|
||||
end
|
||||
|
||||
ui.scroll1.onValueChange = function(scroll, value)
|
||||
context.storage[panelName].min = value
|
||||
updateText()
|
||||
end
|
||||
ui.scroll2.onValueChange = function(scroll, value)
|
||||
context.storage[panelName].max = value
|
||||
updateText()
|
||||
end
|
||||
|
||||
ui.scroll1:setValue(context.storage[panelName].min)
|
||||
ui.scroll2:setValue(context.storage[panelName].max)
|
||||
|
||||
context.macro(25, function()
|
||||
if context.storage[panelName].enabled and context.storage[panelName].item >= 100 and context.storage[panelName].min <= context.manapercent() and context.manapercent() <= context.storage[panelName].max then
|
||||
if context.useRune(context.storage[panelName].item, context.player, 500) then
|
||||
context.delay(300)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
Panels.ManaItem = Panels.Mana
|
||||
|
||||
Panels.Equip = function(parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
|
||||
local panelName = "autoEquipItem"
|
||||
local panelId = 1
|
||||
while parent:getChildById(panelName .. panelId) do
|
||||
panelId = panelId + 1
|
||||
end
|
||||
panelName = panelName .. panelId
|
||||
|
||||
local ui = g_ui.createWidget("TwoItemsAndSlotPanel", parent)
|
||||
ui:setId(panelName)
|
||||
|
||||
if not context.storage[panelName] then
|
||||
context.storage[panelName] = {}
|
||||
if panelId == 1 then
|
||||
context.storage[panelName].item1 = 3052
|
||||
context.storage[panelName].item2 = 3089
|
||||
context.storage[panelName].slot = 9
|
||||
end
|
||||
end
|
||||
|
||||
ui.title:setText("Auto equip")
|
||||
ui.title:setOn(context.storage[panelName].enabled)
|
||||
ui.title.onClick = function(widget)
|
||||
context.storage[panelName].enabled = not context.storage[panelName].enabled
|
||||
widget:setOn(context.storage[panelName].enabled)
|
||||
end
|
||||
|
||||
ui.item1:setItemId(context.storage[panelName].item1 or 0)
|
||||
ui.item1.onItemChange = function(widget)
|
||||
context.storage[panelName].item1 = widget:getItemId()
|
||||
end
|
||||
|
||||
ui.item2:setItemId(context.storage[panelName].item2 or 0)
|
||||
ui.item2.onItemChange = function(widget)
|
||||
context.storage[panelName].item2 = widget:getItemId()
|
||||
end
|
||||
|
||||
if not context.storage[panelName].slot then
|
||||
context.storage[panelName].slot = 1
|
||||
end
|
||||
ui.slot:setCurrentIndex(context.storage[panelName].slot)
|
||||
ui.slot.onOptionChange = function(widget)
|
||||
context.storage[panelName].slot = widget.currentIndex
|
||||
end
|
||||
|
||||
context.macro(250, function()
|
||||
if context.storage[panelName].enabled and context.storage[panelName].slot > 0 then
|
||||
local item1 = context.storage[panelName].item1 or 0
|
||||
local item2 = context.storage[panelName].item2 or 0
|
||||
if item1 < 100 and item2 < 100 then
|
||||
return
|
||||
end
|
||||
local slotItem = context.getSlot(context.storage[panelName].slot)
|
||||
if slotItem and (slotItem:getId() == item1 or slotItem:getId() == item2) then
|
||||
return
|
||||
end
|
||||
local newItem = context.findItem(context.storage[panelName].item1)
|
||||
if not newItem then
|
||||
newItem = context.findItem(context.storage[panelName].item2)
|
||||
if not newItem then
|
||||
return
|
||||
end
|
||||
end
|
||||
g_game.move(newItem, {x=65535, y=context.storage[panelName].slot, z=0})
|
||||
context.delay(1000)
|
||||
end
|
||||
end)
|
||||
end
|
||||
Panels.AutoEquip = Panels.Equip
|
||||
|
||||
Panels.Eating = function(parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
|
||||
local panelName = "autoEatingPanel"
|
||||
local panelId = 1
|
||||
while parent:getChildById(panelName .. panelId) do
|
||||
panelId = panelId + 1
|
||||
end
|
||||
panelName = panelName .. panelId
|
||||
|
||||
local ui = g_ui.createWidget("ItemsPanel", parent)
|
||||
ui:setId(panelName)
|
||||
|
||||
if not context.storage[panelName] then
|
||||
context.storage[panelName] = {}
|
||||
end
|
||||
|
||||
ui.title:setText("Auto eating")
|
||||
ui.title:setOn(context.storage[panelName].enabled)
|
||||
ui.title.onClick = function(widget)
|
||||
context.storage[panelName].enabled = not context.storage[panelName].enabled
|
||||
widget:setOn(context.storage[panelName].enabled)
|
||||
end
|
||||
|
||||
if type(context.storage[panelName].items) ~= 'table' then
|
||||
context.storage[panelName].items = {3725, 0, 0, 0, 0}
|
||||
end
|
||||
|
||||
for i=1,5 do
|
||||
ui.items:getChildByIndex(i).onItemChange = function(widget)
|
||||
context.storage[panelName].items[i] = widget:getItemId()
|
||||
end
|
||||
ui.items:getChildByIndex(i):setItemId(context.storage[panelName].items[i])
|
||||
end
|
||||
|
||||
context.macro(15000, function()
|
||||
if not context.storage[panelName].enabled then
|
||||
return
|
||||
end
|
||||
local candidates = {}
|
||||
for i, item in pairs(context.storage[panelName].items) do
|
||||
if item >= 100 then
|
||||
table.insert(candidates, item)
|
||||
end
|
||||
end
|
||||
if #candidates == 0 then
|
||||
return
|
||||
end
|
||||
context.use(candidates[math.random(1, #candidates)])
|
||||
end)
|
||||
end
|
||||
|
||||
local context = G.botContext
|
||||
local Panels = context.Panels
|
||||
|
||||
Panels.Haste = function(parent)
|
||||
context.macro(500, "Auto Haste", nil, function()
|
||||
if not context.hasHaste() and context.storage.autoHasteText:len() > 0 then
|
||||
if context.saySpell(context.storage.autoHasteText, 2500) then
|
||||
context.delay(5000)
|
||||
end
|
||||
end
|
||||
end, parent)
|
||||
context.addTextEdit("autoHasteText", context.storage.autoHasteText or "utani hur", function(widget, text)
|
||||
context.storage.autoHasteText = text
|
||||
end, parent)
|
||||
end
|
||||
|
||||
Panels.ManaShield = function(parent)
|
||||
local lastManaShield = 0
|
||||
context.macro(100, "Auto Mana Shield", nil, function()
|
||||
if not context.hasManaShield() or context.now > lastManaShield + 90000 then
|
||||
if context.saySpell("utamo vita", 200) then
|
||||
lastManaShield = context.now
|
||||
end
|
||||
end
|
||||
end, parent)
|
||||
end
|
||||
|
||||
Panels.AntiParalyze = function(parent)
|
||||
context.macro(100, "Anti Paralyze", nil, function()
|
||||
if context.isParalyzed() and context.storage.autoAntiParalyzeText:len() > 0 then
|
||||
context.saySpell(context.storage.autoAntiParalyzeText, 750)
|
||||
end
|
||||
end, parent)
|
||||
context.addTextEdit("autoAntiParalyzeText", context.storage.autoAntiParalyzeText or "utani hur", function(widget, text)
|
||||
context.storage.autoAntiParalyzeText = text
|
||||
end, parent)
|
||||
end
|
||||
|
||||
|
||||
Panels.Health = function(parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
|
||||
local panelName = "autoHealthPanel"
|
||||
local panelId = 1
|
||||
while parent:getChildById(panelName .. panelId) do
|
||||
panelId = panelId + 1
|
||||
end
|
||||
panelName = panelName .. panelId
|
||||
|
||||
local ui = g_ui.createWidget("DualScrollPanel", parent)
|
||||
ui:setId(panelName)
|
||||
|
||||
if not context.storage[panelName] then
|
||||
context.storage[panelName] = {
|
||||
item = 266,
|
||||
min = 20,
|
||||
max = 80,
|
||||
text = "exura"
|
||||
}
|
||||
end
|
||||
|
||||
ui.title:setOn(context.storage[panelName].enabled)
|
||||
ui.title.onClick = function(widget)
|
||||
context.storage[panelName].enabled = not context.storage[panelName].enabled
|
||||
widget:setOn(context.storage[panelName].enabled)
|
||||
end
|
||||
|
||||
ui.text.onTextChange = function(widget, text)
|
||||
context.storage[panelName].text = text
|
||||
end
|
||||
ui.text:setText(context.storage[panelName].text or "exura")
|
||||
|
||||
local updateText = function()
|
||||
ui.title:setText("" .. context.storage[panelName].min .. "% <= hp <= " .. context.storage[panelName].max .. "%")
|
||||
end
|
||||
|
||||
ui.scroll1.onValueChange = function(scroll, value)
|
||||
context.storage[panelName].min = value
|
||||
updateText()
|
||||
end
|
||||
ui.scroll2.onValueChange = function(scroll, value)
|
||||
context.storage[panelName].max = value
|
||||
updateText()
|
||||
end
|
||||
|
||||
ui.scroll1:setValue(context.storage[panelName].min)
|
||||
ui.scroll2:setValue(context.storage[panelName].max)
|
||||
|
||||
context.macro(25, function()
|
||||
if context.storage[panelName].enabled and context.storage[panelName].text:len() > 0 and context.storage[panelName].min <= context.hppercent() and context.hppercent() <= context.storage[panelName].max then
|
||||
if context.saySpell(context.storage[panelName].text, 500) then
|
||||
context.delay(200)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
Panels.HealthItem = function(parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
|
||||
local panelName = "autoHealthItemPanel"
|
||||
local panelId = 1
|
||||
while parent:getChildById(panelName .. panelId) do
|
||||
panelId = panelId + 1
|
||||
end
|
||||
panelName = panelName .. panelId
|
||||
|
||||
local ui = g_ui.createWidget("DualScrollItemPanel", parent)
|
||||
ui:setId(panelName)
|
||||
|
||||
if not context.storage[panelName] then
|
||||
context.storage[panelName] = {
|
||||
item = 266,
|
||||
min = 0,
|
||||
max = 60
|
||||
}
|
||||
end
|
||||
|
||||
ui.title:setOn(context.storage[panelName].enabled)
|
||||
ui.title.onClick = function(widget)
|
||||
context.storage[panelName].enabled = not context.storage[panelName].enabled
|
||||
widget:setOn(context.storage[panelName].enabled)
|
||||
end
|
||||
|
||||
ui.item.onItemChange = function(widget)
|
||||
context.storage[panelName].item = widget:getItemId()
|
||||
end
|
||||
ui.item:setItemId(context.storage[panelName].item)
|
||||
|
||||
local updateText = function()
|
||||
ui.title:setText("" .. (context.storage[panelName].min or "") .. "% <= hp <= " .. (context.storage[panelName].max or "") .. "%")
|
||||
end
|
||||
|
||||
ui.scroll1.onValueChange = function(scroll, value)
|
||||
context.storage[panelName].min = value
|
||||
updateText()
|
||||
end
|
||||
ui.scroll2.onValueChange = function(scroll, value)
|
||||
context.storage[panelName].max = value
|
||||
updateText()
|
||||
end
|
||||
|
||||
ui.scroll1:setValue(context.storage[panelName].min)
|
||||
ui.scroll2:setValue(context.storage[panelName].max)
|
||||
|
||||
context.macro(25, function()
|
||||
if context.storage[panelName].enabled and context.storage[panelName].item >= 100 and context.storage[panelName].min <= context.hppercent() and context.hppercent() <= context.storage[panelName].max then
|
||||
if context.useRune(context.storage[panelName].item, context.player, 500) then
|
||||
context.delay(300)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
Panels.Mana = function(parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
|
||||
local panelName = "autoManaItemPanel"
|
||||
local panelId = 1
|
||||
while parent:getChildById(panelName .. panelId) do
|
||||
panelId = panelId + 1
|
||||
end
|
||||
panelName = panelName .. panelId
|
||||
|
||||
local ui = g_ui.createWidget("DualScrollItemPanel", parent)
|
||||
ui:setId(panelName)
|
||||
|
||||
if not context.storage[panelName] then
|
||||
context.storage[panelName] = {
|
||||
item = 268,
|
||||
min = 0,
|
||||
max = 60
|
||||
}
|
||||
end
|
||||
|
||||
ui.title:setOn(context.storage[panelName].enabled)
|
||||
ui.title.onClick = function(widget)
|
||||
context.storage[panelName].enabled = not context.storage[panelName].enabled
|
||||
widget:setOn(context.storage[panelName].enabled)
|
||||
end
|
||||
|
||||
ui.item.onItemChange = function(widget)
|
||||
context.storage[panelName].item = widget:getItemId()
|
||||
end
|
||||
ui.item:setItemId(context.storage[panelName].item)
|
||||
|
||||
local updateText = function()
|
||||
ui.title:setText("" .. (context.storage[panelName].min or "") .. "% <= mana <= " .. (context.storage[panelName].max or "") .. "%")
|
||||
end
|
||||
|
||||
ui.scroll1.onValueChange = function(scroll, value)
|
||||
context.storage[panelName].min = value
|
||||
updateText()
|
||||
end
|
||||
ui.scroll2.onValueChange = function(scroll, value)
|
||||
context.storage[panelName].max = value
|
||||
updateText()
|
||||
end
|
||||
|
||||
ui.scroll1:setValue(context.storage[panelName].min)
|
||||
ui.scroll2:setValue(context.storage[panelName].max)
|
||||
|
||||
context.macro(25, function()
|
||||
if context.storage[panelName].enabled and context.storage[panelName].item >= 100 and context.storage[panelName].min <= context.manapercent() and context.manapercent() <= context.storage[panelName].max then
|
||||
if context.useRune(context.storage[panelName].item, context.player, 500) then
|
||||
context.delay(300)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
Panels.ManaItem = Panels.Mana
|
||||
|
||||
Panels.Equip = function(parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
|
||||
local panelName = "autoEquipItem"
|
||||
local panelId = 1
|
||||
while parent:getChildById(panelName .. panelId) do
|
||||
panelId = panelId + 1
|
||||
end
|
||||
panelName = panelName .. panelId
|
||||
|
||||
local ui = g_ui.createWidget("TwoItemsAndSlotPanel", parent)
|
||||
ui:setId(panelName)
|
||||
|
||||
if not context.storage[panelName] then
|
||||
context.storage[panelName] = {}
|
||||
if panelId == 1 then
|
||||
context.storage[panelName].item1 = 3052
|
||||
context.storage[panelName].item2 = 3089
|
||||
context.storage[panelName].slot = 9
|
||||
end
|
||||
end
|
||||
|
||||
ui.title:setText("Auto equip")
|
||||
ui.title:setOn(context.storage[panelName].enabled)
|
||||
ui.title.onClick = function(widget)
|
||||
context.storage[panelName].enabled = not context.storage[panelName].enabled
|
||||
widget:setOn(context.storage[panelName].enabled)
|
||||
end
|
||||
|
||||
ui.item1:setItemId(context.storage[panelName].item1 or 0)
|
||||
ui.item1.onItemChange = function(widget)
|
||||
context.storage[panelName].item1 = widget:getItemId()
|
||||
end
|
||||
|
||||
ui.item2:setItemId(context.storage[panelName].item2 or 0)
|
||||
ui.item2.onItemChange = function(widget)
|
||||
context.storage[panelName].item2 = widget:getItemId()
|
||||
end
|
||||
|
||||
if not context.storage[panelName].slot then
|
||||
context.storage[panelName].slot = 1
|
||||
end
|
||||
ui.slot:setCurrentIndex(context.storage[panelName].slot)
|
||||
ui.slot.onOptionChange = function(widget)
|
||||
context.storage[panelName].slot = widget.currentIndex
|
||||
end
|
||||
|
||||
context.macro(250, function()
|
||||
if context.storage[panelName].enabled and context.storage[panelName].slot > 0 then
|
||||
local item1 = context.storage[panelName].item1 or 0
|
||||
local item2 = context.storage[panelName].item2 or 0
|
||||
if item1 < 100 and item2 < 100 then
|
||||
return
|
||||
end
|
||||
local slotItem = context.getSlot(context.storage[panelName].slot)
|
||||
if slotItem and (slotItem:getId() == item1 or slotItem:getId() == item2) then
|
||||
return
|
||||
end
|
||||
local newItem = context.findItem(context.storage[panelName].item1)
|
||||
if not newItem then
|
||||
newItem = context.findItem(context.storage[panelName].item2)
|
||||
if not newItem then
|
||||
return
|
||||
end
|
||||
end
|
||||
g_game.move(newItem, {x=65535, y=context.storage[panelName].slot, z=0})
|
||||
context.delay(1000)
|
||||
end
|
||||
end)
|
||||
end
|
||||
Panels.AutoEquip = Panels.Equip
|
||||
|
||||
Panels.Eating = function(parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
|
||||
local panelName = "autoEatingPanel"
|
||||
local panelId = 1
|
||||
while parent:getChildById(panelName .. panelId) do
|
||||
panelId = panelId + 1
|
||||
end
|
||||
panelName = panelName .. panelId
|
||||
|
||||
local ui = g_ui.createWidget("ItemsPanel", parent)
|
||||
ui:setId(panelName)
|
||||
|
||||
if not context.storage[panelName] then
|
||||
context.storage[panelName] = {}
|
||||
end
|
||||
|
||||
ui.title:setText("Auto eating")
|
||||
ui.title:setOn(context.storage[panelName].enabled)
|
||||
ui.title.onClick = function(widget)
|
||||
context.storage[panelName].enabled = not context.storage[panelName].enabled
|
||||
widget:setOn(context.storage[panelName].enabled)
|
||||
end
|
||||
|
||||
if type(context.storage[panelName].items) ~= 'table' then
|
||||
context.storage[panelName].items = {3725, 0, 0, 0, 0}
|
||||
end
|
||||
|
||||
for i=1,5 do
|
||||
ui.items:getChildByIndex(i).onItemChange = function(widget)
|
||||
context.storage[panelName].items[i] = widget:getItemId()
|
||||
end
|
||||
ui.items:getChildByIndex(i):setItemId(context.storage[panelName].items[i])
|
||||
end
|
||||
|
||||
context.macro(15000, function()
|
||||
if not context.storage[panelName].enabled then
|
||||
return
|
||||
end
|
||||
local candidates = {}
|
||||
for i, item in pairs(context.storage[panelName].items) do
|
||||
if item >= 100 then
|
||||
table.insert(candidates, item)
|
||||
end
|
||||
end
|
||||
if #candidates == 0 then
|
||||
return
|
||||
end
|
||||
context.use(candidates[math.random(1, #candidates)])
|
||||
end)
|
||||
end
|
||||
|
||||
|
@@ -1,431 +1,431 @@
|
||||
local context = G.botContext
|
||||
local Panels = context.Panels
|
||||
|
||||
Panels.Looting = function(parent)
|
||||
local ui = context.setupUI([[
|
||||
Panel
|
||||
id: looting
|
||||
height: 180
|
||||
|
||||
BotLabel
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
text: Looting
|
||||
|
||||
ComboBox
|
||||
id: config
|
||||
anchors.top: prev.bottom
|
||||
anchors.left: parent.left
|
||||
margin-top: 5
|
||||
text-offset: 3 0
|
||||
width: 130
|
||||
|
||||
Button
|
||||
id: enableButton
|
||||
anchors.top: prev.top
|
||||
anchors.left: prev.right
|
||||
anchors.right: parent.right
|
||||
margin-left: 5
|
||||
|
||||
Button
|
||||
margin-top: 1
|
||||
id: add
|
||||
anchors.top: prev.bottom
|
||||
anchors.left: parent.left
|
||||
text: Add
|
||||
width: 60
|
||||
height: 17
|
||||
|
||||
Button
|
||||
id: edit
|
||||
anchors.top: prev.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: Edit
|
||||
width: 60
|
||||
height: 17
|
||||
|
||||
Button
|
||||
id: remove
|
||||
anchors.top: prev.top
|
||||
anchors.right: parent.right
|
||||
text: Remove
|
||||
width: 60
|
||||
height: 17
|
||||
|
||||
ScrollablePanel
|
||||
id: items
|
||||
anchors.top: prev.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
vertical-scrollbar: scrollBar
|
||||
margin-right: 5
|
||||
margin-top: 2
|
||||
height: 70
|
||||
layout:
|
||||
type: grid
|
||||
cell-size: 34 34
|
||||
flow: true
|
||||
|
||||
BotSmallScrollBar
|
||||
id: scrollBar
|
||||
anchors.top: prev.top
|
||||
anchors.bottom: prev.bottom
|
||||
anchors.right: parent.right
|
||||
step: 10
|
||||
pixels-scroll: true
|
||||
|
||||
BotLabel
|
||||
anchors.top: prev.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
margin-top: 4
|
||||
text: Loot Containers
|
||||
|
||||
ItemsRow
|
||||
id: containers
|
||||
anchors.top: prev.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 33
|
||||
margin-top: 2
|
||||
|
||||
]], parent)
|
||||
|
||||
local lootContainers = { ui.containers.item1, ui.containers.item2, ui.containers.item3, ui.containers.item4, ui.containers.item5 }
|
||||
|
||||
if type(context.storage.looting) ~= "table" then
|
||||
context.storage.looting = {}
|
||||
end
|
||||
if type(context.storage.looting.configs) ~= "table" then
|
||||
context.storage.looting.configs = {}
|
||||
end
|
||||
|
||||
local getConfigName = function(config)
|
||||
local matches = regexMatch(config, [[name:\s*([^\n]*)$]])
|
||||
if matches[1] and matches[1][2] then
|
||||
return matches[1][2]:trim()
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local items = {}
|
||||
local itemsByKey = {}
|
||||
local containers = {}
|
||||
local commands = {}
|
||||
local refreshConfig = nil -- declared later
|
||||
|
||||
local createNewConfig = function(focusedWidget)
|
||||
if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then
|
||||
return
|
||||
end
|
||||
|
||||
local tmpItems = {}
|
||||
local tmpContainers = {}
|
||||
local focusIndex = 0
|
||||
|
||||
local newConfig = ""
|
||||
for i, text in ipairs(commands) do
|
||||
newConfig = newConfig .. text .. "\n"
|
||||
end
|
||||
for i=1,ui.items:getChildCount() do
|
||||
local widget = ui.items:getChildByIndex(i)
|
||||
if widget and widget:getItemId() >= 100 then
|
||||
if tmpItems[widget:getItemId()] == nil then
|
||||
tmpItems[widget:getItemId()] = 1
|
||||
newConfig = newConfig .. "\n" .. widget:getItemId()
|
||||
end
|
||||
end
|
||||
if widget == focusedWidget then
|
||||
focusIndex = i
|
||||
end
|
||||
end
|
||||
for i, widget in ipairs(lootContainers) do
|
||||
if widget:getItemId() >= 100 then
|
||||
if tmpContainers[widget:getItemId()] == nil then
|
||||
tmpContainers[widget:getItemId()] = 1 -- remove duplicates
|
||||
newConfig = newConfig .. "\ncontainer:" .. widget:getItemId()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context.storage.looting.configs[context.storage.looting.activeConfig] = newConfig
|
||||
refreshConfig(focusIndex)
|
||||
end
|
||||
|
||||
local parseConfig = function(config)
|
||||
items = {}
|
||||
itemsByKey = {}
|
||||
containers = {}
|
||||
commands = {}
|
||||
local matches = regexMatch(config, [[([^:^\n^\s]+)(:?)([^\n]*)]])
|
||||
for i=1,#matches do
|
||||
local command = matches[i][2]
|
||||
local validation = (matches[i][3] == ":")
|
||||
local text = matches[i][4]
|
||||
local commandAsNumber = tonumber(command)
|
||||
local textAsNumber = tonumber(text)
|
||||
if commandAsNumber and commandAsNumber >= 100 then
|
||||
table.insert(items, commandAsNumber)
|
||||
itemsByKey[commandAsNumber] = 1
|
||||
elseif command == "container" and validation and textAsNumber and textAsNumber >= 100 then
|
||||
containers[textAsNumber] = 1
|
||||
elseif validation then
|
||||
table.insert(commands, command .. ":" .. text)
|
||||
end
|
||||
end
|
||||
|
||||
local itemsToShow = #items + 2
|
||||
if itemsToShow % 5 ~= 0 then
|
||||
itemsToShow = itemsToShow + 5 - itemsToShow % 5
|
||||
end
|
||||
if itemsToShow < 10 then
|
||||
itemsToShow = 10
|
||||
end
|
||||
|
||||
for i=1,itemsToShow do
|
||||
local widget = g_ui.createWidget("BotItem", ui.items)
|
||||
local itemId = 0
|
||||
if i <= #items then
|
||||
itemId = items[i]
|
||||
end
|
||||
widget:setItemId(itemId)
|
||||
widget.onItemChange = createNewConfig
|
||||
end
|
||||
|
||||
for i, widget in ipairs(lootContainers) do
|
||||
widget:setItemId(0)
|
||||
end
|
||||
local containerIndex = 1
|
||||
for containerId, i in pairs(containers) do
|
||||
if lootContainers[containerIndex] then
|
||||
lootContainers[containerIndex]:setItemId(containerId)
|
||||
end
|
||||
containerIndex = containerIndex + 1
|
||||
end
|
||||
for i, widget in ipairs(lootContainers) do
|
||||
widget.onItemChange = createNewConfig
|
||||
end
|
||||
end
|
||||
|
||||
local ignoreOnOptionChange = true
|
||||
refreshConfig = function(focusIndex)
|
||||
ignoreOnOptionChange = true
|
||||
if context.storage.looting.enabled then
|
||||
ui.enableButton:setText("On")
|
||||
ui.enableButton:setColor('#00AA00FF')
|
||||
else
|
||||
ui.enableButton:setText("Off")
|
||||
ui.enableButton:setColor('#FF0000FF')
|
||||
end
|
||||
|
||||
ui.config:clear()
|
||||
for i, config in ipairs(context.storage.looting.configs) do
|
||||
local name = getConfigName(config)
|
||||
if not name then
|
||||
name = "Unnamed config"
|
||||
end
|
||||
ui.config:addOption(name)
|
||||
end
|
||||
|
||||
if (not context.storage.looting.activeConfig or context.storage.looting.activeConfig == 0) and #context.storage.looting.configs > 0 then
|
||||
context.storage.looting.activeConfig = 1
|
||||
end
|
||||
|
||||
ui.items:destroyChildren()
|
||||
for i, widget in ipairs(lootContainers) do
|
||||
widget.onItemChange = nil
|
||||
widget:setItemId(0)
|
||||
widget:setItemCount(0)
|
||||
end
|
||||
|
||||
if context.storage.looting.activeConfig and context.storage.looting.configs[context.storage.looting.activeConfig] then
|
||||
ui.config:setCurrentIndex(context.storage.looting.activeConfig)
|
||||
parseConfig(context.storage.looting.configs[context.storage.looting.activeConfig])
|
||||
end
|
||||
|
||||
context.saveConfig()
|
||||
if focusIndex and focusIndex > 0 and ui.items:getChildByIndex(focusIndex) then
|
||||
ui.items:focusChild(ui.items:getChildByIndex(focusIndex))
|
||||
end
|
||||
|
||||
ignoreOnOptionChange = false
|
||||
end
|
||||
|
||||
ui.config.onOptionChange = function(widget)
|
||||
if not ignoreOnOptionChange then
|
||||
context.storage.looting.activeConfig = widget.currentIndex
|
||||
refreshConfig()
|
||||
end
|
||||
end
|
||||
ui.enableButton.onClick = function()
|
||||
if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then
|
||||
return
|
||||
end
|
||||
context.storage.looting.enabled = not context.storage.looting.enabled
|
||||
refreshConfig()
|
||||
end
|
||||
ui.add.onClick = function()
|
||||
modules.client_textedit.multilineEditor("Looting editor", "name:Config name", function(newText)
|
||||
table.insert(context.storage.looting.configs, newText)
|
||||
context.storage.looting.activeConfig = #context.storage.looting.configs
|
||||
refreshConfig()
|
||||
end)
|
||||
end
|
||||
ui.edit.onClick = function()
|
||||
if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then
|
||||
return
|
||||
end
|
||||
modules.client_textedit.multilineEditor("Looting editor", context.storage.looting.configs[context.storage.looting.activeConfig], function(newText)
|
||||
context.storage.looting.configs[context.storage.looting.activeConfig] = newText
|
||||
refreshConfig()
|
||||
end)
|
||||
end
|
||||
ui.remove.onClick = function()
|
||||
if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then
|
||||
return
|
||||
end
|
||||
local questionWindow = nil
|
||||
local closeWindow = function()
|
||||
questionWindow:destroy()
|
||||
end
|
||||
local removeConfig = function()
|
||||
closeWindow()
|
||||
if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then
|
||||
return
|
||||
end
|
||||
context.storage.looting.enabled = false
|
||||
table.remove(context.storage.looting.configs, context.storage.looting.activeConfig)
|
||||
context.storage.looting.activeConfig = 0
|
||||
refreshConfig()
|
||||
end
|
||||
questionWindow = context.displayGeneralBox(tr('Remove config'), tr('Do you want to remove current looting config?'), {
|
||||
{ text=tr('Yes'), callback=removeConfig },
|
||||
{ text=tr('No'), callback=closeWindow },
|
||||
anchor=AnchorHorizontalCenter}, removeConfig, closeWindow)
|
||||
end
|
||||
refreshConfig()
|
||||
|
||||
context.onContainerOpen(function(container, prevContainer)
|
||||
if context.storage.attacking.enabled then
|
||||
return
|
||||
end
|
||||
if prevContainer then
|
||||
container.autoLooting = prevContainer.autoLooting
|
||||
else
|
||||
container.autoLooting = true
|
||||
end
|
||||
end)
|
||||
|
||||
context.macro(200, function()
|
||||
if not context.storage.looting.enabled then
|
||||
return
|
||||
end
|
||||
local candidates = {}
|
||||
local lootContainersCandidates = {}
|
||||
for containerId, container in pairs(g_game.getContainers()) do
|
||||
local containerItem = container:getContainerItem()
|
||||
if container.autoLooting and container:getItemsCount() > 0 and (not containerItem or containers[containerItem:getId()] == nil) then
|
||||
table.insert(candidates, container)
|
||||
elseif containerItem and containers[containerItem:getId()] ~= nil then
|
||||
table.insert(lootContainersCandidates, container)
|
||||
end
|
||||
end
|
||||
if #lootContainersCandidates == 0 then
|
||||
for slot = InventorySlotFirst, InventorySlotLast do
|
||||
local item = context.getInventoryItem(slot)
|
||||
if item and item:isContainer() and containers[item:getId()] ~= nil then
|
||||
table.insert(lootContainersCandidates, item)
|
||||
end
|
||||
end
|
||||
if #lootContainersCandidates > 0 then
|
||||
-- try to open inventory backpack
|
||||
local target = lootContainersCandidates[math.random(1,#lootContainersCandidates)]
|
||||
g_game.open(target, nil)
|
||||
context.delay(200)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if #candidates == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local container = candidates[math.random(1,#candidates)]
|
||||
local nextContainers = {}
|
||||
local foundItem = nil
|
||||
for i, item in ipairs(container:getItems()) do
|
||||
if item:isContainer() then
|
||||
table.insert(nextContainers, item)
|
||||
elseif itemsByKey[item:getId()] ~= nil then
|
||||
foundItem = item
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- found item to loot
|
||||
if foundItem then
|
||||
-- find backpack for it, first backpack with same items
|
||||
for i, container in ipairs(lootContainersCandidates) do
|
||||
if container:getItemsCount() < container:getCapacity() or foundItem:isStackable() then -- has space
|
||||
for j, item in ipairs(container:getItems()) do
|
||||
if item:getId() == foundItem:getId() then
|
||||
if foundItem:isStackable() then
|
||||
if item:getCount() ~= 100 then
|
||||
g_game.move(foundItem, container:getSlotPosition(j - 1), foundItem:getCount())
|
||||
return
|
||||
end
|
||||
else
|
||||
g_game.move(foundItem, container:getSlotPosition(container:getItemsCount()), foundItem:getCount())
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- now any backpack with empty slot
|
||||
for i, container in ipairs(lootContainersCandidates) do
|
||||
if container:getItemsCount() < container:getCapacity() then -- has space
|
||||
g_game.move(foundItem, container:getSlotPosition(container:getItemsCount()), foundItem:getCount())
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- can't find backpack, try to open new
|
||||
for i, container in ipairs(lootContainersCandidates) do
|
||||
local candidates = {}
|
||||
for j, item in ipairs(container:getItems()) do
|
||||
if item:isContainer() and containers[item:getId()] ~= nil then
|
||||
table.insert(candidates, item)
|
||||
end
|
||||
end
|
||||
if #candidates > 0 then
|
||||
g_game.open(candidates[math.random(1,#candidates)], container)
|
||||
return
|
||||
end
|
||||
-- full, close it
|
||||
g_game.close(container)
|
||||
return
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- open remaining containers
|
||||
if #nextContainers == 0 then
|
||||
return
|
||||
end
|
||||
local delay = 1
|
||||
for i=2,#nextContainers do
|
||||
-- if more than 1 container, open them in new window
|
||||
context.schedule(delay, function()
|
||||
g_game.open(nextContainers[i], nil)
|
||||
end)
|
||||
delay = delay + 250
|
||||
end
|
||||
context.schedule(delay, function()
|
||||
g_game.open(nextContainers[1], container)
|
||||
end)
|
||||
context.delay(150 + delay)
|
||||
end)
|
||||
end
|
||||
|
||||
local context = G.botContext
|
||||
local Panels = context.Panels
|
||||
|
||||
Panels.Looting = function(parent)
|
||||
local ui = context.setupUI([[
|
||||
Panel
|
||||
id: looting
|
||||
height: 180
|
||||
|
||||
BotLabel
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
text: Looting
|
||||
|
||||
ComboBox
|
||||
id: config
|
||||
anchors.top: prev.bottom
|
||||
anchors.left: parent.left
|
||||
margin-top: 5
|
||||
text-offset: 3 0
|
||||
width: 130
|
||||
|
||||
Button
|
||||
id: enableButton
|
||||
anchors.top: prev.top
|
||||
anchors.left: prev.right
|
||||
anchors.right: parent.right
|
||||
margin-left: 5
|
||||
|
||||
Button
|
||||
margin-top: 1
|
||||
id: add
|
||||
anchors.top: prev.bottom
|
||||
anchors.left: parent.left
|
||||
text: Add
|
||||
width: 60
|
||||
height: 17
|
||||
|
||||
Button
|
||||
id: edit
|
||||
anchors.top: prev.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: Edit
|
||||
width: 60
|
||||
height: 17
|
||||
|
||||
Button
|
||||
id: remove
|
||||
anchors.top: prev.top
|
||||
anchors.right: parent.right
|
||||
text: Remove
|
||||
width: 60
|
||||
height: 17
|
||||
|
||||
ScrollablePanel
|
||||
id: items
|
||||
anchors.top: prev.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
vertical-scrollbar: scrollBar
|
||||
margin-right: 5
|
||||
margin-top: 2
|
||||
height: 70
|
||||
layout:
|
||||
type: grid
|
||||
cell-size: 34 34
|
||||
flow: true
|
||||
|
||||
BotSmallScrollBar
|
||||
id: scrollBar
|
||||
anchors.top: prev.top
|
||||
anchors.bottom: prev.bottom
|
||||
anchors.right: parent.right
|
||||
step: 10
|
||||
pixels-scroll: true
|
||||
|
||||
BotLabel
|
||||
anchors.top: prev.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
margin-top: 4
|
||||
text: Loot Containers
|
||||
|
||||
ItemsRow
|
||||
id: containers
|
||||
anchors.top: prev.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 33
|
||||
margin-top: 2
|
||||
|
||||
]], parent)
|
||||
|
||||
local lootContainers = { ui.containers.item1, ui.containers.item2, ui.containers.item3, ui.containers.item4, ui.containers.item5 }
|
||||
|
||||
if type(context.storage.looting) ~= "table" then
|
||||
context.storage.looting = {}
|
||||
end
|
||||
if type(context.storage.looting.configs) ~= "table" then
|
||||
context.storage.looting.configs = {}
|
||||
end
|
||||
|
||||
local getConfigName = function(config)
|
||||
local matches = regexMatch(config, [[name:\s*([^\n]*)$]])
|
||||
if matches[1] and matches[1][2] then
|
||||
return matches[1][2]:trim()
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local items = {}
|
||||
local itemsByKey = {}
|
||||
local containers = {}
|
||||
local commands = {}
|
||||
local refreshConfig = nil -- declared later
|
||||
|
||||
local createNewConfig = function(focusedWidget)
|
||||
if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then
|
||||
return
|
||||
end
|
||||
|
||||
local tmpItems = {}
|
||||
local tmpContainers = {}
|
||||
local focusIndex = 0
|
||||
|
||||
local newConfig = ""
|
||||
for i, text in ipairs(commands) do
|
||||
newConfig = newConfig .. text .. "\n"
|
||||
end
|
||||
for i=1,ui.items:getChildCount() do
|
||||
local widget = ui.items:getChildByIndex(i)
|
||||
if widget and widget:getItemId() >= 100 then
|
||||
if tmpItems[widget:getItemId()] == nil then
|
||||
tmpItems[widget:getItemId()] = 1
|
||||
newConfig = newConfig .. "\n" .. widget:getItemId()
|
||||
end
|
||||
end
|
||||
if widget == focusedWidget then
|
||||
focusIndex = i
|
||||
end
|
||||
end
|
||||
for i, widget in ipairs(lootContainers) do
|
||||
if widget:getItemId() >= 100 then
|
||||
if tmpContainers[widget:getItemId()] == nil then
|
||||
tmpContainers[widget:getItemId()] = 1 -- remove duplicates
|
||||
newConfig = newConfig .. "\ncontainer:" .. widget:getItemId()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context.storage.looting.configs[context.storage.looting.activeConfig] = newConfig
|
||||
refreshConfig(focusIndex)
|
||||
end
|
||||
|
||||
local parseConfig = function(config)
|
||||
items = {}
|
||||
itemsByKey = {}
|
||||
containers = {}
|
||||
commands = {}
|
||||
local matches = regexMatch(config, [[([^:^\n^\s]+)(:?)([^\n]*)]])
|
||||
for i=1,#matches do
|
||||
local command = matches[i][2]
|
||||
local validation = (matches[i][3] == ":")
|
||||
local text = matches[i][4]
|
||||
local commandAsNumber = tonumber(command)
|
||||
local textAsNumber = tonumber(text)
|
||||
if commandAsNumber and commandAsNumber >= 100 then
|
||||
table.insert(items, commandAsNumber)
|
||||
itemsByKey[commandAsNumber] = 1
|
||||
elseif command == "container" and validation and textAsNumber and textAsNumber >= 100 then
|
||||
containers[textAsNumber] = 1
|
||||
elseif validation then
|
||||
table.insert(commands, command .. ":" .. text)
|
||||
end
|
||||
end
|
||||
|
||||
local itemsToShow = #items + 2
|
||||
if itemsToShow % 5 ~= 0 then
|
||||
itemsToShow = itemsToShow + 5 - itemsToShow % 5
|
||||
end
|
||||
if itemsToShow < 10 then
|
||||
itemsToShow = 10
|
||||
end
|
||||
|
||||
for i=1,itemsToShow do
|
||||
local widget = g_ui.createWidget("BotItem", ui.items)
|
||||
local itemId = 0
|
||||
if i <= #items then
|
||||
itemId = items[i]
|
||||
end
|
||||
widget:setItemId(itemId)
|
||||
widget.onItemChange = createNewConfig
|
||||
end
|
||||
|
||||
for i, widget in ipairs(lootContainers) do
|
||||
widget:setItemId(0)
|
||||
end
|
||||
local containerIndex = 1
|
||||
for containerId, i in pairs(containers) do
|
||||
if lootContainers[containerIndex] then
|
||||
lootContainers[containerIndex]:setItemId(containerId)
|
||||
end
|
||||
containerIndex = containerIndex + 1
|
||||
end
|
||||
for i, widget in ipairs(lootContainers) do
|
||||
widget.onItemChange = createNewConfig
|
||||
end
|
||||
end
|
||||
|
||||
local ignoreOnOptionChange = true
|
||||
refreshConfig = function(focusIndex)
|
||||
ignoreOnOptionChange = true
|
||||
if context.storage.looting.enabled then
|
||||
ui.enableButton:setText("On")
|
||||
ui.enableButton:setColor('#00AA00FF')
|
||||
else
|
||||
ui.enableButton:setText("Off")
|
||||
ui.enableButton:setColor('#FF0000FF')
|
||||
end
|
||||
|
||||
ui.config:clear()
|
||||
for i, config in ipairs(context.storage.looting.configs) do
|
||||
local name = getConfigName(config)
|
||||
if not name then
|
||||
name = "Unnamed config"
|
||||
end
|
||||
ui.config:addOption(name)
|
||||
end
|
||||
|
||||
if (not context.storage.looting.activeConfig or context.storage.looting.activeConfig == 0) and #context.storage.looting.configs > 0 then
|
||||
context.storage.looting.activeConfig = 1
|
||||
end
|
||||
|
||||
ui.items:destroyChildren()
|
||||
for i, widget in ipairs(lootContainers) do
|
||||
widget.onItemChange = nil
|
||||
widget:setItemId(0)
|
||||
widget:setItemCount(0)
|
||||
end
|
||||
|
||||
if context.storage.looting.activeConfig and context.storage.looting.configs[context.storage.looting.activeConfig] then
|
||||
ui.config:setCurrentIndex(context.storage.looting.activeConfig)
|
||||
parseConfig(context.storage.looting.configs[context.storage.looting.activeConfig])
|
||||
end
|
||||
|
||||
context.saveConfig()
|
||||
if focusIndex and focusIndex > 0 and ui.items:getChildByIndex(focusIndex) then
|
||||
ui.items:focusChild(ui.items:getChildByIndex(focusIndex))
|
||||
end
|
||||
|
||||
ignoreOnOptionChange = false
|
||||
end
|
||||
|
||||
ui.config.onOptionChange = function(widget)
|
||||
if not ignoreOnOptionChange then
|
||||
context.storage.looting.activeConfig = widget.currentIndex
|
||||
refreshConfig()
|
||||
end
|
||||
end
|
||||
ui.enableButton.onClick = function()
|
||||
if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then
|
||||
return
|
||||
end
|
||||
context.storage.looting.enabled = not context.storage.looting.enabled
|
||||
refreshConfig()
|
||||
end
|
||||
ui.add.onClick = function()
|
||||
modules.client_textedit.multilineEditor("Looting editor", "name:Config name", function(newText)
|
||||
table.insert(context.storage.looting.configs, newText)
|
||||
context.storage.looting.activeConfig = #context.storage.looting.configs
|
||||
refreshConfig()
|
||||
end)
|
||||
end
|
||||
ui.edit.onClick = function()
|
||||
if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then
|
||||
return
|
||||
end
|
||||
modules.client_textedit.multilineEditor("Looting editor", context.storage.looting.configs[context.storage.looting.activeConfig], function(newText)
|
||||
context.storage.looting.configs[context.storage.looting.activeConfig] = newText
|
||||
refreshConfig()
|
||||
end)
|
||||
end
|
||||
ui.remove.onClick = function()
|
||||
if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then
|
||||
return
|
||||
end
|
||||
local questionWindow = nil
|
||||
local closeWindow = function()
|
||||
questionWindow:destroy()
|
||||
end
|
||||
local removeConfig = function()
|
||||
closeWindow()
|
||||
if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then
|
||||
return
|
||||
end
|
||||
context.storage.looting.enabled = false
|
||||
table.remove(context.storage.looting.configs, context.storage.looting.activeConfig)
|
||||
context.storage.looting.activeConfig = 0
|
||||
refreshConfig()
|
||||
end
|
||||
questionWindow = context.displayGeneralBox(tr('Remove config'), tr('Do you want to remove current looting config?'), {
|
||||
{ text=tr('Yes'), callback=removeConfig },
|
||||
{ text=tr('No'), callback=closeWindow },
|
||||
anchor=AnchorHorizontalCenter}, removeConfig, closeWindow)
|
||||
end
|
||||
refreshConfig()
|
||||
|
||||
context.onContainerOpen(function(container, prevContainer)
|
||||
if context.storage.attacking.enabled then
|
||||
return
|
||||
end
|
||||
if prevContainer then
|
||||
container.autoLooting = prevContainer.autoLooting
|
||||
else
|
||||
container.autoLooting = true
|
||||
end
|
||||
end)
|
||||
|
||||
context.macro(200, function()
|
||||
if not context.storage.looting.enabled then
|
||||
return
|
||||
end
|
||||
local candidates = {}
|
||||
local lootContainersCandidates = {}
|
||||
for containerId, container in pairs(g_game.getContainers()) do
|
||||
local containerItem = container:getContainerItem()
|
||||
if container.autoLooting and container:getItemsCount() > 0 and (not containerItem or containers[containerItem:getId()] == nil) then
|
||||
table.insert(candidates, container)
|
||||
elseif containerItem and containers[containerItem:getId()] ~= nil then
|
||||
table.insert(lootContainersCandidates, container)
|
||||
end
|
||||
end
|
||||
if #lootContainersCandidates == 0 then
|
||||
for slot = InventorySlotFirst, InventorySlotLast do
|
||||
local item = context.getInventoryItem(slot)
|
||||
if item and item:isContainer() and containers[item:getId()] ~= nil then
|
||||
table.insert(lootContainersCandidates, item)
|
||||
end
|
||||
end
|
||||
if #lootContainersCandidates > 0 then
|
||||
-- try to open inventory backpack
|
||||
local target = lootContainersCandidates[math.random(1,#lootContainersCandidates)]
|
||||
g_game.open(target, nil)
|
||||
context.delay(200)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if #candidates == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local container = candidates[math.random(1,#candidates)]
|
||||
local nextContainers = {}
|
||||
local foundItem = nil
|
||||
for i, item in ipairs(container:getItems()) do
|
||||
if item:isContainer() then
|
||||
table.insert(nextContainers, item)
|
||||
elseif itemsByKey[item:getId()] ~= nil then
|
||||
foundItem = item
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- found item to loot
|
||||
if foundItem then
|
||||
-- find backpack for it, first backpack with same items
|
||||
for i, container in ipairs(lootContainersCandidates) do
|
||||
if container:getItemsCount() < container:getCapacity() or foundItem:isStackable() then -- has space
|
||||
for j, item in ipairs(container:getItems()) do
|
||||
if item:getId() == foundItem:getId() then
|
||||
if foundItem:isStackable() then
|
||||
if item:getCount() ~= 100 then
|
||||
g_game.move(foundItem, container:getSlotPosition(j - 1), foundItem:getCount())
|
||||
return
|
||||
end
|
||||
else
|
||||
g_game.move(foundItem, container:getSlotPosition(container:getItemsCount()), foundItem:getCount())
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- now any backpack with empty slot
|
||||
for i, container in ipairs(lootContainersCandidates) do
|
||||
if container:getItemsCount() < container:getCapacity() then -- has space
|
||||
g_game.move(foundItem, container:getSlotPosition(container:getItemsCount()), foundItem:getCount())
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- can't find backpack, try to open new
|
||||
for i, container in ipairs(lootContainersCandidates) do
|
||||
local candidates = {}
|
||||
for j, item in ipairs(container:getItems()) do
|
||||
if item:isContainer() and containers[item:getId()] ~= nil then
|
||||
table.insert(candidates, item)
|
||||
end
|
||||
end
|
||||
if #candidates > 0 then
|
||||
g_game.open(candidates[math.random(1,#candidates)], container)
|
||||
return
|
||||
end
|
||||
-- full, close it
|
||||
g_game.close(container)
|
||||
return
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- open remaining containers
|
||||
if #nextContainers == 0 then
|
||||
return
|
||||
end
|
||||
local delay = 1
|
||||
for i=2,#nextContainers do
|
||||
-- if more than 1 container, open them in new window
|
||||
context.schedule(delay, function()
|
||||
g_game.open(nextContainers[i], nil)
|
||||
end)
|
||||
delay = delay + 250
|
||||
end
|
||||
context.schedule(delay, function()
|
||||
g_game.open(nextContainers[1], container)
|
||||
end)
|
||||
context.delay(150 + delay)
|
||||
end)
|
||||
end
|
||||
|
||||
|
@@ -1,36 +1,36 @@
|
||||
local context = G.botContext
|
||||
local Panels = context.Panels
|
||||
|
||||
Panels.TradeMessage = function(parent)
|
||||
context.macro(60000, "Send message on trade", nil, function()
|
||||
local trade = context.getChannelId("advertising")
|
||||
if not trade then
|
||||
trade = context.getChannelId("trade")
|
||||
end
|
||||
if context.storage.autoTradeMessage:len() > 0 and trade then
|
||||
context.sayChannel(trade, context.storage.autoTradeMessage)
|
||||
end
|
||||
end, parent)
|
||||
context.addTextEdit("autoTradeMessage", context.storage.autoTradeMessage or "I'm using OTClientV8 - https://github.com/OTCv8/otclientv8", function(widget, text)
|
||||
context.storage.autoTradeMessage = text
|
||||
end, parent)
|
||||
end
|
||||
|
||||
Panels.AutoStackItems = function(parent)
|
||||
context.macro(500, "Auto stacking items", nil, function()
|
||||
local containers = context.getContainers()
|
||||
for i, container in pairs(containers) do
|
||||
local toStack = {}
|
||||
for j, item in ipairs(container:getItems()) do
|
||||
if item:isStackable() and item:getCount() ~= 100 then
|
||||
local otherItem = toStack[item:getId()]
|
||||
if otherItem then
|
||||
g_game.move(item, otherItem, item:getCount())
|
||||
return
|
||||
end
|
||||
toStack[item:getId()] = container:getSlotPosition(j - 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end, parent)
|
||||
local context = G.botContext
|
||||
local Panels = context.Panels
|
||||
|
||||
Panels.TradeMessage = function(parent)
|
||||
context.macro(60000, "Send message on trade", nil, function()
|
||||
local trade = context.getChannelId("advertising")
|
||||
if not trade then
|
||||
trade = context.getChannelId("trade")
|
||||
end
|
||||
if context.storage.autoTradeMessage:len() > 0 and trade then
|
||||
context.sayChannel(trade, context.storage.autoTradeMessage)
|
||||
end
|
||||
end, parent)
|
||||
context.addTextEdit("autoTradeMessage", context.storage.autoTradeMessage or "I'm using OTClientV8 - https://github.com/OTCv8/otclientv8", function(widget, text)
|
||||
context.storage.autoTradeMessage = text
|
||||
end, parent)
|
||||
end
|
||||
|
||||
Panels.AutoStackItems = function(parent)
|
||||
context.macro(500, "Auto stacking items", nil, function()
|
||||
local containers = context.getContainers()
|
||||
for i, container in pairs(containers) do
|
||||
local toStack = {}
|
||||
for j, item in ipairs(container:getItems()) do
|
||||
if item:isStackable() and item:getCount() ~= 100 then
|
||||
local otherItem = toStack[item:getId()]
|
||||
if otherItem then
|
||||
g_game.move(item, otherItem, item:getCount())
|
||||
return
|
||||
end
|
||||
toStack[item:getId()] = container:getSlotPosition(j - 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end, parent)
|
||||
end
|
@@ -1,127 +1,127 @@
|
||||
local context = G.botContext
|
||||
local Panels = context.Panels
|
||||
|
||||
Panels.AttackLeaderTarget = function(parent)
|
||||
local toAttack = nil
|
||||
context.onMissle(function(missle)
|
||||
if not context.storage.attackLeader or context.storage.attackLeader:len() == 0 then
|
||||
return
|
||||
end
|
||||
local src = missle:getSource()
|
||||
if src.z ~= context.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]
|
||||
if c1:getName():lower() == context.storage.attackLeader:lower() then
|
||||
toAttack = toCreatures[1]
|
||||
end
|
||||
end)
|
||||
context.macro(50, "Attack leader's target", nil, function()
|
||||
if toAttack and context.storage.attackLeader:len() > 0 and toAttack ~= g_game.getAttackingCreature() then
|
||||
g_game.attack(toAttack)
|
||||
toAttack = nil
|
||||
end
|
||||
end, parent)
|
||||
context.addTextEdit("attackLeader", context.storage.attackLeader or "player name", function(widget, text)
|
||||
context.storage.attackLeader = text
|
||||
end, parent)
|
||||
end
|
||||
|
||||
|
||||
Panels.LimitFloor = function(parent)
|
||||
context.onPlayerPositionChange(function(pos)
|
||||
if context.storage.limitFloor then
|
||||
local gameMapPanel = modules.game_interface.getMapPanel()
|
||||
if gameMapPanel then
|
||||
gameMapPanel:lockVisibleFloor(pos.z)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local switch = context.addSwitch("limitFloor", "Don't show higher floors", function(widget)
|
||||
widget:setOn(not widget:isOn())
|
||||
context.storage.limitFloor = widget:isOn()
|
||||
local gameMapPanel = modules.game_interface.getMapPanel()
|
||||
if gameMapPanel then
|
||||
if context.storage.limitFloor then
|
||||
gameMapPanel:lockVisibleFloor(context.posz())
|
||||
else
|
||||
gameMapPanel:unlockVisibleFloor()
|
||||
end
|
||||
end
|
||||
end, parent)
|
||||
switch:setOn(context.storage.limitFloor)
|
||||
end
|
||||
|
||||
Panels.AntiPush = function(parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
|
||||
local panelName = "antiPushPanel"
|
||||
local ui = g_ui.createWidget("ItemsPanel", parent)
|
||||
ui:setId(panelName)
|
||||
|
||||
if not context.storage[panelName] then
|
||||
context.storage[panelName] = {}
|
||||
end
|
||||
|
||||
ui.title:setText("Anti push")
|
||||
ui.title:setOn(context.storage[panelName].enabled)
|
||||
ui.title.onClick = function(widget)
|
||||
context.storage[panelName].enabled = not context.storage[panelName].enabled
|
||||
widget:setOn(context.storage[panelName].enabled)
|
||||
end
|
||||
|
||||
if type(context.storage[panelName].items) ~= 'table' then
|
||||
context.storage[panelName].items = {3031, 3035, 0, 0, 0}
|
||||
end
|
||||
|
||||
for i=1,5 do
|
||||
ui.items:getChildByIndex(i).onItemChange = function(widget)
|
||||
context.storage[panelName].items[i] = widget:getItemId()
|
||||
end
|
||||
ui.items:getChildByIndex(i):setItemId(context.storage[panelName].items[i])
|
||||
end
|
||||
|
||||
context.macro(100, function()
|
||||
if not context.storage[panelName].enabled then
|
||||
return
|
||||
end
|
||||
local tile = g_map.getTile(context.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(context.storage[panelName].items) do
|
||||
if item >= 100 and item ~= topItem and context.findItem(item) then
|
||||
table.insert(candidates, item)
|
||||
end
|
||||
end
|
||||
if #candidates == 0 then
|
||||
return
|
||||
end
|
||||
if type(context.storage[panelName].lastItem) ~= 'number' or context.storage[panelName].lastItem > #candidates then
|
||||
context.storage[panelName].lastItem = 1
|
||||
end
|
||||
local item = context.findItem(candidates[context.storage[panelName].lastItem])
|
||||
g_game.move(item, context.player:getPosition(), 1)
|
||||
context.storage[panelName].lastItem = context.storage[panelName].lastItem + 1
|
||||
end)
|
||||
end
|
||||
local context = G.botContext
|
||||
local Panels = context.Panels
|
||||
|
||||
Panels.AttackLeaderTarget = function(parent)
|
||||
local toAttack = nil
|
||||
context.onMissle(function(missle)
|
||||
if not context.storage.attackLeader or context.storage.attackLeader:len() == 0 then
|
||||
return
|
||||
end
|
||||
local src = missle:getSource()
|
||||
if src.z ~= context.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]
|
||||
if c1:getName():lower() == context.storage.attackLeader:lower() then
|
||||
toAttack = toCreatures[1]
|
||||
end
|
||||
end)
|
||||
context.macro(50, "Attack leader's target", nil, function()
|
||||
if toAttack and context.storage.attackLeader:len() > 0 and toAttack ~= g_game.getAttackingCreature() then
|
||||
g_game.attack(toAttack)
|
||||
toAttack = nil
|
||||
end
|
||||
end, parent)
|
||||
context.addTextEdit("attackLeader", context.storage.attackLeader or "player name", function(widget, text)
|
||||
context.storage.attackLeader = text
|
||||
end, parent)
|
||||
end
|
||||
|
||||
|
||||
Panels.LimitFloor = function(parent)
|
||||
context.onPlayerPositionChange(function(pos)
|
||||
if context.storage.limitFloor then
|
||||
local gameMapPanel = modules.game_interface.getMapPanel()
|
||||
if gameMapPanel then
|
||||
gameMapPanel:lockVisibleFloor(pos.z)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local switch = context.addSwitch("limitFloor", "Don't show higher floors", function(widget)
|
||||
widget:setOn(not widget:isOn())
|
||||
context.storage.limitFloor = widget:isOn()
|
||||
local gameMapPanel = modules.game_interface.getMapPanel()
|
||||
if gameMapPanel then
|
||||
if context.storage.limitFloor then
|
||||
gameMapPanel:lockVisibleFloor(context.posz())
|
||||
else
|
||||
gameMapPanel:unlockVisibleFloor()
|
||||
end
|
||||
end
|
||||
end, parent)
|
||||
switch:setOn(context.storage.limitFloor)
|
||||
end
|
||||
|
||||
Panels.AntiPush = function(parent)
|
||||
if not parent then
|
||||
parent = context.panel
|
||||
end
|
||||
|
||||
local panelName = "antiPushPanel"
|
||||
local ui = g_ui.createWidget("ItemsPanel", parent)
|
||||
ui:setId(panelName)
|
||||
|
||||
if not context.storage[panelName] then
|
||||
context.storage[panelName] = {}
|
||||
end
|
||||
|
||||
ui.title:setText("Anti push")
|
||||
ui.title:setOn(context.storage[panelName].enabled)
|
||||
ui.title.onClick = function(widget)
|
||||
context.storage[panelName].enabled = not context.storage[panelName].enabled
|
||||
widget:setOn(context.storage[panelName].enabled)
|
||||
end
|
||||
|
||||
if type(context.storage[panelName].items) ~= 'table' then
|
||||
context.storage[panelName].items = {3031, 3035, 0, 0, 0}
|
||||
end
|
||||
|
||||
for i=1,5 do
|
||||
ui.items:getChildByIndex(i).onItemChange = function(widget)
|
||||
context.storage[panelName].items[i] = widget:getItemId()
|
||||
end
|
||||
ui.items:getChildByIndex(i):setItemId(context.storage[panelName].items[i])
|
||||
end
|
||||
|
||||
context.macro(100, function()
|
||||
if not context.storage[panelName].enabled then
|
||||
return
|
||||
end
|
||||
local tile = g_map.getTile(context.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(context.storage[panelName].items) do
|
||||
if item >= 100 and item ~= topItem and context.findItem(item) then
|
||||
table.insert(candidates, item)
|
||||
end
|
||||
end
|
||||
if #candidates == 0 then
|
||||
return
|
||||
end
|
||||
if type(context.storage[panelName].lastItem) ~= 'number' or context.storage[panelName].lastItem > #candidates then
|
||||
context.storage[panelName].lastItem = 1
|
||||
end
|
||||
local item = context.findItem(candidates[context.storage[panelName].lastItem])
|
||||
g_game.move(item, context.player:getPosition(), 1)
|
||||
context.storage[panelName].lastItem = context.storage[panelName].lastItem + 1
|
||||
end)
|
||||
end
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,88 +1,88 @@
|
||||
BotButton < Button
|
||||
height: 17
|
||||
margin-top: 2
|
||||
|
||||
BotSwitch < Button
|
||||
margin-top: 2
|
||||
height: 17
|
||||
image-color: green
|
||||
$!on:
|
||||
image-color: red
|
||||
|
||||
SmallBotSwitch < Button
|
||||
margin-top: 2
|
||||
height: 15
|
||||
image-color: green
|
||||
$!on:
|
||||
image-color: red
|
||||
|
||||
BotLabel < Label
|
||||
margin-top: 2
|
||||
height: 15
|
||||
text-auto-resize: true
|
||||
text-align: center
|
||||
text-wrap: true
|
||||
|
||||
BotItem < Item
|
||||
virtual: true
|
||||
&selectable: true
|
||||
&editable: true
|
||||
|
||||
BotTextEdit < TextEdit
|
||||
@onClick: modules.client_textedit.show(self)
|
||||
text-align: center
|
||||
multiline: false
|
||||
focusable: false
|
||||
height: 20
|
||||
|
||||
BotSeparator < HorizontalSeparator
|
||||
margin-top: 5
|
||||
margin-bottom: 3
|
||||
|
||||
BotSmallScrollBar < SmallScrollBar
|
||||
|
||||
BotPanel < Panel
|
||||
margin-top: 1
|
||||
ScrollablePanel
|
||||
id: content
|
||||
anchors.fill: parent
|
||||
margin-right: 8
|
||||
margin-left: 1
|
||||
margin-bottom: 5
|
||||
vertical-scrollbar: botPanelScroll
|
||||
layout:
|
||||
type: verticalBox
|
||||
$mobile:
|
||||
margin-right: 16
|
||||
|
||||
BotSmallScrollBar
|
||||
id: botPanelScroll
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
|
||||
CaveBotLabel < Label
|
||||
background-color: alpha
|
||||
text-offset: 2 0
|
||||
focusable: true
|
||||
|
||||
$focus:
|
||||
background-color: #00000055
|
||||
|
||||
SlotComboBoxPopupMenu < ComboBoxPopupMenu
|
||||
SlotComboBoxPopupMenuButton < ComboBoxPopupMenuButton
|
||||
SlotComboBox < ComboBox
|
||||
@onSetup: |
|
||||
self:addOption("Head")
|
||||
self:addOption("Neck")
|
||||
self:addOption("Back")
|
||||
self:addOption("Body")
|
||||
self:addOption("Right")
|
||||
self:addOption("Left")
|
||||
self:addOption("Leg")
|
||||
self:addOption("Feet")
|
||||
self:addOption("Finger")
|
||||
self:addOption("Ammo")
|
||||
self:addOption("Purse")
|
||||
|
||||
|
||||
BotButton < Button
|
||||
height: 17
|
||||
margin-top: 2
|
||||
|
||||
BotSwitch < Button
|
||||
margin-top: 2
|
||||
height: 17
|
||||
image-color: green
|
||||
$!on:
|
||||
image-color: red
|
||||
|
||||
SmallBotSwitch < Button
|
||||
margin-top: 2
|
||||
height: 15
|
||||
image-color: green
|
||||
$!on:
|
||||
image-color: red
|
||||
|
||||
BotLabel < Label
|
||||
margin-top: 2
|
||||
height: 15
|
||||
text-auto-resize: true
|
||||
text-align: center
|
||||
text-wrap: true
|
||||
|
||||
BotItem < Item
|
||||
virtual: true
|
||||
&selectable: true
|
||||
&editable: true
|
||||
|
||||
BotTextEdit < TextEdit
|
||||
@onClick: modules.client_textedit.show(self)
|
||||
text-align: center
|
||||
multiline: false
|
||||
focusable: false
|
||||
height: 20
|
||||
|
||||
BotSeparator < HorizontalSeparator
|
||||
margin-top: 5
|
||||
margin-bottom: 3
|
||||
|
||||
BotSmallScrollBar < SmallScrollBar
|
||||
|
||||
BotPanel < Panel
|
||||
margin-top: 1
|
||||
ScrollablePanel
|
||||
id: content
|
||||
anchors.fill: parent
|
||||
margin-right: 8
|
||||
margin-left: 1
|
||||
margin-bottom: 5
|
||||
vertical-scrollbar: botPanelScroll
|
||||
layout:
|
||||
type: verticalBox
|
||||
$mobile:
|
||||
margin-right: 16
|
||||
|
||||
BotSmallScrollBar
|
||||
id: botPanelScroll
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
|
||||
CaveBotLabel < Label
|
||||
background-color: alpha
|
||||
text-offset: 2 0
|
||||
focusable: true
|
||||
|
||||
$focus:
|
||||
background-color: #00000055
|
||||
|
||||
SlotComboBoxPopupMenu < ComboBoxPopupMenu
|
||||
SlotComboBoxPopupMenuButton < ComboBoxPopupMenuButton
|
||||
SlotComboBox < ComboBox
|
||||
@onSetup: |
|
||||
self:addOption("Head")
|
||||
self:addOption("Neck")
|
||||
self:addOption("Back")
|
||||
self:addOption("Body")
|
||||
self:addOption("Right")
|
||||
self:addOption("Left")
|
||||
self:addOption("Leg")
|
||||
self:addOption("Feet")
|
||||
self:addOption("Finger")
|
||||
self:addOption("Ammo")
|
||||
self:addOption("Purse")
|
||||
|
||||
|
||||
|
@@ -1,54 +1,54 @@
|
||||
BotConfig < Panel
|
||||
id: botConfig
|
||||
height: 45
|
||||
margin-left: 2
|
||||
margin-right: 2
|
||||
|
||||
ComboBox
|
||||
id: list
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
text-offset: 3 0
|
||||
width: 130
|
||||
|
||||
Button
|
||||
id: switch
|
||||
anchors.top: prev.top
|
||||
anchors.left: prev.right
|
||||
anchors.right: parent.right
|
||||
margin-left: 5
|
||||
$on:
|
||||
text: On
|
||||
color: #00AA00
|
||||
|
||||
$!on:
|
||||
text: Off
|
||||
color: #FF0000
|
||||
|
||||
Button
|
||||
margin-top: 2
|
||||
id: add
|
||||
anchors.top: prev.bottom
|
||||
anchors.left: parent.left
|
||||
text: Add
|
||||
width: 56
|
||||
height: 18
|
||||
text-offet: 0 2
|
||||
|
||||
Button
|
||||
id: edit
|
||||
anchors.top: prev.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: Edit
|
||||
width: 56
|
||||
height: 18
|
||||
text-offet: 0 2
|
||||
|
||||
Button
|
||||
id: remove
|
||||
anchors.top: prev.top
|
||||
anchors.right: parent.right
|
||||
text: Remove
|
||||
width: 56
|
||||
height: 18
|
||||
BotConfig < Panel
|
||||
id: botConfig
|
||||
height: 45
|
||||
margin-left: 2
|
||||
margin-right: 2
|
||||
|
||||
ComboBox
|
||||
id: list
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
text-offset: 3 0
|
||||
width: 130
|
||||
|
||||
Button
|
||||
id: switch
|
||||
anchors.top: prev.top
|
||||
anchors.left: prev.right
|
||||
anchors.right: parent.right
|
||||
margin-left: 5
|
||||
$on:
|
||||
text: On
|
||||
color: #00AA00
|
||||
|
||||
$!on:
|
||||
text: Off
|
||||
color: #FF0000
|
||||
|
||||
Button
|
||||
margin-top: 2
|
||||
id: add
|
||||
anchors.top: prev.bottom
|
||||
anchors.left: parent.left
|
||||
text: Add
|
||||
width: 56
|
||||
height: 18
|
||||
text-offet: 0 2
|
||||
|
||||
Button
|
||||
id: edit
|
||||
anchors.top: prev.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: Edit
|
||||
width: 56
|
||||
height: 18
|
||||
text-offet: 0 2
|
||||
|
||||
Button
|
||||
id: remove
|
||||
anchors.top: prev.top
|
||||
anchors.right: parent.right
|
||||
text: Remove
|
||||
width: 56
|
||||
height: 18
|
||||
text-offet: 0 2
|
@@ -1,19 +1,19 @@
|
||||
BotContainer < Panel
|
||||
height: 68
|
||||
|
||||
ScrollablePanel
|
||||
id: items
|
||||
anchors.fill: parent
|
||||
vertical-scrollbar: scroll
|
||||
layout:
|
||||
type: grid
|
||||
cell-size: 34 34
|
||||
flow: true
|
||||
|
||||
BotSmallScrollBar
|
||||
id: scroll
|
||||
anchors.top: prev.top
|
||||
anchors.bottom: prev.bottom
|
||||
anchors.right: parent.right
|
||||
step: 10
|
||||
pixels-scroll: true
|
||||
BotContainer < Panel
|
||||
height: 68
|
||||
|
||||
ScrollablePanel
|
||||
id: items
|
||||
anchors.fill: parent
|
||||
vertical-scrollbar: scroll
|
||||
layout:
|
||||
type: grid
|
||||
cell-size: 34 34
|
||||
flow: true
|
||||
|
||||
BotSmallScrollBar
|
||||
id: scroll
|
||||
anchors.top: prev.top
|
||||
anchors.bottom: prev.bottom
|
||||
anchors.right: parent.right
|
||||
step: 10
|
||||
pixels-scroll: true
|
||||
|
@@ -1,60 +1,60 @@
|
||||
BotIcon < UIWidget
|
||||
size: 50 50
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
focusable: false
|
||||
phantom: false
|
||||
draggable: true
|
||||
|
||||
UIItem
|
||||
id: item
|
||||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
margin-top: 6
|
||||
virtual: true
|
||||
phantom: true
|
||||
size: 32 32
|
||||
|
||||
UICreature
|
||||
id: creature
|
||||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
margin-top: 0
|
||||
size: 48 48
|
||||
phantom: true
|
||||
|
||||
UIWidget
|
||||
id: status
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
size: 18 10
|
||||
color: black
|
||||
font: terminus-10px
|
||||
phantom: true
|
||||
|
||||
$on:
|
||||
text: ON
|
||||
background: green
|
||||
|
||||
$!on:
|
||||
text: OFF
|
||||
background: red
|
||||
|
||||
UIWidget
|
||||
id: hotkey
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
size: 18 10
|
||||
color: white
|
||||
phantom: true
|
||||
text-align: right
|
||||
|
||||
UIWidget
|
||||
id: text
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
text-wrap: true
|
||||
text-auto-resize: true
|
||||
phantom: true
|
||||
BotIcon < UIWidget
|
||||
size: 50 50
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
focusable: false
|
||||
phantom: false
|
||||
draggable: true
|
||||
|
||||
UIItem
|
||||
id: item
|
||||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
margin-top: 6
|
||||
virtual: true
|
||||
phantom: true
|
||||
size: 32 32
|
||||
|
||||
UICreature
|
||||
id: creature
|
||||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
margin-top: 0
|
||||
size: 48 48
|
||||
phantom: true
|
||||
|
||||
UIWidget
|
||||
id: status
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
size: 18 10
|
||||
color: black
|
||||
font: terminus-10px
|
||||
phantom: true
|
||||
|
||||
$on:
|
||||
text: ON
|
||||
background: green
|
||||
|
||||
$!on:
|
||||
text: OFF
|
||||
background: red
|
||||
|
||||
UIWidget
|
||||
id: hotkey
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
size: 18 10
|
||||
color: white
|
||||
phantom: true
|
||||
text-align: right
|
||||
|
||||
UIWidget
|
||||
id: text
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
text-wrap: true
|
||||
text-auto-resize: true
|
||||
phantom: true
|
||||
|
@@ -1,240 +1,240 @@
|
||||
DualScrollPanel < Panel
|
||||
height: 51
|
||||
margin-top: 3
|
||||
|
||||
SmallBotSwitch
|
||||
id: title
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
text-align: center
|
||||
|
||||
HorizontalScrollBar
|
||||
id: scroll1
|
||||
anchors.left: title.left
|
||||
anchors.right: title.horizontalCenter
|
||||
anchors.top: title.bottom
|
||||
margin-right: 2
|
||||
margin-top: 2
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
step: 1
|
||||
&disableScroll: true
|
||||
|
||||
HorizontalScrollBar
|
||||
id: scroll2
|
||||
anchors.left: title.horizontalCenter
|
||||
anchors.right: title.right
|
||||
anchors.top: prev.top
|
||||
margin-left: 2
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
step: 1
|
||||
&disableScroll: true
|
||||
|
||||
BotTextEdit
|
||||
id: text
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: scroll1.bottom
|
||||
margin-top: 3
|
||||
margin-left: 2
|
||||
margin-right: 1
|
||||
|
||||
SingleScrollItemPanel < Panel
|
||||
height: 45
|
||||
margin-top: 2
|
||||
|
||||
BotItem
|
||||
id: item
|
||||
anchors.left: parent.left
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 3
|
||||
|
||||
SmallBotSwitch
|
||||
id: title
|
||||
anchors.left: prev.right
|
||||
anchors.right: parent.right
|
||||
anchors.top: prev.top
|
||||
margin-left: 2
|
||||
text-align: center
|
||||
|
||||
HorizontalScrollBar
|
||||
id: scroll
|
||||
anchors.left: title.left
|
||||
anchors.right: title.right
|
||||
anchors.top: title.bottom
|
||||
margin-top: 2
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
step: 1
|
||||
&disableScroll: true
|
||||
|
||||
DualScrollItemPanel < Panel
|
||||
height: 33
|
||||
margin-top: 3
|
||||
|
||||
BotItem
|
||||
id: item
|
||||
anchors.left: parent.left
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 3
|
||||
|
||||
SmallBotSwitch
|
||||
id: title
|
||||
anchors.left: prev.right
|
||||
anchors.right: parent.right
|
||||
anchors.top: prev.top
|
||||
margin-left: 2
|
||||
text-align: center
|
||||
|
||||
HorizontalScrollBar
|
||||
id: scroll1
|
||||
anchors.left: title.left
|
||||
anchors.right: title.horizontalCenter
|
||||
anchors.top: title.bottom
|
||||
margin-top: 2
|
||||
margin-right: 2
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
step: 1
|
||||
&disableScroll: true
|
||||
|
||||
HorizontalScrollBar
|
||||
id: scroll2
|
||||
anchors.left: title.horizontalCenter
|
||||
anchors.right: title.right
|
||||
anchors.top: prev.top
|
||||
margin-left: 2
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
step: 1
|
||||
&disableScroll: true
|
||||
|
||||
ItemsRow < Panel
|
||||
height: 33
|
||||
margin-top: 2
|
||||
|
||||
BotItem
|
||||
id: item1
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
|
||||
BotItem
|
||||
id: item2
|
||||
anchors.top: prev.top
|
||||
anchors.left: prev.right
|
||||
margin-left: 2
|
||||
|
||||
BotItem
|
||||
id: item3
|
||||
anchors.top: prev.top
|
||||
anchors.left: prev.right
|
||||
margin-left: 2
|
||||
|
||||
BotItem
|
||||
id: item4
|
||||
anchors.top: prev.top
|
||||
anchors.left: prev.right
|
||||
margin-left: 2
|
||||
|
||||
BotItem
|
||||
id: item5
|
||||
anchors.top: prev.top
|
||||
anchors.left: prev.right
|
||||
margin-left: 2
|
||||
|
||||
ItemsPanel < Panel
|
||||
height: 55
|
||||
|
||||
SmallBotSwitch
|
||||
id: title
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
text-align: center
|
||||
|
||||
ItemsRow
|
||||
id: items
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: prev.bottom
|
||||
|
||||
|
||||
ItemAndButtonPanel < Panel
|
||||
height: 40
|
||||
|
||||
BotItem
|
||||
id: item
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
|
||||
BotSwitch
|
||||
id: title
|
||||
anchors.left: prev.right
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: prev.verticalCenter
|
||||
text-align: center
|
||||
margin-left: 2
|
||||
margin-top: 0
|
||||
|
||||
ItemAndSlotPanel < Panel
|
||||
height: 40
|
||||
|
||||
BotItem
|
||||
id: item
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
|
||||
SmallBotSwitch
|
||||
id: title
|
||||
anchors.left: prev.right
|
||||
anchors.right: parent.right
|
||||
anchors.top: prev.top
|
||||
text-align: center
|
||||
margin-left: 2
|
||||
margin-top: 0
|
||||
|
||||
SlotComboBox
|
||||
id: slot
|
||||
anchors.left: prev.left
|
||||
anchors.right: prev.right
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 2
|
||||
height: 20
|
||||
&disableScroll: true
|
||||
|
||||
TwoItemsAndSlotPanel < Panel
|
||||
height: 35
|
||||
margin-top: 4
|
||||
|
||||
BotItem
|
||||
id: item1
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
margin-top: 1
|
||||
|
||||
BotItem
|
||||
id: item2
|
||||
anchors.left: prev.right
|
||||
anchors.top: prev.top
|
||||
margin-left: 1
|
||||
|
||||
SmallBotSwitch
|
||||
id: title
|
||||
anchors.left: prev.right
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
text-align: center
|
||||
margin-left: 2
|
||||
margin-top: 0
|
||||
|
||||
SlotComboBox
|
||||
id: slot
|
||||
anchors.left: prev.left
|
||||
anchors.right: prev.right
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 2
|
||||
height: 20
|
||||
&disableScroll: true
|
||||
DualScrollPanel < Panel
|
||||
height: 51
|
||||
margin-top: 3
|
||||
|
||||
SmallBotSwitch
|
||||
id: title
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
text-align: center
|
||||
|
||||
HorizontalScrollBar
|
||||
id: scroll1
|
||||
anchors.left: title.left
|
||||
anchors.right: title.horizontalCenter
|
||||
anchors.top: title.bottom
|
||||
margin-right: 2
|
||||
margin-top: 2
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
step: 1
|
||||
&disableScroll: true
|
||||
|
||||
HorizontalScrollBar
|
||||
id: scroll2
|
||||
anchors.left: title.horizontalCenter
|
||||
anchors.right: title.right
|
||||
anchors.top: prev.top
|
||||
margin-left: 2
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
step: 1
|
||||
&disableScroll: true
|
||||
|
||||
BotTextEdit
|
||||
id: text
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: scroll1.bottom
|
||||
margin-top: 3
|
||||
margin-left: 2
|
||||
margin-right: 1
|
||||
|
||||
SingleScrollItemPanel < Panel
|
||||
height: 45
|
||||
margin-top: 2
|
||||
|
||||
BotItem
|
||||
id: item
|
||||
anchors.left: parent.left
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 3
|
||||
|
||||
SmallBotSwitch
|
||||
id: title
|
||||
anchors.left: prev.right
|
||||
anchors.right: parent.right
|
||||
anchors.top: prev.top
|
||||
margin-left: 2
|
||||
text-align: center
|
||||
|
||||
HorizontalScrollBar
|
||||
id: scroll
|
||||
anchors.left: title.left
|
||||
anchors.right: title.right
|
||||
anchors.top: title.bottom
|
||||
margin-top: 2
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
step: 1
|
||||
&disableScroll: true
|
||||
|
||||
DualScrollItemPanel < Panel
|
||||
height: 33
|
||||
margin-top: 3
|
||||
|
||||
BotItem
|
||||
id: item
|
||||
anchors.left: parent.left
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 3
|
||||
|
||||
SmallBotSwitch
|
||||
id: title
|
||||
anchors.left: prev.right
|
||||
anchors.right: parent.right
|
||||
anchors.top: prev.top
|
||||
margin-left: 2
|
||||
text-align: center
|
||||
|
||||
HorizontalScrollBar
|
||||
id: scroll1
|
||||
anchors.left: title.left
|
||||
anchors.right: title.horizontalCenter
|
||||
anchors.top: title.bottom
|
||||
margin-top: 2
|
||||
margin-right: 2
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
step: 1
|
||||
&disableScroll: true
|
||||
|
||||
HorizontalScrollBar
|
||||
id: scroll2
|
||||
anchors.left: title.horizontalCenter
|
||||
anchors.right: title.right
|
||||
anchors.top: prev.top
|
||||
margin-left: 2
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
step: 1
|
||||
&disableScroll: true
|
||||
|
||||
ItemsRow < Panel
|
||||
height: 33
|
||||
margin-top: 2
|
||||
|
||||
BotItem
|
||||
id: item1
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
|
||||
BotItem
|
||||
id: item2
|
||||
anchors.top: prev.top
|
||||
anchors.left: prev.right
|
||||
margin-left: 2
|
||||
|
||||
BotItem
|
||||
id: item3
|
||||
anchors.top: prev.top
|
||||
anchors.left: prev.right
|
||||
margin-left: 2
|
||||
|
||||
BotItem
|
||||
id: item4
|
||||
anchors.top: prev.top
|
||||
anchors.left: prev.right
|
||||
margin-left: 2
|
||||
|
||||
BotItem
|
||||
id: item5
|
||||
anchors.top: prev.top
|
||||
anchors.left: prev.right
|
||||
margin-left: 2
|
||||
|
||||
ItemsPanel < Panel
|
||||
height: 55
|
||||
|
||||
SmallBotSwitch
|
||||
id: title
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
text-align: center
|
||||
|
||||
ItemsRow
|
||||
id: items
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: prev.bottom
|
||||
|
||||
|
||||
ItemAndButtonPanel < Panel
|
||||
height: 40
|
||||
|
||||
BotItem
|
||||
id: item
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
|
||||
BotSwitch
|
||||
id: title
|
||||
anchors.left: prev.right
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: prev.verticalCenter
|
||||
text-align: center
|
||||
margin-left: 2
|
||||
margin-top: 0
|
||||
|
||||
ItemAndSlotPanel < Panel
|
||||
height: 40
|
||||
|
||||
BotItem
|
||||
id: item
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
|
||||
SmallBotSwitch
|
||||
id: title
|
||||
anchors.left: prev.right
|
||||
anchors.right: parent.right
|
||||
anchors.top: prev.top
|
||||
text-align: center
|
||||
margin-left: 2
|
||||
margin-top: 0
|
||||
|
||||
SlotComboBox
|
||||
id: slot
|
||||
anchors.left: prev.left
|
||||
anchors.right: prev.right
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 2
|
||||
height: 20
|
||||
&disableScroll: true
|
||||
|
||||
TwoItemsAndSlotPanel < Panel
|
||||
height: 35
|
||||
margin-top: 4
|
||||
|
||||
BotItem
|
||||
id: item1
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
margin-top: 1
|
||||
|
||||
BotItem
|
||||
id: item2
|
||||
anchors.left: prev.right
|
||||
anchors.top: prev.top
|
||||
margin-left: 1
|
||||
|
||||
SmallBotSwitch
|
||||
id: title
|
||||
anchors.left: prev.right
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
text-align: center
|
||||
margin-left: 2
|
||||
margin-top: 0
|
||||
|
||||
SlotComboBox
|
||||
id: slot
|
||||
anchors.left: prev.left
|
||||
anchors.right: prev.right
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 2
|
||||
height: 20
|
||||
&disableScroll: true
|
||||
|
Reference in New Issue
Block a user