mirror of
https://github.com/OTCv8/otclientv8.git
synced 2026-01-20 17:36:22 +01:00
Version 0.999 BETA - a lot of bug fixes, improvments and more advanced bot
This commit is contained in:
11
README.md
11
README.md
@@ -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
|
||||
|
||||
|
||||
@@ -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 = ""
|
||||
|
||||
@@ -87,6 +87,13 @@ MainWindow
|
||||
DebugText
|
||||
id: luaCallback
|
||||
text: -
|
||||
|
||||
DebugLabel
|
||||
!text: tr('Widgets')
|
||||
|
||||
DebugText
|
||||
id: widgetsInfo
|
||||
text: -
|
||||
|
||||
DebugLabel
|
||||
!text: tr('Slow main functions')
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
]=]},
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
101
modules/game_bot/functions/callbacks.lua
Normal file
101
modules/game_bot/functions/callbacks.lua
Normal 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
|
||||
136
modules/game_bot/functions/main.lua
Normal file
136
modules/game_bot/functions/main.lua
Normal 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
|
||||
39
modules/game_bot/functions/map.lua
Normal file
39
modules/game_bot/functions/map.lua
Normal 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
|
||||
98
modules/game_bot/functions/player.lua
Normal file
98
modules/game_bot/functions/player.lua
Normal 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
|
||||
32
modules/game_bot/functions/player_conditions.lua
Normal file
32
modules/game_bot/functions/player_conditions.lua
Normal 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
|
||||
33
modules/game_bot/functions/player_inventory.lua
Normal file
33
modules/game_bot/functions/player_inventory.lua
Normal 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
|
||||
3
modules/game_bot/functions/test.lua
Normal file
3
modules/game_bot/functions/test.lua
Normal file
@@ -0,0 +1,3 @@
|
||||
local context = G.botContext
|
||||
|
||||
context.test = function() return context.info("test") end
|
||||
4
modules/game_bot/functions/tools.lua
Normal file
4
modules/game_bot/functions/tools.lua
Normal 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
|
||||
95
modules/game_bot/functions/ui.lua
Normal file
95
modules/game_bot/functions/ui.lua
Normal 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
|
||||
326
modules/game_bot/panels/basic.lua
Normal file
326
modules/game_bot/panels/basic.lua
Normal 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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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))
|
||||
|
||||
73
modules/game_itemselector/itemselector.lua
Normal file
73
modules/game_itemselector/itemselector.lua
Normal 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
|
||||
10
modules/game_itemselector/itemselector.otmod
Normal file
10
modules/game_itemselector/itemselector.otmod
Normal 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()
|
||||
65
modules/game_itemselector/itemselector.otui
Normal file
65
modules/game_itemselector/itemselector.otui
Normal 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
|
||||
56
modules/game_textedit/textedit.lua
Normal file
56
modules/game_textedit/textedit.lua
Normal 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
|
||||
10
modules/game_textedit/textedit.otmod
Normal file
10
modules/game_textedit/textedit.otmod
Normal 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()
|
||||
25
modules/game_textedit/textedit.otui
Normal file
25
modules/game_textedit/textedit.otui
Normal 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
|
||||
133
modules/gamelib/ui/uiitem.lua
Normal file
133
modules/gamelib/ui/uiitem.lua
Normal 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
|
||||
BIN
otclient_dx.exe
BIN
otclient_dx.exe
Binary file not shown.
BIN
otclient_gl.exe
BIN
otclient_gl.exe
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user