mirror of
https://github.com/OTCv8/otclientv8.git
synced 2025-04-29 10:49:21 +02:00
Version 1.8
This commit is contained in:
parent
2a10e65ec0
commit
26c347d2bc
1
init.lua
1
init.lua
@ -20,6 +20,7 @@ Servers = {
|
||||
-- OTClientV8ClassicWithFeatures = "otclient.ovh:7171:1099:25:30:80:90",
|
||||
-- OTClientV8Classic = "otclient.ovh:7171:1099"
|
||||
}
|
||||
USE_NEW_ENERGAME = false -- uses entergamev2 based on websockets instead of entergame
|
||||
ALLOW_CUSTOM_SERVERS = true -- if true it shows option ANOTHER on server list
|
||||
-- CONFIG END
|
||||
|
||||
|
@ -16,6 +16,7 @@ Module
|
||||
- client_background
|
||||
- client_options
|
||||
- client_entergame
|
||||
- client_entergamev2
|
||||
- client_terminal
|
||||
- client_stats
|
||||
- client_news
|
||||
|
@ -176,6 +176,7 @@ end
|
||||
|
||||
-- public functions
|
||||
function CharacterList.init()
|
||||
if USE_NEW_ENERGAME then return end
|
||||
connect(g_game, { onLoginError = onGameLoginError })
|
||||
connect(g_game, { onLoginToken = onGameLoginToken })
|
||||
connect(g_game, { onUpdateNeeded = onGameUpdateNeeded })
|
||||
@ -191,6 +192,7 @@ function CharacterList.init()
|
||||
end
|
||||
|
||||
function CharacterList.terminate()
|
||||
if USE_NEW_ENERGAME then return end
|
||||
disconnect(g_game, { onLoginError = onGameLoginError })
|
||||
disconnect(g_game, { onLoginToken = onGameLoginToken })
|
||||
disconnect(g_game, { onUpdateNeeded = onGameUpdateNeeded })
|
||||
|
@ -186,6 +186,7 @@ end
|
||||
|
||||
-- public functions
|
||||
function EnterGame.init()
|
||||
if USE_NEW_ENERGAME then return end
|
||||
enterGame = g_ui.displayUI('entergame')
|
||||
|
||||
serverSelectorPanel = enterGame:getChildById('serverSelectorPanel')
|
||||
@ -246,6 +247,7 @@ function EnterGame.init()
|
||||
end
|
||||
|
||||
function EnterGame.terminate()
|
||||
if USE_NEW_ENERGAME then return end
|
||||
g_keyboard.unbindKeyDown('Ctrl+G')
|
||||
|
||||
enterGame:destroy()
|
||||
|
@ -1,50 +0,0 @@
|
||||
StaticWindow
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
margin-right: 20
|
||||
id: newLoginPanel
|
||||
width: 240
|
||||
height: 320
|
||||
!text: tr('Quick Login & Registration')
|
||||
|
||||
UIButton
|
||||
id: qrcode
|
||||
width: 200
|
||||
height: 200
|
||||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
image-fixed-ratio: true
|
||||
image-smooth: false
|
||||
margin-top: 5
|
||||
|
||||
UIButton
|
||||
id: quathlogo
|
||||
width: 66
|
||||
height: 40
|
||||
anchors.verticalCenter: prev.verticalCenter
|
||||
anchors.horizontalCenter: prev.horizontalCenter
|
||||
image-fixed-ratio: true
|
||||
image-smooth: false
|
||||
image-source: /images/ui/qauth
|
||||
|
||||
Label
|
||||
anchors.top: qrcode.bottom
|
||||
anchors.left: qrcode.left
|
||||
anchors.right: qrcode.right
|
||||
text-align: center
|
||||
text-auto-resize: true
|
||||
!text: tr("Scan or click QR code\nto register or login")
|
||||
height: 40
|
||||
margin-top: 10
|
||||
margin-bottom: 5
|
||||
|
||||
Button
|
||||
anchors.top: prev.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
text-align: center
|
||||
!text: tr("Click to get PC/Android/iOS app")
|
||||
height: 20
|
||||
margin-top: 10
|
||||
color: #FFFFFF
|
||||
@onClick: g_platform.openUrl("http://qauth.co")
|
5
modules/client_entergamev2/entergamev2.lua
Normal file
5
modules/client_entergamev2/entergamev2.lua
Normal file
@ -0,0 +1,5 @@
|
||||
function init()
|
||||
end
|
||||
|
||||
function terminate()
|
||||
end
|
10
modules/client_entergamev2/entergamev2.otmod
Normal file
10
modules/client_entergamev2/entergamev2.otmod
Normal file
@ -0,0 +1,10 @@
|
||||
Module
|
||||
name: client_entergamev2
|
||||
description: Manages enter game and character list windows
|
||||
author: otclient.ovh
|
||||
website: http://otclient.ovh
|
||||
sandboxed: true
|
||||
scripts: [ entergamev2 ]
|
||||
@onLoad: init()
|
||||
@onUnload: terminate()
|
||||
|
@ -17,8 +17,8 @@ Panel
|
||||
!tooltip: tr('Disable chat and allow walk using WSAD keys')
|
||||
|
||||
OptionCheckBox
|
||||
id: extentedPreWalking
|
||||
!text: tr('Enable smooth walking (DASH)')
|
||||
id: dash
|
||||
!text: tr('Enable fast walking (DASH)')
|
||||
!tooltip: tr('Allows to execute next move without server confirmation of previous one')
|
||||
|
||||
OptionCheckBox
|
||||
|
@ -6,7 +6,7 @@ local defaultOptions = {
|
||||
classicView = true,
|
||||
classicControl = true,
|
||||
smartWalk = false,
|
||||
extentedPreWalking = true,
|
||||
dash = false,
|
||||
autoChaseOverride = true,
|
||||
showStatusMessagesInConsole = true,
|
||||
showEventMessagesInConsole = true,
|
||||
@ -292,7 +292,7 @@ function setOption(key, value, force)
|
||||
addEvent(function()
|
||||
modules.game_interface.updateStretchShrink()
|
||||
end)
|
||||
elseif key == 'extentedPreWalking' then
|
||||
elseif key == 'dash' then
|
||||
if value then
|
||||
g_game.setMaxPreWalkingSteps(2)
|
||||
else
|
||||
|
@ -25,7 +25,7 @@ end
|
||||
|
||||
function UIWindow:onDragEnter(mousePos)
|
||||
if self.static then
|
||||
return
|
||||
return false
|
||||
end
|
||||
self:breakAnchors()
|
||||
self.movingReference = { x = mousePos.x - self:getX(), y = mousePos.y - self:getY() }
|
||||
|
@ -23,6 +23,7 @@ function init()
|
||||
g_ui.importStyle("ui/basic.otui")
|
||||
g_ui.importStyle("ui/panels.otui")
|
||||
g_ui.importStyle("ui/config.otui")
|
||||
g_ui.importStyle("ui/icons.otui")
|
||||
|
||||
connect(g_game, {
|
||||
onGameStart = online,
|
||||
@ -89,14 +90,19 @@ function clear()
|
||||
|
||||
for i, socket in pairs(botWebSockets) do
|
||||
g_http.cancel(socket)
|
||||
botWebSockets[i] = nil
|
||||
end
|
||||
botWebSockets = {}
|
||||
|
||||
for i, widget in pairs(g_ui.getRootWidget():getChildren()) do
|
||||
if widget.botWidget then
|
||||
widget:destroy()
|
||||
end
|
||||
end
|
||||
for i, widget in pairs(modules.game_interface.gameMapPanel:getChildren()) do
|
||||
if widget.botWidget then
|
||||
widget:destroy()
|
||||
end
|
||||
end
|
||||
|
||||
local gameMapPanel = modules.game_interface.getMapPanel()
|
||||
if gameMapPanel then
|
||||
@ -149,7 +155,8 @@ function refresh()
|
||||
end
|
||||
configList:setCurrentOption(settings[index].config)
|
||||
if configList:getCurrentOption().text ~= settings[index].config then
|
||||
settings[index].enabled = false
|
||||
settings[index].config = configList:getCurrentOption().text
|
||||
settings[index].enabled = false
|
||||
end
|
||||
|
||||
enableButton:setOn(settings[index].enabled)
|
||||
|
@ -1,75 +0,0 @@
|
||||
ConfigTabBar < MoveableTabBar
|
||||
height: 22
|
||||
|
||||
ConfigTabBarButton < MoveableTabBarButton
|
||||
height: 22
|
||||
padding: 15
|
||||
|
||||
ConfigTabBarPanel < MoveableTabBarPanel
|
||||
|
||||
MainWindow
|
||||
id: configWindow
|
||||
size: 650 497
|
||||
!text: tr("Config editor")
|
||||
|
||||
Label
|
||||
id: description
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
text-auto-resize: true
|
||||
text-align: left
|
||||
text-wrap: true
|
||||
!text: tr("For more informations how to edit config, click 'Documentation' button")
|
||||
|
||||
ConfigTabBar
|
||||
id: configTab
|
||||
anchors.left: parent.left
|
||||
anchors.top: prev.bottom
|
||||
anchors.right: parent.right
|
||||
margin-top: 5
|
||||
tab-spacing: 2
|
||||
movable: false
|
||||
|
||||
MultilineTextEdit
|
||||
id: text
|
||||
anchors.top: textScroll.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: textScroll.left
|
||||
anchors.bottom: textScroll.bottom
|
||||
vertical-scrollbar: textScroll
|
||||
text-wrap: true
|
||||
|
||||
VerticalScrollBar
|
||||
id: textScroll
|
||||
anchors.top: configTab.bottom
|
||||
anchors.bottom: okButton.top
|
||||
anchors.right: parent.right
|
||||
margin-bottom: 10
|
||||
step: 16
|
||||
pixels-scroll: true
|
||||
|
||||
Button
|
||||
id: documentationButton
|
||||
!text: tr('Documentation')
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
width: 150
|
||||
@onClick: scheduleEvent(function() g_platform.openUrl("https://github.com/OTCv8/otclientv8_bot") end, 50)
|
||||
|
||||
Button
|
||||
id: okButton
|
||||
!text: tr('Ok')
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: next.left
|
||||
margin-right: 10
|
||||
width: 60
|
||||
@onClick: modules.game_bot.saveEditedConfig()
|
||||
|
||||
Button
|
||||
id: cancelButton
|
||||
!text: tr('Cancel')
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
width: 60
|
||||
@onClick: self:getParent():hide()
|
38
modules/game_bot/default_config/icons.lua
Normal file
38
modules/game_bot/default_config/icons.lua
Normal file
@ -0,0 +1,38 @@
|
||||
|
||||
|
||||
addIcon("dancing", {outfit={mount=0,feet=0,legs=0,body=176,type=128,auxType=0,addons=3,head=48}, hotkey="F5", text="dance"}, macro(100, "dance", function()
|
||||
turn(math.random(0,3))
|
||||
end))
|
||||
|
||||
addIcon("ctrl", {outfit={mount=0,feet=10,legs=10,body=176,type=129,auxType=0,addons=3,head=48}, text="press ctrl to move icon"}, function(widget, enabled)
|
||||
if enabled then
|
||||
info("icon on")
|
||||
else
|
||||
info("icon off")
|
||||
end
|
||||
end)
|
||||
|
||||
addIcon("mount", {outfit={mount=848,feet=10,legs=10,body=176,type=129,auxType=0,addons=3,head=48}}, function(widget, enabled)
|
||||
if enabled then
|
||||
info("icon mount on")
|
||||
else
|
||||
info("icon mount off")
|
||||
end
|
||||
end)
|
||||
|
||||
addIcon("mount 2", {outfit={mount=849,feet=10,legs=10,body=176,type=140,auxType=0,addons=3,head=48}, switchable=false}, function(widget, enabled)
|
||||
info("icon mount 2 pressed")
|
||||
end)
|
||||
|
||||
addIcon("item", {item=3380, hotkey="F6", switchable=false}, function(widget, enabled)
|
||||
info("icon clicked")
|
||||
end)
|
||||
|
||||
addIcon("item2", {item={id=3043, count=100}, switchable=true}, function(widget, enabled)
|
||||
info("icon 2 clicked")
|
||||
end)
|
||||
|
||||
addIcon("text", {text="text\nonly\nicon", switchable=true}, function(widget, enabled)
|
||||
info("icon with text clicked")
|
||||
end)
|
||||
|
@ -1,305 +0,0 @@
|
||||
botDefaultConfig = {
|
||||
configs = {
|
||||
{name = "Default", script = [=[
|
||||
--Default
|
||||
--IMPORTANT
|
||||
--In 1st config (default) editions are not saved, just select and edit other config
|
||||
|
||||
--#main
|
||||
|
||||
--#panels
|
||||
|
||||
local healTab = addTab("HP")
|
||||
local batTab = addTab("Batt")
|
||||
local caveTab = addTab("Cave")
|
||||
local toolsTab = addTab("Tools")
|
||||
|
||||
Panels.TradeMessage()
|
||||
Panels.AutoStackItems()
|
||||
|
||||
addButton("discord", "Discord & Help", function()
|
||||
g_platform.openUrl("https://discord.gg/yhqBE4A")
|
||||
end)
|
||||
|
||||
addButton("forum", "Forum", function()
|
||||
g_platform.openUrl("https://otland.net/forums/otclient.494/")
|
||||
end)
|
||||
|
||||
addButton("github", "Documentation", function()
|
||||
g_platform.openUrl("https://github.com/OTCv8/otclientv8_bot")
|
||||
end)
|
||||
|
||||
addSeparator("sep")
|
||||
|
||||
Panels.Haste(healTab)
|
||||
Panels.ManaShield(healTab)
|
||||
Panels.AntiParalyze(healTab)
|
||||
Panels.Health(healTab)
|
||||
Panels.Health(healTab)
|
||||
Panels.HealthItem(healTab)
|
||||
Panels.HealthItem(healTab)
|
||||
Panels.ManaItem(healTab)
|
||||
Panels.ManaItem(healTab)
|
||||
Panels.Equip(healTab)
|
||||
Panels.Equip(healTab)
|
||||
Panels.Equip(healTab)
|
||||
Panels.Eating(healTab)
|
||||
|
||||
Panels.AttackSpell(batTab)
|
||||
Panels.AttackItem(batTab)
|
||||
|
||||
Panels.AttackLeaderTarget(batTab)
|
||||
Panels.LimitFloor(batTab)
|
||||
Panels.AntiPush(batTab)
|
||||
|
||||
local waypoints = Panels.Waypoints(caveTab)
|
||||
local attacking = Panels.Attacking(caveTab)
|
||||
local looting = Panels.Looting(caveTab)
|
||||
addButton("tutorial", "Help & Tutorials", function()
|
||||
g_platform.openUrl("https://github.com/OTCv8/otclientv8_bot")
|
||||
end, caveTab)
|
||||
|
||||
--#macros
|
||||
|
||||
macro(1000, "exchange money", function()
|
||||
local containers = getContainers()
|
||||
for i, container in pairs(containers) do
|
||||
for j, item in ipairs(container:getItems()) do
|
||||
if item:isStackable() and (item:getId() == 3035 or item:getId() == 3031) and item:getCount() == 100 then
|
||||
g_game.use(item)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
macro(1000, "this macro does nothing", "f7", function()
|
||||
|
||||
end)
|
||||
|
||||
macro(100, "debug pathfinding", nil, function()
|
||||
for i, tile in ipairs(g_map.getTiles(posz())) do
|
||||
tile:setText("")
|
||||
end
|
||||
local path = findEveryPath(pos(), 20, {
|
||||
ignoreNonPathable = false
|
||||
})
|
||||
local total = 0
|
||||
for i, p in pairs(path) do
|
||||
local s = i:split(",")
|
||||
local pos = {x=tonumber(s[1]), y=tonumber(s[2]), z=tonumber(s[3])}
|
||||
local tile = g_map.getTile(pos)
|
||||
if tile then
|
||||
tile:setText(p[2])
|
||||
end
|
||||
total = total + 1
|
||||
end
|
||||
end)
|
||||
|
||||
macro(1000, "speed hack", nil, function()
|
||||
player:setSpeed(1000)
|
||||
end)
|
||||
|
||||
|
||||
--#hotkeys
|
||||
|
||||
hotkey("f5", "example hotkey", function()
|
||||
info("Wow, you clicked f5 hotkey")
|
||||
end)
|
||||
|
||||
singlehotkey("ctrl+f6", "singlehotkey", function()
|
||||
info("Wow, you clicked f6 singlehotkey")
|
||||
usewith(268, player)
|
||||
end)
|
||||
|
||||
singlehotkey("ctrl+f8", "play alarm", function()
|
||||
playAlarm()
|
||||
end)
|
||||
|
||||
singlehotkey("ctrl+f9", "stop alarm", function()
|
||||
stopSound()
|
||||
end)
|
||||
|
||||
--#callbacks
|
||||
|
||||
local positionLabel = addLabel("positionLabel", "")
|
||||
onPlayerPositionChange(function()
|
||||
positionLabel:setText("Pos: " .. posx() .. "," .. posy() .. "," .. posz())
|
||||
end)
|
||||
|
||||
local s = addSwitch("sdSound", "Play sound when using sd", function(widget)
|
||||
storage.sdSound = not storage.sdSound
|
||||
widget:setOn(storage.sdSound)
|
||||
end)
|
||||
s:setOn(storage.sdSound)
|
||||
|
||||
onUseWith(function(pos, itemId)
|
||||
if storage.sdSound and itemId == 3155 then
|
||||
playSound("/sounds/magnum.ogg")
|
||||
end
|
||||
end)
|
||||
|
||||
--#other
|
||||
|
||||
macro(100, "hide useless tiles", "", function()
|
||||
for i, tile in ipairs(g_map.getTiles(posz())) do
|
||||
if not tile:isWalkable(true) then
|
||||
tile:setFill('black')
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
addLabel("mapinfo", "You can use ctrl + plus and ctrl + minus to zoom in / zoom out map")
|
||||
|
||||
]=]},
|
||||
{name = "UI & Healing", script = [=[
|
||||
-- UI & healing
|
||||
info("Tested on 10.99")
|
||||
|
||||
--#main
|
||||
local healthPanel = setupUI([[
|
||||
Panel
|
||||
id: healingPanel
|
||||
height: 150
|
||||
margin-top: 3
|
||||
|
||||
Label
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
text: Use item if
|
||||
text-align: center
|
||||
|
||||
BotItem
|
||||
id: item1
|
||||
anchors.left: parent.left
|
||||
anchors.top: prev.bottom
|
||||
|
||||
Label
|
||||
id: label1
|
||||
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: prev.left
|
||||
anchors.right: prev.right
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 5
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
step: 1
|
||||
|
||||
BotItem
|
||||
id: item2
|
||||
anchors.left: parent.left
|
||||
anchors.top: item1.bottom
|
||||
margin-top: 3
|
||||
|
||||
Label
|
||||
id: label2
|
||||
anchors.left: prev.right
|
||||
anchors.right: parent.right
|
||||
anchors.top: prev.top
|
||||
margin: 0 5 0 5
|
||||
text-align: center
|
||||
|
||||
HorizontalScrollBar
|
||||
id: scroll2
|
||||
anchors.left: label2.left
|
||||
anchors.right: label2.horizontalCenter
|
||||
anchors.top: label2.bottom
|
||||
margin-top: 5
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
step: 1
|
||||
|
||||
HorizontalScrollBar
|
||||
id: scroll3
|
||||
anchors.left: label2.horizontalCenter
|
||||
anchors.right: label2.right
|
||||
anchors.top: label2.bottom
|
||||
margin-top: 5
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
step: 1
|
||||
|
||||
Label
|
||||
anchors.top: item2.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
margin-top: 3
|
||||
text: Drag item to change it
|
||||
text-align: center
|
||||
|
||||
HorizontalSeparator
|
||||
anchors.top: prev.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
margin-top: 3
|
||||
]])
|
||||
|
||||
healthPanel.item1:setItemId(storage.healItem1 or 266)
|
||||
healthPanel.item1.onItemChange = function(widget, item)
|
||||
storage.healItem1 = item:getId()
|
||||
widget:setItemId(storage.healItem1)
|
||||
end
|
||||
|
||||
healthPanel.item2:setItemId(storage.healItem2 or 268)
|
||||
healthPanel.item2.onItemChange = function(widget, item)
|
||||
storage.healItem2 = item:getId()
|
||||
widget:setItemId(storage.healItem2)
|
||||
end
|
||||
|
||||
healthPanel.scroll1.onValueChange = function(scroll, value)
|
||||
storage.healPercent1 = value
|
||||
healthPanel.label1:setText("0% <= hp <= " .. storage.healPercent1 .. "%")
|
||||
end
|
||||
healthPanel.scroll1:setValue(storage.healPercent1 or 50)
|
||||
|
||||
healthPanel.scroll2.onValueChange = function(scroll, value)
|
||||
storage.healPercent2 = value
|
||||
healthPanel.label2:setText("" .. storage.healPercent2 .. "% <= mana <= " .. storage.healPercent3 .. "%")
|
||||
end
|
||||
healthPanel.scroll3.onValueChange = function(scroll, value)
|
||||
storage.healPercent3 = value
|
||||
healthPanel.label2:setText("" .. storage.healPercent2 .. "% <= mana <= " .. storage.healPercent3 .. "%")
|
||||
end
|
||||
healthPanel.scroll2:setValue(storage.healPercent2 or 40)
|
||||
healthPanel.scroll3:setValue(storage.healPercent3 or 60)
|
||||
|
||||
macro(25, function()
|
||||
if not storage.healItem1 then
|
||||
return
|
||||
end
|
||||
if healthPanel.scroll1:getValue() >= hppercent() then
|
||||
useWith(storage.healItem1, player)
|
||||
delay(500)
|
||||
end
|
||||
end)
|
||||
macro(25, function()
|
||||
if not storage.healItem2 then
|
||||
return
|
||||
end
|
||||
if storage.healPercent2 <= manapercent() and manapercent() <= storage.healPercent3 then
|
||||
useWith(storage.healItem2, player)
|
||||
delay(500)
|
||||
end
|
||||
end)
|
||||
|
||||
--#macros
|
||||
|
||||
--#hotkeys
|
||||
|
||||
--#callbacks
|
||||
|
||||
--#other
|
||||
]=]},
|
||||
{}, {}, {}, {}
|
||||
},
|
||||
enabled = false,
|
||||
selectedConfig = 1
|
||||
}
|
@ -82,34 +82,42 @@ MainWindow
|
||||
!text: tr("To reload configs just press On and Off in bot window.\nTo learn more about bot click Tutorials button.")
|
||||
|
||||
Button
|
||||
!text: tr('Tutorials')
|
||||
!text: tr('Documentation')
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
width: 100
|
||||
width: 118
|
||||
@onClick: g_platform.openUrl("http://otclient.ovh/bot.php?documentation")
|
||||
|
||||
Button
|
||||
!text: tr('Tutorials')
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: prev.right
|
||||
margin-left: 5
|
||||
width: 80
|
||||
@onClick: g_platform.openUrl("http://otclient.ovh/bot.php?tutorials")
|
||||
|
||||
Button
|
||||
!text: tr('Scripts')
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: prev.right
|
||||
margin-left: 10
|
||||
width: 100
|
||||
margin-left: 5
|
||||
width: 80
|
||||
@onClick: g_platform.openUrl("http://otclient.ovh/bot.php?scripts")
|
||||
|
||||
Button
|
||||
!text: tr('Forum')
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: prev.right
|
||||
margin-left: 10
|
||||
width: 100
|
||||
margin-left: 5
|
||||
width: 80
|
||||
@onClick: g_platform.openUrl("http://otclient.ovh/bot.php?forum")
|
||||
|
||||
Button
|
||||
!text: tr('Discord')
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: prev.right
|
||||
margin-left: 10
|
||||
width: 100
|
||||
margin-left: 5
|
||||
width: 80
|
||||
@onClick: g_platform.openUrl("http://otclient.ovh/bot.php?discord")
|
||||
|
||||
Button
|
||||
|
@ -30,7 +30,7 @@ function executeBot(config, storage, tabs, msgCallback, saveConfigCallback, webs
|
||||
context.storage._macros = {} -- active macros
|
||||
end
|
||||
|
||||
-- macros, hotkeys, scheduler, callbacks
|
||||
-- macros, hotkeys, scheduler, icons, callbacks
|
||||
context._macros = {}
|
||||
context._hotkeys = {}
|
||||
context._scheduler = {}
|
||||
@ -123,9 +123,9 @@ function executeBot(config, storage, tabs, msgCallback, saveConfigCallback, webs
|
||||
context.time = g_clock.millis()
|
||||
|
||||
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 macro.lastExecution + macro.timeout <= context.now and (macro.name == nil or macro.name:len() < 1 or macro.enabled) then
|
||||
local status, result = pcall(function()
|
||||
if macro.callback() then
|
||||
if macro.callback(macro) then
|
||||
macro.lastExecution = context.now
|
||||
end
|
||||
end)
|
||||
|
@ -1,123 +0,0 @@
|
||||
-- In this file are declared extra functions and variables for bot
|
||||
-- It has been made to make most common functions shorter, for eg. hp() instead of player:getHealth()
|
||||
|
||||
function setupFunctions(context)
|
||||
-- player releated
|
||||
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
|
||||
|
||||
-- game releated
|
||||
context.say = g_game.talk
|
||||
context.talk = g_game.talk
|
||||
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
|
||||
|
||||
-- map releated
|
||||
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
|
||||
|
||||
-- tools
|
||||
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
|
||||
end
|
@ -8,12 +8,24 @@ context.callback = function(callbackType, callback)
|
||||
if callbackType == "onAddThing" or callbackType == "onRemoveThing" then
|
||||
g_game.enableTileThingLuaCallback(true)
|
||||
end
|
||||
|
||||
local desc = "lua"
|
||||
local info = debug.getinfo(2, "Sl")
|
||||
if info then
|
||||
desc = info.short_src .. ":" .. info.currentline
|
||||
end
|
||||
|
||||
local callbackData = {}
|
||||
table.insert(context._callbacks[callbackType], function(...)
|
||||
if not callbackData.delay or callbackData.delay < context.now then
|
||||
local prevExecution = context._currentExecution
|
||||
context._currentExecution = callbackData
|
||||
local start = g_clock.realMillis()
|
||||
callback(...)
|
||||
local executionTime = g_clock.realMillis() - start
|
||||
if executionTime > 100 then
|
||||
context.warning("Slow " .. callbackType .. " (" .. executionTime .. "ms): " .. desc)
|
||||
end
|
||||
context._currentExecution = prevExecution
|
||||
end
|
||||
end)
|
||||
|
174
modules/game_bot/functions/icon.lua
Normal file
174
modules/game_bot/functions/icon.lua
Normal file
@ -0,0 +1,174 @@
|
||||
local context = G.botContext
|
||||
|
||||
local iconsWithoutPosition = 0
|
||||
|
||||
context.addIcon = function(id, options, callback)
|
||||
--[[
|
||||
Available options:
|
||||
item: {id=2160, count=100}
|
||||
outfit: outfit table ({})
|
||||
text: string
|
||||
x: float (0.0 - 1.0)
|
||||
y: float (0.0 - 1.0)
|
||||
width: number
|
||||
height: number
|
||||
hotkey: string
|
||||
switchable: true / false [default: true]
|
||||
movable: true / false [default: true]
|
||||
phantom: true / false [defaule: false]
|
||||
]]--
|
||||
local panel = modules.game_interface.gameMapPanel
|
||||
if type(id) ~= "string" or id:len() < 1 then
|
||||
return context.error("Invalid id for addIcon")
|
||||
end
|
||||
if options.switchable == false and type(callback) ~= 'function' then
|
||||
return context.error("Invalid callback for addIcon")
|
||||
end
|
||||
if type(context.storage._icons) ~= "table" then
|
||||
context.storage._icons = {}
|
||||
end
|
||||
if type(context.storage._icons[id]) ~= "table" then
|
||||
context.storage._icons[id] = {}
|
||||
end
|
||||
local config = context.storage._icons[id]
|
||||
local widget = g_ui.createWidget("BotIcon", panel)
|
||||
widget.botWidget = true
|
||||
|
||||
if type(config.x) ~= 'number' and type(config.y) ~= 'number' then
|
||||
if type(options.x) == 'number' and type(options.y) == 'number' then
|
||||
config.x = math.min(1.0, math.max(0.0, options.x))
|
||||
config.y = math.min(1.0, math.max(0.0, options.y))
|
||||
else
|
||||
config.x = 0.01 + math.floor(iconsWithoutPosition / 5) / 10
|
||||
config.y = 0.05 + (iconsWithoutPosition % 5) / 5
|
||||
iconsWithoutPosition = iconsWithoutPosition + 1
|
||||
end
|
||||
end
|
||||
|
||||
if options.item then
|
||||
if type(options.item) == 'number' then
|
||||
widget.item:setItemId(options.item)
|
||||
else
|
||||
widget.item:setItemId(options.item.id)
|
||||
widget.item:setItemCount(options.item.count or 1)
|
||||
widget.item:setShowCount(false)
|
||||
end
|
||||
end
|
||||
|
||||
if options.outfit then
|
||||
widget.creature:setOutfit(options.outfit)
|
||||
end
|
||||
|
||||
if options.switchable == false then
|
||||
widget.status:hide()
|
||||
widget.status:setOn(true)
|
||||
else
|
||||
widget.status:setOn(config.enabled)
|
||||
end
|
||||
|
||||
if options.text then
|
||||
if options.switchable ~= false then
|
||||
widget.status:hide()
|
||||
if widget.status:isOn() then
|
||||
widget.text:setColor('green')
|
||||
else
|
||||
widget.text:setColor('red')
|
||||
end
|
||||
end
|
||||
widget.text:setText(options.text)
|
||||
end
|
||||
|
||||
widget.setOn = function(val)
|
||||
widget.status:setOn(val)
|
||||
if widget.status:isOn() then
|
||||
widget.text:setColor('green')
|
||||
else
|
||||
widget.text:setColor('red')
|
||||
end
|
||||
config.enabled = widget.status:isOn()
|
||||
end
|
||||
|
||||
widget.onClick = function(widget)
|
||||
if options.switchable ~= false then
|
||||
widget.setOn(not widget.status:isOn())
|
||||
if type(callback) == 'table' then
|
||||
callback.setOn(config.enabled)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
callback(widget, widget.status:isOn())
|
||||
end
|
||||
|
||||
if options.hotkey then
|
||||
widget.hotkey:setText(options.hotkey)
|
||||
context.hotkey(options.hotkey, "", function()
|
||||
widget:onClick()
|
||||
end, nil, options.switchable ~= false)
|
||||
else
|
||||
widget.hotkey:hide()
|
||||
end
|
||||
|
||||
if options.movable ~= false then
|
||||
widget.onDragEnter = function(widget, mousePos)
|
||||
if not g_keyboard.isCtrlPressed() then
|
||||
return false
|
||||
end
|
||||
widget:breakAnchors()
|
||||
widget.movingReference = { x = mousePos.x - widget:getX(), y = mousePos.y - widget:getY() }
|
||||
return true
|
||||
end
|
||||
|
||||
widget.onDragMove = function(widget, mousePos, moved)
|
||||
local parentRect = widget:getParent():getRect()
|
||||
local x = math.min(math.max(parentRect.x, mousePos.x - widget.movingReference.x), parentRect.x + parentRect.width - widget:getWidth())
|
||||
local y = math.min(math.max(parentRect.y, mousePos.y - widget.movingReference.y), parentRect.y + parentRect.height - widget:getHeight())
|
||||
widget:move(x, y)
|
||||
return true
|
||||
end
|
||||
|
||||
widget.onDragLeave = function(widget, pos)
|
||||
local parent = widget:getParent()
|
||||
local parentRect = parent:getRect()
|
||||
local x = widget:getX() - parentRect.x
|
||||
local y = widget:getY() - parentRect.y
|
||||
local width = parentRect.width - widget:getWidth()
|
||||
local height = parentRect.height - widget:getHeight()
|
||||
|
||||
config.x = math.min(1, math.max(0, x / width))
|
||||
config.y = math.min(1, math.max(0, y / height))
|
||||
widget:addAnchor(AnchorHorizontalCenter, 'parent', AnchorHorizontalCenter)
|
||||
widget:addAnchor(AnchorVerticalCenter, 'parent', AnchorVerticalCenter)
|
||||
|
||||
widget:setMarginTop(height * (-0.5 + config.x))
|
||||
widget:setMarginLeft(width * (-0.5 + config.y))
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
widget.onGeometryChange = function(widget, oldRect, newRect)
|
||||
if widget:isDragging() then return end
|
||||
local parent = widget:getParent()
|
||||
local parentRect = parent:getRect()
|
||||
local width = parentRect.width - widget:getWidth()
|
||||
local height = parentRect.height - widget:getHeight()
|
||||
widget:setMarginTop(height * (-0.5 + config.y))
|
||||
widget:setMarginLeft(width * (-0.5 + config.x))
|
||||
end
|
||||
|
||||
if options.phantom ~= true then
|
||||
widget.onMouseRelease = function()
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
if options.switchable ~= false then
|
||||
if type(callback) == 'table' then
|
||||
callback.setOn(config.enabled)
|
||||
callback.icon = widget
|
||||
else
|
||||
callback(widget, widget.status:isOn())
|
||||
end
|
||||
end
|
||||
return widget
|
||||
end
|
@ -34,33 +34,89 @@ context.macro = function(timeout, name, hotkey, callback, parent)
|
||||
hotkey = retranslateKeyComboDesc(hotkey)
|
||||
end
|
||||
|
||||
local switch = nil
|
||||
if name:len() > 0 then
|
||||
if context.storage._macros[name] == nil then
|
||||
context.storage._macros[name] = false
|
||||
table.insert(context._macros, {
|
||||
enabled = false,
|
||||
name = name,
|
||||
timeout = timeout,
|
||||
lastExecution = context.now,
|
||||
hotkey = hotkey,
|
||||
})
|
||||
local macro = context._macros[#context._macros]
|
||||
|
||||
macro.isOn = function()
|
||||
return macro.enabled
|
||||
end
|
||||
macro.isOff = function()
|
||||
return not macro.enabled
|
||||
end
|
||||
macro.toggle = function(widget)
|
||||
if macro.isOn() then
|
||||
macro.setOff()
|
||||
else
|
||||
macro.setOn()
|
||||
end
|
||||
switch = context._addMacroSwitch(name, hotkey, parent)
|
||||
end
|
||||
macro.setOn = function(val)
|
||||
if val == false then
|
||||
return macro.setOff()
|
||||
end
|
||||
macro.enabled = true
|
||||
context.storage._macros[name] = true
|
||||
if macro.switch then
|
||||
macro.switch:setOn(true)
|
||||
end
|
||||
if macro.icon then
|
||||
macro.icon.setOn(true)
|
||||
end
|
||||
end
|
||||
macro.setOff = function(val)
|
||||
if val == false then
|
||||
return macro.setOn()
|
||||
end
|
||||
macro.enabled = false
|
||||
context.storage._macros[name] = false
|
||||
if macro.switch then
|
||||
macro.switch:setOn(false)
|
||||
end
|
||||
if macro.icon then
|
||||
macro.icon.setOn(false)
|
||||
end
|
||||
end
|
||||
|
||||
if name:len() > 0 then
|
||||
-- creature switch
|
||||
local text = name
|
||||
if hotkey:len() > 0 then
|
||||
text = name .. " [" .. hotkey .. "]"
|
||||
end
|
||||
macro.switch = context.addSwitch("macro_" .. (#context._macros + 1), text, macro.toggle, parent)
|
||||
|
||||
-- load state
|
||||
if context.storage._macros[name] == true then
|
||||
macro.setOn()
|
||||
end
|
||||
end
|
||||
|
||||
local desc = "lua"
|
||||
local info = debug.getinfo(2, "Sl")
|
||||
if info then
|
||||
desc = info.short_src .. ":" .. info.currentline
|
||||
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()
|
||||
macro.callback = function(macro)
|
||||
if not macro.delay or macro.delay < context.now then
|
||||
context._currentExecution = macro
|
||||
local start = g_clock.realMillis()
|
||||
callback(macro)
|
||||
local executionTime = g_clock.realMillis() - start
|
||||
if executionTime > 100 then
|
||||
context.warning("Slow macro (" .. executionTime .. "ms): " .. macro.name .. " - " .. desc)
|
||||
end
|
||||
context._currentExecution = nil
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return macroData
|
||||
return macro
|
||||
end
|
||||
|
||||
-- hotkey(keys, callback)
|
||||
@ -94,11 +150,22 @@ context.hotkey = function(keys, name, callback, parent, single)
|
||||
single = single
|
||||
}
|
||||
|
||||
local desc = "lua"
|
||||
local info = debug.getinfo(2, "Sl")
|
||||
if info then
|
||||
desc = info.short_src .. ":" .. info.currentline
|
||||
end
|
||||
|
||||
local hotkeyData = context._hotkeys[keys]
|
||||
hotkeyData.callback = function()
|
||||
if not hotkeyData.delay or hotkeyData.delay < context.now then
|
||||
context._currentExecution = hotkeyData
|
||||
local start = g_clock.realMillis()
|
||||
callback()
|
||||
local executionTime = g_clock.realMillis() - start
|
||||
if executionTime > 100 then
|
||||
context.warning("Slow hotkey (" .. executionTime .. "ms): " .. hotkeyData.name .. " - " .. desc)
|
||||
end
|
||||
context._currentExecution = nil
|
||||
return true
|
||||
end
|
||||
|
@ -132,7 +132,6 @@ context.findPath = function(startPos, destPos, maxDist, params)
|
||||
local destPosStr = destPos.x .. "," .. destPos.y .. "," .. destPos.z
|
||||
params["destination"] = destPosStr
|
||||
local paths = context.findAllPaths(startPos, maxDist, params)
|
||||
|
||||
local marginMin = params.marginMin or params.minMargin
|
||||
local marginMax = params.marginMax or params.maxMargin
|
||||
if type(marginMin) == 'number' and type(marginMax) == 'number' then
|
||||
@ -143,6 +142,7 @@ context.findPath = function(startPos, destPos, maxDist, params)
|
||||
if math.abs(x) >= marginMin or math.abs(y) >= marginMin then
|
||||
local dest = (destPos.x + x) .. "," .. (destPos.y + y) .. "," .. destPos.z
|
||||
local node = paths[dest]
|
||||
print(node)
|
||||
if node and (not bestCandidate or bestCandidate[1] > node[1]) then
|
||||
bestCandidate = node
|
||||
bestCandidatePos = dest
|
||||
@ -195,3 +195,7 @@ context.autoWalk = function(destination, maxDist, params)
|
||||
return true
|
||||
end
|
||||
|
||||
context.getTileUnderCursor = function()
|
||||
if not modules.game_interface.gameMapPanel.mousePos then return end
|
||||
return modules.game_interface.gameMapPanel:getTile(modules.game_interface.gameMapPanel.mousePos)
|
||||
end
|
@ -3,6 +3,7 @@ local context = G.botContext
|
||||
context.BotServer = {}
|
||||
context.BotServer.url = "ws://bot.otclient.ovh:8000/"
|
||||
context.BotServer.timeout = 3
|
||||
context.BotServer.ping = 0
|
||||
context.BotServer._callbacks = {}
|
||||
context.BotServer._lastMessageId = 0
|
||||
context.BotServer._wasConnected = true -- show first warning
|
||||
@ -24,6 +25,7 @@ context.BotServer.init = function(name, channel)
|
||||
end
|
||||
context.BotServer._wasConnected = true
|
||||
if message["type"] == "ping" then
|
||||
context.BotServer.ping = message["ping"]
|
||||
return context.BotServer._websocket.send({type="ping"})
|
||||
end
|
||||
if message["type"] == "message" then
|
||||
|
@ -59,7 +59,7 @@ Panel
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
vertical-scrollbar: scrollBar
|
||||
margin-right: 10
|
||||
margin-right: 5
|
||||
margin-top: 2
|
||||
height: 70
|
||||
layout:
|
||||
@ -67,7 +67,7 @@ Panel
|
||||
cell-size: 34 34
|
||||
flow: true
|
||||
|
||||
VerticalScrollBar
|
||||
BotSmallScrollBar
|
||||
id: scrollBar
|
||||
anchors.top: prev.top
|
||||
anchors.bottom: prev.bottom
|
||||
|
@ -38,6 +38,67 @@ BotSeparator < HorizontalSeparator
|
||||
margin-top: 5
|
||||
margin-bottom: 3
|
||||
|
||||
BotSmallScrollBar < UIScrollBar
|
||||
orientation: vertical
|
||||
margin-bottom: 1
|
||||
step: 20
|
||||
width: 8
|
||||
image-source: /images/ui/scrollbar
|
||||
image-clip: 39 0 13 65
|
||||
image-border: 1
|
||||
pixels-scroll: true
|
||||
|
||||
UIButton
|
||||
id: decrementButton
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
image-source: /images/ui/scrollbar
|
||||
image-clip: 0 0 13 13
|
||||
image-color: #ffffffff
|
||||
size: 8 8
|
||||
$hover:
|
||||
image-clip: 13 0 13 13
|
||||
$pressed:
|
||||
image-clip: 26 0 13 13
|
||||
$disabled:
|
||||
image-color: #ffffff66
|
||||
|
||||
UIButton
|
||||
id: incrementButton
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
size: 8 8
|
||||
image-source: /images/ui/scrollbar
|
||||
image-clip: 0 13 13 13
|
||||
image-color: #ffffffff
|
||||
$hover:
|
||||
image-clip: 13 13 13 13
|
||||
$pressed:
|
||||
image-clip: 26 13 13 13
|
||||
$disabled:
|
||||
image-color: #ffffff66
|
||||
|
||||
UIButton
|
||||
id: sliderButton
|
||||
anchors.centerIn: parent
|
||||
size: 8 11
|
||||
image-source: /images/ui/scrollbar
|
||||
image-clip: 0 26 13 13
|
||||
image-border: 2
|
||||
image-color: #ffffffff
|
||||
$hover:
|
||||
image-clip: 13 26 13 13
|
||||
$pressed:
|
||||
image-clip: 26 26 13 13
|
||||
$disabled:
|
||||
image-color: #ffffff66
|
||||
|
||||
Label
|
||||
id: valueLabel
|
||||
anchors.fill: parent
|
||||
color: white
|
||||
text-align: center
|
||||
|
||||
BotPanel < Panel
|
||||
ScrollablePanel
|
||||
id: content
|
||||
@ -49,70 +110,11 @@ BotPanel < Panel
|
||||
layout:
|
||||
type: verticalBox
|
||||
|
||||
UIScrollBar
|
||||
BotSmallScrollBar
|
||||
id: botPanelScroll
|
||||
orientation: vertical
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
margin-bottom: 1
|
||||
step: 20
|
||||
width: 8
|
||||
image-source: /images/ui/scrollbar
|
||||
image-clip: 39 0 13 65
|
||||
image-border: 1
|
||||
pixels-scroll: true
|
||||
|
||||
UIButton
|
||||
id: decrementButton
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
image-source: /images/ui/scrollbar
|
||||
image-clip: 0 0 13 13
|
||||
image-color: #ffffffff
|
||||
size: 8 8
|
||||
$hover:
|
||||
image-clip: 13 0 13 13
|
||||
$pressed:
|
||||
image-clip: 26 0 13 13
|
||||
$disabled:
|
||||
image-color: #ffffff66
|
||||
|
||||
UIButton
|
||||
id: incrementButton
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
size: 8 8
|
||||
image-source: /images/ui/scrollbar
|
||||
image-clip: 0 13 13 13
|
||||
image-color: #ffffffff
|
||||
$hover:
|
||||
image-clip: 13 13 13 13
|
||||
$pressed:
|
||||
image-clip: 26 13 13 13
|
||||
$disabled:
|
||||
image-color: #ffffff66
|
||||
|
||||
UIButton
|
||||
id: sliderButton
|
||||
anchors.centerIn: parent
|
||||
size: 8 11
|
||||
image-source: /images/ui/scrollbar
|
||||
image-clip: 0 26 13 13
|
||||
image-border: 2
|
||||
image-color: #ffffffff
|
||||
$hover:
|
||||
image-clip: 13 26 13 13
|
||||
$pressed:
|
||||
image-clip: 26 26 13 13
|
||||
$disabled:
|
||||
image-color: #ffffff66
|
||||
|
||||
Label
|
||||
id: valueLabel
|
||||
anchors.fill: parent
|
||||
color: white
|
||||
text-align: center
|
||||
|
||||
CaveBotLabel < Label
|
||||
background-color: alpha
|
||||
|
60
modules/game_bot/ui/icons.otui
Normal file
60
modules/game_bot/ui/icons.otui
Normal file
@ -0,0 +1,60 @@
|
||||
BotIcon < UIWidget
|
||||
size: 50 50
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
focusable: false
|
||||
phantom: false
|
||||
draggable: true
|
||||
|
||||
UIItem
|
||||
id: item
|
||||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
margin-top: 6
|
||||
virtual: true
|
||||
phantom: true
|
||||
size: 32 32
|
||||
|
||||
UICreature
|
||||
id: creature
|
||||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
margin-top: 0
|
||||
size: 48 48
|
||||
phantom: true
|
||||
|
||||
UIWidget
|
||||
id: status
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
size: 18 10
|
||||
color: black
|
||||
font: terminus-10px
|
||||
phantom: true
|
||||
|
||||
$on:
|
||||
text: ON
|
||||
background: green
|
||||
|
||||
$!on:
|
||||
text: OFF
|
||||
background: red
|
||||
|
||||
UIWidget
|
||||
id: hotkey
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
size: 18 10
|
||||
color: white
|
||||
phantom: true
|
||||
text-align: right
|
||||
|
||||
UIWidget
|
||||
id: text
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
text-wrap: true
|
||||
text-auto-resize: true
|
||||
phantom: true
|
@ -11,6 +11,7 @@ function updateFeatures(version)
|
||||
|
||||
-- you can add custom features here, list of them is in the modules\gamelib\const.lua
|
||||
g_game.enableFeature(GameBot)
|
||||
g_game.enableFeature(GameExtendedOpcode)
|
||||
--g_game.enableFeature(GameMinimapLimitedToSingleFloor) -- it will generate minimap only for current floor
|
||||
--g_game.enableFeature(GameSpritesAlphaChannel)
|
||||
|
||||
|
@ -112,7 +112,6 @@ function UIGameMap:onMouseRelease(mousePosition, mouseButton)
|
||||
if not self.allowNextRelease and not self.markingMouseRelease then
|
||||
return true
|
||||
end
|
||||
|
||||
local autoWalkPos = self:getPosition(mousePosition)
|
||||
local positionOffset = self:getPositionOffset(mousePosition)
|
||||
|
||||
|
@ -1,118 +0,0 @@
|
||||
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
|
||||
if self.onItemChange then
|
||||
self.onItemChange(self, item)
|
||||
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
|
@ -26,7 +26,6 @@ end
|
||||
-- public functions
|
||||
function init()
|
||||
connect(g_game, { onGameStart = check, onGameEnd = hide })
|
||||
|
||||
ProtocolGame.registerExtendedJSONOpcode(SHOP_EXTENTED_OPCODE, onExtendedJSONOpcode)
|
||||
|
||||
if g_game.isOnline() then
|
||||
|
@ -266,38 +266,44 @@ function walk(dir)
|
||||
g_game.cancelFollow()
|
||||
end
|
||||
|
||||
if player:isAutoWalking() or player:isServerWalking() then
|
||||
if player:isAutoWalking() then
|
||||
if lastStop + 100 < g_clock.millis() then
|
||||
lastStop = g_clock.millis()
|
||||
if player:isAutoWalking() then
|
||||
player:stopAutoWalk()
|
||||
end
|
||||
player:stopAutoWalk()
|
||||
g_game.stop()
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if player:isWalkLocked() then
|
||||
nextWalkDir = nil
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
local dash = false
|
||||
local ignoredCanWalk = false
|
||||
if not g_game.getFeature(GameNewWalking) then
|
||||
dash = g_settings.getBoolean("dash", true)
|
||||
end
|
||||
|
||||
local ticksToNextWalk = player:getStepTicksLeft()
|
||||
if not player:canWalk(dir) then -- canWalk return false when previous walk is not finished or not confirmed by server
|
||||
if ticksToNextWalk < 500 and lastWalkDir ~= dir then
|
||||
nextWalkDir = dir
|
||||
if dash then
|
||||
ignoredCanWalk = true
|
||||
else
|
||||
if ticksToNextWalk < 500 and lastWalkDir ~= dir then
|
||||
nextWalkDir = dir
|
||||
end
|
||||
if ticksToNextWalk < 30 and lastFinishedStep + 400 > g_clock.millis() and nextWalkDir == nil then -- clicked walk 20 ms too early, try to execute again as soon possible to keep smooth walking
|
||||
nextWalkDir = dir
|
||||
end
|
||||
return
|
||||
end
|
||||
if ticksToNextWalk < 30 and lastFinishedStep + 400 > g_clock.millis() and nextWalkDir == nil then -- clicked walk 20 ms too early, try to execute again as soon possible to keep smooth walking
|
||||
nextWalkDir = dir
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
--if nextWalkDir ~= nil and lastFinishedStep + 200 < g_clock.millis() then
|
||||
-- print("Cancel " .. nextWalkDir)
|
||||
-- nextWalkDir = nil
|
||||
--end
|
||||
|
||||
if nextWalkDir ~= nil and nextWalkDir ~= lastWalkDir then
|
||||
dir = nextWalkDir
|
||||
end
|
||||
@ -336,25 +342,34 @@ function walk(dir)
|
||||
walkLock = lastWalk + g_settings.getNumber('walkFirstStepDelay')
|
||||
return
|
||||
end
|
||||
|
||||
if dash and lastWalkDir == dir and lastWalk + 30 > g_clock.millis() then
|
||||
walkLock = lastWalk + g_settings.getNumber('walkFirstStepDelay')
|
||||
return
|
||||
end
|
||||
|
||||
firstStep = not player:isWalking() and lastFinishedStep + 100 < g_clock.millis() and walkLock + 100 < g_clock.millis()
|
||||
firstStep = (not player:isWalking() and lastFinishedStep + 100 < g_clock.millis() and walkLock + 100 < g_clock.millis()) or (player:isServerWalking() and not dash)
|
||||
nextWalkDir = nil
|
||||
removeEvent(autoWalkEvent)
|
||||
autoWalkEvent = nil
|
||||
|
||||
local preWalked = false
|
||||
if toTile and toTile:isWalkable() then
|
||||
player:preWalk(dir)
|
||||
preWalked = true
|
||||
if not player:isServerWalking() and not ignoredCanWalk then
|
||||
player:preWalk(dir)
|
||||
preWalked = true
|
||||
end
|
||||
else
|
||||
local playerTile = player:getTile()
|
||||
if (playerTile and playerTile:hasElevation(3) and canChangeFloorUp(toPos)) or canChangeFloorDown(toPos) or (toTile and toTile:isEmpty() and not toTile:isBlocking()) then
|
||||
player:lockWalk(100)
|
||||
elseif player:isServerWalking() then
|
||||
g_game.stop()
|
||||
return
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
g_game.walk(dir, preWalked)
|
||||
|
||||
if not firstStep and lastWalkDir ~= dir then
|
||||
|
@ -4,5 +4,6 @@ Module
|
||||
author: otclient.ovh
|
||||
website: http://otclient.ovh
|
||||
scripts: [ walking ]
|
||||
dependencies: [ game_interface ]
|
||||
@onLoad: init()
|
||||
@onUnload: terminate()
|
||||
|
BIN
otclient_dx.exe
BIN
otclient_dx.exe
Binary file not shown.
BIN
otclient_gl.exe
BIN
otclient_gl.exe
Binary file not shown.
BIN
otclient_linux
BIN
otclient_linux
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user