Version 0.999 BETA - a lot of bug fixes, improvments and more advanced bot

This commit is contained in:
OTCv8
2019-10-31 05:46:22 +01:00
parent 017fa290b4
commit 06b08af1df
36 changed files with 1513 additions and 415 deletions

View File

@@ -6,6 +6,9 @@ It's based on https://github.com/edubart/otclient and it's not backward compatib
# DISCORD
OTClientV8 discord channel: https://discord.gg/feySup6 (new, working link!)
# Forum
OTClientV8 forum: https://otland.net/forums/otclient.494/
# FEATURES
- Rewritten and optimized rendering (60 fps on 11 years old computer)
- Better DirectX9 and DirectX11 support
@@ -26,6 +29,7 @@ OTClientV8 discord channel: https://discord.gg/feySup6 (new, working link!)
- Updated and optimized battle list
- Crosshair, floor fading, extra health/mana bars and panels
- Removed a lot of useless and outdated things
- Bot (https://github.com/OTCv8/otclientv8_bot)
- Support for proxies to lower latency and protect against DDoS (extra paid option)
### And hundreds of smaller features, optimizations and bug fixes!
@@ -33,13 +37,8 @@ OTClientV8 discord channel: https://discord.gg/feySup6 (new, working link!)
### There's github repo of tfs 1.3 with otclientv8 features: https://github.com/OTCv8/otclientv8-tfs
# Facts
### It took almost 1000h to make this project
### OTClientV8 has been used by over 6000 unique players!
### You can check last active players on: http://otclient.ovh/clients.php
# Paid version
The difference between paid version and this one is that the 1st one comes with c++ sources and has professional support. You may need c++ source if you want to add some more advanced modifications, better encryption, bot protection or some other things. The free version doesn't offer technical support, you need to follow tutorials and in case of any bug or problem you should submit an issue on github. Check http://otclient.ovh if you want more about paid version and other extra services.
The difference between paid version and this one is that the 1st one comes with c++ sources and has better support. You may need c++ source if you want to add some more advanced modifications, better encryption, bot protection or some other things. The free version doesn't offer technical support, you need to follow tutorials and in case of any bug or problem you should submit an issue on github. Visit http://otclient.ovh if you want to know more about paid version and other extra services.
# Quick Start

View File

@@ -9,6 +9,7 @@ local render = nil
local atlas = nil
local adaptiveRender = nil
local slowMain = nil
local widgetsInfo = nil
local updateEvent = nil
local monitorEvent = nil
@@ -36,6 +37,7 @@ function init()
atlas = statsWindow:recursiveGetChildById('atlas')
adaptiveRender = statsWindow:recursiveGetChildById('adaptiveRender')
slowMain = statsWindow:recursiveGetChildById('slowMain')
widgetsInfo = statsWindow:recursiveGetChildById('widgetsInfo')
lastSend = os.time()
g_stats.resetSleepTime()
@@ -143,6 +145,7 @@ function sendStats()
g_stats.clear(i - 1)
g_stats.clearSlow(i - 1)
end
data.widgets = g_stats.getWidgetsInfo(10, false)
data = json.encode(data)
if Services.stats ~= nil and Services.stats:len() > 3 then
g_http.post(Services.stats, data)
@@ -171,7 +174,8 @@ function update()
dispatcherStats:setText(g_stats.get(3, 5, true))
luaStats:setText(g_stats.get(4, 5, true))
luaCallback:setText(g_stats.get(5, 5, true))
slowMain:setText(g_stats.getSlow(3, 10, 10, true) .. "\n\n\n" .. g_stats.getSlow(1, 20, 20, true))
slowMain:setText(g_stats.getSlow(3, 10, 10, true) .. "\n\n\n" .. g_stats.getSlow(1, 20, 20, true))
widgetsInfo:setText(g_stats.getWidgetsInfo(10, true))
if g_proxy then
local text = ""

View File

@@ -87,6 +87,13 @@ MainWindow
DebugText
id: luaCallback
text: -
DebugLabel
!text: tr('Widgets')
DebugText
id: widgetsInfo
text: -
DebugLabel
!text: tr('Slow main functions')

View File

@@ -317,6 +317,12 @@ function UIMoveableTabBar:onStyleApply(styleName, styleNode)
end
end
function UIMoveableTabBar:clearTabs()
while #self.tabs > 0 do
self:removeTab(self.tabs[#self.tabs])
end
end
function UIMoveableTabBar:removeTab(tab)
local tabTables = {self.tabs, self.preTabs, self.postTabs}
local index = nil

View File

@@ -80,8 +80,10 @@ end
function UISpinBox:onStyleApply(styleName, styleNode)
for name, value in pairs(styleNode) do
if name == 'maximum' then
self.maximum = value
addEvent(function() self:setMaximum(value) end)
elseif name == 'minimum' then
self.minimum = value
addEvent(function() self:setMinimum(value) end)
elseif name == 'mouse-scroll' then
addEvent(function() self:setMouseScroll(value) end)
@@ -118,6 +120,9 @@ function UISpinBox:down()
end
function UISpinBox:setValue(value, dontSignal)
if type(value) == "string" then
value = tonumber(value)
end
value = value or 0
value = math.max(math.min(self.maximum, value), self.minimum)

View File

@@ -6,6 +6,7 @@ contentsPanel = nil
configWindow = nil
configEditorText = nil
configList = nil
botTabs = nil
botPanel = nil
local botMessages = nil
local configCopy = ""
@@ -32,6 +33,17 @@ function init()
onKeyPress = botKeyPress })
connect(Tile, { onAddThing = botAddThing, onRemoveThing = botRemoveThing })
connect(Creature, {
onAppear = botCreatureAppear,
onDisappear =botCreatureDisappear,
onPositionChange = botCreaturePositionChange,
onHealthPercentChange = botCraetureHealthPercentChange
})
connect(LocalPlayer, {
onPositionChange = botCreaturePositionChange,
onHealthPercentChange = botCraetureHealthPercentChange
})
botConfigFile = g_configs.create("/bot.otml")
local config = botConfigFile:get("config")
@@ -53,18 +65,20 @@ function init()
botWindow = g_ui.loadUI('bot', modules.game_interface.getRightPanel())
botWindow:setup()
contentsPanel = botWindow:getChildById('contentsPanel')
configList = contentsPanel:getChildById('config')
enableButton = contentsPanel:getChildById('enableButton')
statusLabel = contentsPanel:getChildById('statusLabel')
botMessages = contentsPanel:getChildById('messages')
botPanel = contentsPanel:getChildById('botPanel')
contentsPanel = botWindow.contentsPanel
configList = contentsPanel.config
enableButton = contentsPanel.enableButton
statusLabel = contentsPanel.statusLabel
botMessages = contentsPanel.messages
botTabs = contentsPanel.botTabs
botPanel = contentsPanel.botPanel
botTabs:setContentWidget(botPanel)
configWindow = g_ui.displayUI('config')
configWindow:hide()
configEditorText = configWindow:getChildById('text')
configTab = configWindow:getChildById('configTab')
configEditorText = configWindow.text
configTab = configWindow.configTab
configTab.onTabChange = editorTabChanged
@@ -91,8 +105,27 @@ function init()
end
function saveConfig()
botConfigFile:set("config", json.encode(botConfig))
botConfigFile:save()
local status, result = pcall(function()
botConfigFile:set("config", json.encode(botConfig))
botConfigFile:save()
end)
if not status then
errorOccured = true
-- try to fix it
local extraInfo = ""
for i = 1, #botConfig.configs do
if botConfig.configs[i].storage then
local status, result = pcall(function() json.encode(botConfig.configs[i].storage) end)
if not status then
botConfig.configs[i].storage = nil
extraInfo = extraInfo .. "\nLocal storage of config " .. i .. " has been erased due to invalid data"
end
end
end
statusLabel:setText("Error while saving config and user storage:\n" .. result .. extraInfo .. "\n\n" .. "Try to restart bot")
return false
end
return true
end
function terminate()
@@ -107,6 +140,17 @@ function terminate()
disconnect(Tile, { onAddThing = botAddThing, onRemoveThing = botRemoveThing })
disconnect(Creature, {
onAppear = botCreatureAppear,
onDisappear =botCreatureDisappear,
onPositionChange = botCreaturePositionChange,
onHealthPercentChange = botCraetureHealthPercentChange
})
disconnect(LocalPlayer, {
onPositionChange = botCreaturePositionChange,
onHealthPercentChange = botCraetureHealthPercentChange
})
removeEvent(executeEvent)
removeEvent(checkMsgsEvent)
@@ -259,13 +303,15 @@ end
function clearConfig()
compiledConfig = nil
botPanel:destroyChildren()
botTabs:clearTabs()
botTabs:setOn(false)
botMessages:destroyChildren()
botMessages:updateLayout()
end
function refreshConfig()
clearConfig()
configWindow:hide()
botConfig.selectedConfig = configList.currentIndex
@@ -273,8 +319,13 @@ function refreshConfig()
return
end
saveConfig()
if not saveConfig() then
clearConfig()
return
end
clearConfig()
local config = botConfig.configs[configList.currentIndex]
if not config.storage then
config.storage = {}
@@ -286,7 +337,7 @@ function refreshConfig()
end
errorOccured = false
g_game.enableTileThingLuaCallback(false)
local status, result = pcall(function() return executeBot(config.script, config.storage, botPanel, botMsgCallback) end)
local status, result = pcall(function() return executeBot(config.script, config.storage, botTabs, botMsgCallback) end)
if not status then
errorOccured = true
statusLabel:setText("Error: " .. tostring(result))
@@ -342,9 +393,8 @@ function checkMsgs()
end
end
function botKeyDown(widget, keyCode, keyboardModifiers)
if keyCode == KeyUnknown or compiledConfig == nil then return false end
local status, result = pcall(function() compiledConfig.callbacks.onKeyDown(keyCode, keyboardModifiers) end)
function safeBotCall(func)
local status, result = pcall(func)
if not status then
errorOccured = true
statusLabel:setText("Error: " .. result)
@@ -352,52 +402,55 @@ function botKeyDown(widget, keyCode, keyboardModifiers)
return false
end
function botKeyDown(widget, keyCode, keyboardModifiers)
if compiledConfig == nil then return false end
if keyCode == KeyUnknown then return end
safeBotCall(function() compiledConfig.callbacks.onKeyDown(keyCode, keyboardModifiers) end)
end
function botKeyUp(widget, keyCode, keyboardModifiers)
if keyCode == KeyUnknown or compiledConfig == nil then return false end
local status, result = pcall(function() compiledConfig.callbacks.onKeyUp(keyCode, keyboardModifiers) end)
if not status then
errorOccured = true
statusLabel:setText("Error: " .. result)
end
return false
if compiledConfig == nil then return false end
if keyCode == KeyUnknown then return end
safeBotCall(function() compiledConfig.callbacks.onKeyUp(keyCode, keyboardModifiers) end)
end
function botKeyPress(widget, keyCode, keyboardModifiers, autoRepeatTicks)
if keyCode == KeyUnknown or compiledConfig == nil then return false end
local status, result = pcall(function() compiledConfig.callbacks.onKeyPress(keyCode, keyboardModifiers, autoRepeatTicks) end)
if not status then
errorOccured = true
statusLabel:setText("Error: " .. result)
end
return false
if compiledConfig == nil then return false end
if keyCode == KeyUnknown then return end
safeBotCall(function() compiledConfig.callbacks.onKeyPress(keyCode, keyboardModifiers, autoRepeatTicks) end)
end
function botOnTalk(name, level, mode, text, channelId, pos)
if compiledConfig == nil then return false end
local status, result = pcall(function() compiledConfig.callbacks.onTalk(name, level, mode, text, channelId, pos) end)
if not status then
errorOccured = true
statusLabel:setText("Error: " .. result)
end
return false
safeBotCall(function() compiledConfig.callbacks.onTalk(name, level, mode, text, channelId, pos) end)
end
function botAddThing(tile, thing, asd)
function botAddThing(tile, thing)
if compiledConfig == nil then return false end
local status, result = pcall(function() compiledConfig.callbacks.onAddThing(tile, thing) end)
if not status then
errorOccured = true
statusLabel:setText("Error: " .. result)
end
return false
safeBotCall(function() compiledConfig.callbacks.onAddThing(tile, thing) end)
end
function botRemoveThing(tile, thing)
if compiledConfig == nil then return false end
local status, result = pcall(function() compiledConfig.callbacks.onRemoveThing(tile, thing) end)
if not status then
errorOccured = true
statusLabel:setText("Error: " .. result)
end
return false
end
safeBotCall(function() compiledConfig.callbacks.onRemoveThing(tile, thing) end)
end
function botCreatureAppear(creature)
if compiledConfig == nil then return false end
safeBotCall(function() compiledConfig.callbacks.onCreatureAppear(creature) end)
end
function botCreatureDisappear(creature)
if compiledConfig == nil then return false end
safeBotCall(function() compiledConfig.callbacks.onCreatureDisappear(creature) end)
end
function botCreaturePositionChange(creature, newPos, oldPos)
if compiledConfig == nil then return false end
safeBotCall(function() compiledConfig.callbacks.onCreaturePositionChange(creature, newPos, oldPos) end)
end
function botCraetureHealthPercentChange(creature, healthPercent)
if compiledConfig == nil then return false end
safeBotCall(function() compiledConfig.callbacks.onCreatureHealthPercentChange(creature, healthPercent) end)
end

View File

@@ -3,12 +3,14 @@ BotButton < Button
BotSwitch < Button
margin-top: 2
height: 20
image-color: green
$!on:
image-color: red
BotLabel < Label
margin-top: 2
height: 20
text-auto-resize: true
text-align: center
text-wrap: true
@@ -18,17 +20,20 @@ BotItem < UIItem
size: 32 32
border: 1 black
&selectable: true
BotTextEdit < TextEdit
@onClick: modules.game_textedit.show(self)
text-align: center
multiline: false
BotSeparator < HorizontalSeparator
margin-top: 5
margin-bottom: 3
BotPanel < Panel
margin-top: 2
layout:
type: verticalBox
fit-children: true
MiniWindow
id: botWindow
!text: tr('Bot')
@@ -99,12 +104,28 @@ MiniWindow
anchors.right: parent.right
anchors.top: prev.bottom
margin-top: 5
MoveableTabBar
id: botTabs
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
tab-spacing: 2
height: 20
movable: false
$on:
visible: true
margin-top: 2
$!on:
visible: false
margin-top: -20
Panel
id: botPanel
margin-top: 2
anchors.top: prev.bottom
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
id: botPanel
layout:
type: verticalBox

View File

@@ -1,82 +1,52 @@
botDefaultConfig = {
configs = {
{name = "Example", script = [=[
--#Example
info("Tested on 10.99")
--Example
--#main
local widget = setupUI([[
Panel
id: redPanel
background: red
margin-top: 10
margin-bottom: 10
height: 100
Label
anchors.fill: parent
text: custom ui, otml based
text-align: center
]])
Panels.Haste()
Panels.ManaShield()
Panels.Health()
Panels.HealthItem()
Panels.ManaItem()
Panels.ManaItem()
Panels.AntiParalyze()
local tab2 = addTab("Another Tab")
addButton("button1", "test button on 2nd tab", nil, tab2)
local tab3 = addTab("3th tab")
addLabel("label1", "Label on 3th tab", tab3)
Panels.Turning(tab3)
--#macros
macro(5000, "macro send link", "f5", function()
g_game.talk("macro test - https://github.com/OTCv8/otclient_bot")
g_game.talk("bot is hiding 50% of effects as example, say exevo gran mas vis")
end)
macro(1000, "flag tiles", function()
player:getTile():setText("Hello =)", "red")
end)
macro(25, "auto healing", function()
if hppercent() < 80 then
say("exura")
delay(1000) -- not calling this macro for next 1s
end
end)
addSeparator("spe0")
local helloLabel = addLabel("helloLabel", "", tab2)
macro(1000, "example macro (time)", nil, function()
helloLabel:setText("Time from start: " .. now)
end, tab2)
--#hotkeys
hotkey('y', 'test hotkey', function() g_game.talk('hotkey elo') end)
singlehotkey('x', 'single hotkey', function() g_game.talk('single hotkey') end)
singlehotkey('=', "Zoom in map", function () zoomIn() end)
singlehotkey('-', "Zoom out map", function () zoomOut() end)
--#callbacks
onAddThing(function(tile, thing)
if thing:isItem() and thing:getId() == 2129 then
local pos = tile:getPosition().x .. "," .. tile:getPosition().y .. "," .. tile:getPosition().z
if not storage[pos] or storage[pos] < now then
storage[pos] = now + 20000
end
tile:setTimer(storage[pos] - now)
end
hotkey("f5", "example hotkey", function()
info("Wow, you clicked f5 hotkey")
end)
-- hide 50% of effects
onAddThing(function(tile, thing)
if thing:isEffect() and math.random(1, 2) == 1 then
thing:hide()
end
singlehotkey("f6", "example hotkey2", function()
info("Wow, you clicked f6 singlehotkey")
end)
--#callbacks
local positionLabel = addLabel("positionLabel", "")
onPlayerPositionChange(function()
positionLabel:setText("Pos: " .. posx() .. "," .. posy() .. "," .. posz())
end)
listen(player:getName(), function(text)
info("you said: " .. text)
end)
--#other
addLabel("label1", "Test label 1")
addSeparator("sep1")
addLabel("label2", "Test label 2")
storage.clicks = 0
addButton("button1", "Click me", function()
storage.clicks = storage.clicks + 1
ui.button1:setText("Clicks: " .. storage.clicks)
end)
HTTP.getJSON("https://api.ipify.org/?format=json", function(data, err)
if err then
@@ -85,6 +55,7 @@ HTTP.getJSON("https://api.ipify.org/?format=json", function(data, err)
end
info("HTTP: My IP is: " .. tostring(data['ip']))
end)
]=]},

View File

@@ -1,6 +1,8 @@
function executeBot(config, storage, panel, msgCallback)
function executeBot(config, storage, tabs, msgCallback)
local context = {}
context.panel = panel
context.tabs = tabs
context.panel = context.tabs:addTab("Main", g_ui.createWidget('BotPanel')).tabPanel
context.storage = storage
if context.storage._macros == nil then
context.storage._macros = {} -- active macros
@@ -16,9 +18,12 @@ function executeBot(config, storage, panel, msgCallback)
onKeyPress = {},
onTalk = {},
onAddThing = {},
onRemoveThing = {}
onRemoveThing = {},
onCreatureAppear = {},
onCreatureDisappear = {},
onCreaturePositionChange = {},
onCreatureHealthPercentChange = {}
}
context.ui = {}
-- basic functions & classes
context.print = print
@@ -44,265 +49,20 @@ function executeBot(config, storage, panel, msgCallback)
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
-- UI
context.setupUI = function(otml, parent)
if parent == nil then
parent = context.panel
end
local widget = g_ui.loadUIFromString(otml, parent)
if parent == context.panel and widget:getId() then
context.ui[widget:getId()] = widget
end
return widget
end
context.addSwitch = function(id, text, onClickCallback)
local switch = g_ui.createWidget('BotSwitch', context.panel)
switch:setId(id)
switch:setText(text)
switch.onClick = onClickCallback
context.ui[id] = switch
return switch
end
context.addButton = function(id, text, onClickCallback)
local button = g_ui.createWidget('BotButton', context.panel)
button:setId(id)
button:setText(text)
button.onClick = onClickCallback
context.ui[id] = button
return button
end
context.addLabel = function(id, text)
local label = g_ui.createWidget('BotLabel', context.panel)
label:setId(id)
label:setText(text)
context.ui[id] = label
return label
end
context.addSeparator = function(id)
local separator = g_ui.createWidget('BotSeparator', context.panel)
separator:setId(id)
context.ui[id] = separator
return separator
end
context._addMacroSwitch = function(name, keys)
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)
switch:setOn(context.storage._macros[name])
return switch
end
context._addHotkeySwitch = function(name, keys)
local text = name
if keys:len() > 0 then
text = name .. " [" .. keys .. "]"
end
local switch = context.addSwitch("hotkey_" .. #context._hotkeys, text, nil)
switch:setOn(false)
return switch
end
-- MAIN BOT FUNCTION
-- macro(timeout, callback)
-- macro(timeout, name, callback)
-- macro(timeout, name, hotkey, callback)
context.macro = function(timeout, name, hotkey, callback)
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
callback = hotkey
hotkey = ""
elseif type(callback) ~= 'function' then
error("Invalid callback for macro: " .. tostring(callback))
end
if type(name) ~= 'string' or type(hotkey) ~= 'string' then
error("Invalid name or hotkey for macro")
end
if hotkey:len() > 0 then
hotkey = retranslateKeyComboDesc(hotkey)
end
local switch = nil
if name:len() > 0 then
if context.storage._macros[name] == nil then
context.storage._macros[name] = true
end
switch = context._addMacroSwitch(name, hotkey)
end
table.insert(context._macros, {
timeout = timeout,
name = name,
callback = callback,
lastExecution = context.now,
hotkey = hotkey,
switch = switch
})
return context._macros[#context._macros]
end
-- hotkey(keys, callback)
-- hotkey(keys, name, callback)
context.hotkey = function(keys, name, callback)
if type(name) == 'function' then
callback = name
name = ""
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)
end
context._hotkeys[keys] = {
name = name,
callback = callback,
lastExecution = context.now,
switch = switch,
single = false
}
return context._hotkeys[keys]
end
-- singlehotkey(keys, callback)
-- singlehotkey(keys, name, callback)
context.singlehotkey = function(keys, name, callback)
if type(name) == 'function' then
callback = name
name = ""
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)
end
context._hotkeys[keys] = {
name = name,
callback = callback,
lastExecution = context.now,
switch = switch,
single = true
}
return context._hotkeys[keys]
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
-- 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 callbackData = {}
table.insert(context._callbacks[callbackType], function(...)
if not callbackData.delay or callbackData.delay < context.now then
context._currentExecution = callbackData
callback(...)
context._currentExecution = nil
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
-- 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
-- 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()
context.onTalk(function(name2, level, mode, text, channelId, pos)
if name == name2:lower() then
callback(text, channelId, pos)
end
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
context.warning = context.warn
-- init context
context.now = g_clock.millis()
context.time = g_clock.millis()
context.player = g_game.getLocalPlayer()
require("functions.lua")
setupFunctions(context)
-- init functions
G.botContext = context
dofiles("functions")
context.Panels = {}
dofiles("panels")
G.botContext = nil
-- run script
assert(load(config, nil, nil, context))()
@@ -313,11 +73,8 @@ function executeBot(config, storage, panel, msgCallback)
for i, macro in ipairs(context._macros) do
if macro.lastExecution + macro.timeout <= context.now and (macro.name == nil or macro.name:len() < 1 or context.storage._macros[macro.name]) then
if not macro.delay or macro.delay < context.now then
macro.lastExecution = context.now
context._currentExecution = context._macros[i]
macro.callback()
context._currentExecution = nil
if macro.callback() then
macro.lastExecution = context.now
end
end
end
@@ -338,11 +95,8 @@ function executeBot(config, storage, panel, msgCallback)
local hotkey = context._hotkeys[keyDesc]
if hotkey then
if hotkey.single then
if not hotkey.delay or hotkey.delay < context.now then
hotkey.lastExecution = context.now
context._currentExecution = hotkey
hotkey.callback()
context._currentExecution = nil
if hotkey.callback() then
hotkey.lastExecution = context.now
end
end
if hotkey.switch then
@@ -369,11 +123,8 @@ function executeBot(config, storage, panel, msgCallback)
local keyDesc = determineKeyComboDesc(keyCode, keyboardModifiers)
local hotkey = context._hotkeys[keyDesc]
if hotkey and not hotkey.single then
if not hotkey.delay or hotkey.delay < context.now then
hotkey.lastExecution = context.now
context._currentExecution = hotkey
hotkey.callback()
context._currentExecution = nil
if hotkey.callback() then
hotkey.lastExecution = context.now
end
end
for i, callback in ipairs(context._callbacks.onKeyPress) do
@@ -394,6 +145,26 @@ function executeBot(config, storage, panel, msgCallback)
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
}
}

View File

@@ -0,0 +1,101 @@
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 callbackData = {}
table.insert(context._callbacks[callbackType], function(...)
if not callbackData.delay or callbackData.delay < context.now then
context._currentExecution = callbackData
callback(...)
context._currentExecution = nil
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
-- 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
-- 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()
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)
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)
context.onCreatureHealthPercentChange(function(creature, healthPercent)
if creature == context.player then
callback(healthPercent)
end
end)
end

View File

@@ -0,0 +1,136 @@
local context = G.botContext
-- MAIN BOT FUNCTION
-- macro(timeout, callback)
-- macro(timeout, name, callback)
-- macro(timeout, name, hotkey, callback)
-- macro(timeout, name, hotkey, callback, parent)
context.macro = function(timeout, name, hotkey, callback, parent)
if not parent then
parent = context.panel
end
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
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 hotkey:len() > 0 then
hotkey = retranslateKeyComboDesc(hotkey)
end
local switch = nil
if name:len() > 0 then
if context.storage._macros[name] == nil then
context.storage._macros[name] = true
end
switch = context._addMacroSwitch(name, hotkey, parent)
end
table.insert(context._macros, {
timeout = timeout,
name = name,
lastExecution = context.now,
hotkey = hotkey,
switch = switch
})
local macroData = context._macros[#context._macros]
macroData.callback = function()
if not macroData.delay or macroData.delay < context.now then
context._currentExecution = macroData
callback()
context._currentExecution = nil
return true
end
end
return macroData
end
-- hotkey(keys, callback)
-- hotkey(keys, name, callback)
-- hotkey(keys, name, callback, parent)
context.hotkey = function(keys, name, callback, single, parent)
if not parent then
parent = context.panel
end
if type(name) == 'function' then
callback = name
name = ""
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 hotkeyData = context._hotkeys[keys]
hotkeyData.callback = function()
if not hotkeyData.delay or hotkeyData.delay < context.now then
context._currentExecution = hotkeyData
callback()
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, true, parent)
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

View File

@@ -0,0 +1,39 @@
local context = G.botContext
context.zoomIn = function() modules.game_interface.getMapPanel():zoomIn() end
context.zoomOut = function() modules.game_interface.getMapPanel():zoomOut() end
context.getSpectators = function(multifloor)
if multifloor ~= true then
multifloor = false
end
return g_map.getSpectators(context.player:getPosition(), multifloor)
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

View File

@@ -0,0 +1,98 @@
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.autoWalk = function(destination) return context.player:autoWalk(destination) 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.say = g_game.talk
context.talk = g_game.talk
context.saySpell = function(text, lastSpellTimeout)
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.talkPrivate = g_game.talkPrivate
context.sayPrivate = g_game.talkPrivate
context.use = g_game.useInventoryItem
context.usewith = g_game.useInventoryItemWith
context.useWith = g_game.useInventoryItemWith
context.findItem = g_game.findItemInContainers
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.ping = g_game.getPing

View File

@@ -0,0 +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

View File

@@ -0,0 +1,33 @@
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

View File

@@ -0,0 +1,3 @@
local context = G.botContext
context.test = function() return context.info("test") end

View File

@@ -0,0 +1,4 @@
local context = G.botContext
context.encode = function(data) return json.encode(data) end
context.decode = function(text) local status, result = pcall(function() return json.decode(text) end) if status then return result end return {} end

View File

@@ -0,0 +1,95 @@
local context = G.botContext
context.setupUI = function(otml, parent)
if parent == nil then
parent = context.panel
end
local widget = g_ui.loadUIFromString(otml, parent)
return widget
end
context.addTab = function(name)
context.tabs:setOn(true)
return context.tabs:addTab(name, g_ui.createWidget('BotPanel')).tabPanel
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

View File

@@ -0,0 +1,326 @@
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)
context.macro(500, "Auto ManaShield", nil, function()
if not context.hasManaShield() then
if context.saySpell("utamo vita", 1000) then
context.delay(5000)
end
end
end, parent)
end
Panels.AntiParalyze = function(parent)
context.macro(500, "Anti Paralyze", nil, function()
if not context.isParalyzed() and context.storage.autoHasteText:len() > 0 then
if context.saySpell(context.storage.autoAntiParalyzeText, 2500) then
context.delay(5000)
end
end
end, parent)
context.addTextEdit("autoHasteText", 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 = context.setupUI([[
Panel
height: 70
margin-top: 2
Label
id: info
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
text: Auto Healing
text-align: center
Label
id: label
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin: 0 5 0 5
text-align: center
HorizontalScrollBar
id: scroll1
anchors.left: label.left
anchors.right: label.horizontalCenter
anchors.top: label.bottom
margin-top: 5
margin-right: 2
minimum: 0
maximum: 100
step: 1
HorizontalScrollBar
id: scroll2
anchors.left: label.horizontalCenter
anchors.right: label.right
anchors.top: label.bottom
margin-top: 5
margin-left: 2
minimum: 0
maximum: 100
step: 1
BotTextEdit
id: text
anchors.left: parent.left
anchors.right: parent.right
anchors.top: scroll1.bottom
]], parent)
ui:setId(panelName)
ui.text.onTextChange = function(widget, text)
context.storage["healthText" .. panelId] = text
end
ui.text:setText(context.storage["healthText" .. panelId] or "exura")
local updateText = function()
ui.label:setText("" .. (context.storage["healthPercentMin" .. panelId] or "") .. "% <= hp <= " .. (context.storage["healthPercentMax" .. panelId] or "") .. "%")
end
ui.scroll1.onValueChange = function(scroll, value)
context.storage["healthPercentMin" .. panelId] = value
updateText()
end
ui.scroll2.onValueChange = function(scroll, value)
context.storage["healthPercentMax" .. panelId] = value
updateText()
end
ui.scroll1:setValue(context.storage["healthPercentMin" .. panelId] or 20)
ui.scroll2:setValue(context.storage["healthPercentMax" .. panelId] or 60)
context.macro(25, function()
if context.storage["healthText" .. panelId]:len() > 0 and context.storage["healthPercentMin" .. panelId] <= context.hppercent() and context.hppercent() <= context.storage["healthPercentMax" .. panelId] then
if context.saySpell(context.storage["healthText" .. panelId], 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 = context.setupUI([[
Panel
height: 55
margin-top: 2
Label
id: info
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
text: Auto Healing
text-align: center
BotItem
id: item
anchors.left: parent.left
anchors.top: prev.bottom
margin-top: 3
Label
id: label
anchors.left: prev.right
anchors.right: parent.right
anchors.top: prev.top
margin: 0 5 0 5
text-align: center
HorizontalScrollBar
id: scroll1
anchors.left: label.left
anchors.right: label.horizontalCenter
anchors.top: label.bottom
margin-top: 5
margin-right: 2
minimum: 0
maximum: 100
step: 1
HorizontalScrollBar
id: scroll2
anchors.left: label.horizontalCenter
anchors.right: label.right
anchors.top: label.bottom
margin-top: 5
margin-left: 2
minimum: 0
maximum: 100
step: 1
]], parent)
ui:setId(panelName)
ui.item.onItemChange = function(widget)
cp("item change")
context.storage["healthItem" .. panelId] = widget:getItemId()
end
ui.item:setItemId(context.storage["healthItem" .. panelId] or 266)
local updateText = function()
ui.label:setText("" .. (context.storage["healthItemPercentMin" .. panelId] or "") .. "% <= hp <= " .. (context.storage["healthItemPercentMax" .. panelId] or "") .. "%")
end
ui.scroll1.onValueChange = function(scroll, value)
context.storage["healthItemPercentMin" .. panelId] = value
updateText()
end
ui.scroll2.onValueChange = function(scroll, value)
context.storage["healthItemPercentMax" .. panelId] = value
updateText()
end
ui.scroll1:setValue(context.storage["healthItemPercentMin" .. panelId] or 20)
ui.scroll2:setValue(context.storage["healthItemPercentMax" .. panelId] or 60)
context.macro(25, function()
if context.storage["healthItem" .. panelId] > 0 and context.storage["healthItemPercentMin" .. panelId] <= context.hppercent() and context.hppercent() <= context.storage["healthItemPercentMax" .. panelId] then
context.useWith(context.storage["healthItem" .. panelId], context.player)
context.delay(300)
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 = context.setupUI([[
Panel
height: 55
margin-top: 2
Label
id: info
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
text: Auto Mana
text-align: center
BotItem
id: item
anchors.left: parent.left
anchors.top: prev.bottom
margin-top: 3
Label
id: label
anchors.left: prev.right
anchors.right: parent.right
anchors.top: prev.top
margin: 0 5 0 5
text-align: center
HorizontalScrollBar
id: scroll1
anchors.left: label.left
anchors.right: label.horizontalCenter
anchors.top: label.bottom
margin-top: 5
margin-right: 2
minimum: 0
maximum: 100
step: 1
HorizontalScrollBar
id: scroll2
anchors.left: label.horizontalCenter
anchors.right: label.right
anchors.top: label.bottom
margin-top: 5
margin-left: 2
minimum: 0
maximum: 100
step: 1
]], parent)
ui:setId(panelName)
ui.item.onItemChange = function(widget)
context.storage["manaItem" .. panelId] = widget:getItemId()
end
ui.item:setItemId(context.storage["manaItem" .. panelId] or 268)
local updateText = function()
ui.label:setText("" .. (context.storage["manaItemPercentMin" .. panelId] or "") .. "% <= mana <= " .. (context.storage["manaItemPercentMax" .. panelId] or "") .. "%")
end
ui.scroll1.onValueChange = function(scroll, value)
context.storage["manaItemPercentMin" .. panelId] = value
updateText()
end
ui.scroll2.onValueChange = function(scroll, value)
context.storage["manaItemPercentMax" .. panelId] = value
updateText()
end
ui.scroll1:setValue(context.storage["manaItemPercentMin" .. panelId] or 20)
ui.scroll2:setValue(context.storage["manaItemPercentMax" .. panelId] or 60)
context.macro(25, function()
if context.storage["manaItem" .. panelId] > 0 and context.storage["manaItemPercentMin" .. panelId] <= context.manapercent() and context.manapercent() <= context.storage["manaItemPercentMax" .. panelId] then
context.useWith(context.storage["manaItem" .. panelId], context.player)
context.delay(300)
end
end)
end
Panels.ManaItem = Panels.Mana
Panels.Turning = function(parent)
context.macro(1000, "Turning / AntiIdle", nil, function()
context.turn(math.random(1, 4))
end, parent)
end
Panels.AntiIdle = Panels.Turning

View File

@@ -619,22 +619,36 @@ function addTabText(text, speaktype, tab, creatureName)
local panel = consoleTabBar:getTabPanel(tab)
local consoleBuffer = panel:getChildById('consoleBuffer')
local label = g_ui.createWidget('ConsoleLabel', consoleBuffer)
local label = nil
if consoleBuffer:getChildCount() > MAX_LINES then
label = consoleBuffer:getFirstChild()
consoleBuffer:moveChildToIndex(label, consoleBuffer:getChildCount())
end
if not label then
label = g_ui.createWidget('ConsoleLabel', consoleBuffer)
end
label:setId('consoleLabel' .. consoleBuffer:getChildCount())
label:setText(text)
label:setColor(speaktype.color)
consoleTabBar:blinkTab(tab)
-- Overlay for consoleBuffer which shows highlighted words only
-- Overlay for consoleBuffer which shows highlighted words only
local labelHighlight = label:getChildById("consoleLabelHighlight")
if labelHighlight then
labelHighlight:setText("")
end
if speaktype.npcChat and (g_game.getCharacterName() ~= creatureName or g_game.getCharacterName() == 'Account Manager') then
local highlightData = getHighlightedText(text)
if #highlightData > 0 then
local labelHighlight = g_ui.createWidget('ConsolePhantomLabel', label)
labelHighlight:fill('parent')
labelHighlight:setId('consoleLabelHighlight' .. consoleBuffer:getChildCount())
labelHighlight:setColor("#1f9ffe")
if not labelHighlight then
labelHighlight = g_ui.createWidget('ConsolePhantomLabel', label)
labelHighlight:fill('parent')
labelHighlight:setId('consoleLabelHighlight')
labelHighlight:setColor("#1f9ffe")
end
-- Remove the curly braces
for i = 1, #highlightData / 3 do
@@ -768,12 +782,6 @@ function addTabText(text, speaktype, tab, creatureName)
return true
end
if consoleBuffer:getChildCount() > MAX_LINES then
local child = consoleBuffer:getFirstChild()
clearSelection(consoleBuffer)
child:destroy()
end
end
function removeTabLabelByName(tab, name)
@@ -1499,6 +1507,12 @@ function online()
defaultTab = addTab(tr('Default'), true)
serverTab = addTab(tr('Server Log'), false)
if g_game.getClientVersion() >= 820 then
local tab = addTab("NPCs", false)
tab.npcChat = true
end
if g_game.getClientVersion() < 862 then
local gameRootPanel = modules.game_interface.getRootPanel()
g_keyboard.bindKeyDown('Ctrl+R', openPlayerReportRuleViolationWindow, gameRootPanel)

View File

@@ -12,6 +12,7 @@ function updateFeatures(version)
-- you can add custom features here, list of them in modules\gamelib\const.lua
g_game.enableFeature(GameBot)
--g_game.enableFeature(GameMinimapLimitedToSingleFloor)
--g_game.enableFeature(GameSpritesAlphaChannel)
if(version >= 770) then
g_game.enableFeature(GameLooktypeU16);

View File

@@ -402,7 +402,7 @@ end
function prepareKeyCombo(keyCombo, repeated)
local hotKey = hotkeyList[keyCombo]
if keyCombo:lower():find("ctrl") or not hotKey or (hotKey.itemId == nil and (not hotKey.value or #hotKey.value == 0)) then
if (keyCombo:lower():find("ctrl") and not hotKey) or (hotKey and hotKey.itemId == nil and (not hotKey.value or #hotKey.value == 0)) then
keyCombo = keyCombo:gsub("Ctrl%+", "")
keyCombo = keyCombo:gsub("ctrl%+", "")
hotKey = hotkeyList[keyCombo]

View File

@@ -531,9 +531,13 @@ function createThingMenu(menuPosition, lookThing, useThing, creatureThing)
end
end
if g_game.getFeature(GameBot) and useThing then
if g_game.getFeature(GameBot) and useThing and useThing:isItem() then
menu:addSeparator()
menu:addOption("ID: " .. useThing:getId())
if useThing:getSubType() > 1 then
menu:addOption("ID: " .. useThing:getId() .. " SubType: " .. useThing:getSubType())
else
menu:addOption("ID: " .. useThing:getId())
end
end
menu:display(menuPosition)

View File

@@ -4,7 +4,7 @@ Module
author: OTClient team
website: https://github.com/edubart/otclient
sandboxed: true
scripts: [ widgets/uigamemap, widgets/uiitem, gameinterface ]
scripts: [ widgets/uigamemap, gameinterface ]
load-later:
- game_hotkeys
- game_questlog
@@ -32,6 +32,8 @@ Module
- game_unjustifiedpoints
- game_walking
- game_shop
- game_itemselector
- game_textedit
- game_bot
@onLoad: init()
@onUnload: terminate()

View File

@@ -200,6 +200,7 @@ function refresh()
if player then
onSoulChange(player, player:getSoul())
onFreeCapacityChange(player, player:getFreeCapacity())
onStatesChange(player, player:getStates(), 0)
end
--purseButton:setVisible(g_game.getFeature(GamePurseSlot))

View File

@@ -0,0 +1,73 @@
local activeWindow
function init()
g_ui.importStyle('itemselector')
connect(g_game, { onGameEnd = destroyWindow })
end
function terminate()
disconnect(g_game, { onGameEnd = destroyWindow })
destroyWindow()
end
function destroyWindow()
if activeWindow then
activeWindow:destroy()
activeWindow = nil
end
end
function show(itemWidget)
if not itemWidget then
return
end
if activeWindow then
destroyWindow()
end
local window = g_ui.createWidget('ItemSelectorWindow', rootWidget)
local destroy = function()
window:destroy()
if window == activeWindow then
activeWindow = nil
end
end
local doneFunc = function()
itemWidget:setItemId(window.item:getItemId())
itemWidget:setItemCount(window.item:getItemCount())
if itemWidget.onItemChange then
itemWidget:onItemChange()
end
destroy()
end
window.okButton.onClick = doneFunc
window.cancelButton.onClick = destroy
window.onEnter = doneFunc
window.onEscape = destroy
window.item:setItemId(itemWidget:getItemId())
window.item:setItemCount(itemWidget:getItemCount())
window.itemId:setValue(itemWidget:getItemId())
if itemWidget:getItemCount() > 1 then
window.itemCount:setValue(itemWidget:getItemCount())
end
window.itemId.onValueChange = function(widget, value)
window.item:setItemId(value)
end
window.itemCount.onValueChange = function(widget, value)
window.item:setItemCount(value)
end
activeWindow = window
activeWindow:raise()
activeWindow:focus()
end
function hide()
destroyWindow()
end

View File

@@ -0,0 +1,10 @@
Module
name: game_itemselector
description: Allow to select item
author: OTClientV8
website: https://github.com/OTCv8/otclientv8
sandboxed: true
dependencies: [ game_interface ]
scripts: [ itemselector ]
@onLoad: init()
@onUnload: terminate()

View File

@@ -0,0 +1,65 @@
ItemSelectorWindow < MainWindow
id: itemSelector
size: 260 120
!text: tr("Select item")
Item
id: item
virtual: true
size: 32 32
margin-top: 10
anchors.top: parent.top
anchors.left: parent.left
SpinBox
id: itemId
anchors.top: parent.top
anchors.left: prev.right
margin-top: 15
margin-left: 5
padding-left: 5
width: 70
minimum: 1
maximum: 999999999
focusable: true
Label
anchors.top: parent.top
anchors.left: prev.left
anchors.right: prev.right
text-align: center
!text: tr("Item ID")
SpinBox
id: itemCount
anchors.top: parent.top
anchors.left: prev.right
margin-top: 15
margin-left: 5
padding-left: 5
width: 120
minimum: 1
maximum: 100
focusable: true
Label
anchors.top: parent.top
anchors.left: prev.left
anchors.right: prev.right
text-align: center
!text: tr("Count / SubType")
Button
id: okButton
!text: tr('Ok')
anchors.bottom: parent.bottom
anchors.right: next.left
margin-right: 10
width: 60
Button
id: cancelButton
!text: tr('Cancel')
anchors.bottom: parent.bottom
anchors.right: parent.right
width: 60

View File

@@ -0,0 +1,56 @@
local activeWindow
function init()
g_ui.importStyle('textedit')
connect(g_game, { onGameEnd = destroyWindow })
end
function terminate()
disconnect(g_game, { onGameEnd = destroyWindow })
destroyWindow()
end
function destroyWindow()
if activeWindow then
activeWindow:destroy()
activeWindow = nil
end
end
function show(widget)
if not widget then
return
end
if activeWindow then
destroyWindow()
end
local window = g_ui.createWidget('TextEditWindow', rootWidget)
local destroy = function()
window:destroy()
if window == activeWindow then
activeWindow = nil
end
end
local doneFunc = function()
widget:setText(window.text:getText())
destroy()
end
window.okButton.onClick = doneFunc
window.cancelButton.onClick = destroy
window.onEnter = doneFunc
window.onEscape = destroy
window.text:setText(widget:getText())
activeWindow = window
activeWindow:raise()
activeWindow:focus()
end
function hide()
destroyWindow()
end

View File

@@ -0,0 +1,10 @@
Module
name: game_textedit
description: Allow to edit text
author: OTClientV8
website: https://github.com/OTCv8/otclientv8
sandboxed: true
dependencies: [ game_interface ]
scripts: [ textedit ]
@onLoad: init()
@onUnload: terminate()

View File

@@ -0,0 +1,25 @@
TextEditWindow < MainWindow
id: textedit
size: 260 105
!text: tr("Edit text")
TextEdit
id: text
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Button
id: okButton
!text: tr('Ok')
anchors.bottom: parent.bottom
anchors.right: next.left
margin-right: 10
width: 60
Button
id: cancelButton
!text: tr('Cancel')
anchors.bottom: parent.bottom
anchors.right: parent.right
width: 60

View File

@@ -0,0 +1,133 @@
function UIItem:onDragEnter(mousePos)
if self:isVirtual() then return false end
local item = self:getItem()
if not item then return false end
self:setBorderWidth(1)
self.currentDragThing = item
g_mouse.pushCursor('target')
return true
end
function UIItem:onDragLeave(droppedWidget, mousePos)
if self:isVirtual() then return false end
self.currentDragThing = nil
g_mouse.popCursor('target')
self:setBorderWidth(0)
self.hoveredWho = nil
return true
end
function UIItem:onDrop(widget, mousePos, forced)
if not self:canAcceptDrop(widget, mousePos) and not forced then return false end
local item = widget.currentDragThing
if not item or not item:isItem() then return false end
if self.selectable then
self:setItemId(item:getId())
self:setItemCount(item:getCount())
if item:getSubType() > 1 then
self:setItemSubType(item:getSubType())
end
if self.onItemChange then
self:onItemChange()
end
return
end
local toPos = self.position
local itemPos = item:getPosition()
if itemPos.x == toPos.x and itemPos.y == toPos.y and itemPos.z == toPos.z then return false end
if item:getCount() > 1 then
modules.game_interface.moveStackableItem(item, toPos)
else
g_game.move(item, toPos, 1)
end
self:setBorderWidth(0)
return true
end
function UIItem:onDestroy()
if self == g_ui.getDraggingWidget() and self.hoveredWho then
self.hoveredWho:setBorderWidth(0)
end
if self.hoveredWho then
self.hoveredWho = nil
end
end
function UIItem:onHoverChange(hovered)
UIWidget.onHoverChange(self, hovered)
if self:isVirtual() or not self:isDraggable() then return end
local draggingWidget = g_ui.getDraggingWidget()
if draggingWidget and self ~= draggingWidget then
local gotMap = draggingWidget:getClassName() == 'UIGameMap'
local gotItem = draggingWidget:getClassName() == 'UIItem' and not draggingWidget:isVirtual()
if hovered and (gotItem or gotMap) then
self:setBorderWidth(1)
draggingWidget.hoveredWho = self
else
self:setBorderWidth(0)
draggingWidget.hoveredWho = nil
end
end
end
function UIItem:onMouseRelease(mousePosition, mouseButton)
if self.cancelNextRelease then
self.cancelNextRelease = false
return true
end
if self:isVirtual() then return false end
local item = self:getItem()
if not item or not self:containsPoint(mousePosition) then return false end
if modules.client_options.getOption('classicControl') and
((g_mouse.isPressed(MouseLeftButton) and mouseButton == MouseRightButton) or
(g_mouse.isPressed(MouseRightButton) and mouseButton == MouseLeftButton)) then
g_game.look(item)
self.cancelNextRelease = true
return true
elseif modules.game_interface.processMouseAction(mousePosition, mouseButton, nil, item, item, nil, nil) then
return true
end
return false
end
function UIItem:canAcceptDrop(widget, mousePos)
if not self.selectable and (self:isVirtual() or not self:isDraggable()) then return false end
if not widget or not widget.currentDragThing then return false end
local children = rootWidget:recursiveGetChildrenByPos(mousePos)
for i=1,#children do
local child = children[i]
if child == self then
return true
elseif not child:isPhantom() then
return false
end
end
error('Widget ' .. self:getId() .. ' not in drop list.')
return false
end
function UIItem:onClick(mousePos)
if not self.selectable then
return
end
if modules.game_itemselector then
modules.game_itemselector.show(self)
end
end

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.