Version 1.8

This commit is contained in:
OTCv8 2020-01-10 02:29:15 +01:00
parent 2a10e65ec0
commit 26c347d2bc
38 changed files with 531 additions and 792 deletions

View File

@ -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

View File

@ -16,6 +16,7 @@ Module
- client_background
- client_options
- client_entergame
- client_entergamev2
- client_terminal
- client_stats
- client_news

View File

@ -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 })

View File

@ -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()

View File

@ -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")

View File

@ -0,0 +1,5 @@
function init()
end
function terminate()
end

View 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()

View File

@ -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

View File

@ -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

View File

@ -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() }

View File

@ -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,6 +155,7 @@ function refresh()
end
configList:setCurrentOption(settings[index].config)
if configList:getCurrentOption().text ~= settings[index].config then
settings[index].config = configList:getCurrentOption().text
settings[index].enabled = false
end

View File

@ -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()

View 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)

View File

@ -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
}

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)

View 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

View File

@ -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
end
switch = context._addMacroSwitch(name, hotkey, parent)
end
table.insert(context._macros, {
timeout = timeout,
enabled = false,
name = name,
timeout = timeout,
lastExecution = context.now,
hotkey = hotkey,
switch = switch
})
local macro = context._macros[#context._macros]
local macroData = context._macros[#context._macros]
macroData.callback = function()
if not macroData.delay or macroData.delay < context.now then
context._currentExecution = macroData
callback()
macro.isOn = function()
return macro.enabled
end
macro.isOff = function()
return not macro.enabled
end
macro.toggle = function(widget)
if macro.isOn() then
macro.setOff()
else
macro.setOn()
end
end
macro.setOn = function(val)
if val == false then
return macro.setOff()
end
macro.enabled = true
context.storage._macros[name] = true
if macro.switch then
macro.switch:setOn(true)
end
if macro.icon then
macro.icon.setOn(true)
end
end
macro.setOff = function(val)
if val == false then
return macro.setOn()
end
macro.enabled = false
context.storage._macros[name] = false
if macro.switch then
macro.switch:setOn(false)
end
if macro.icon then
macro.icon.setOn(false)
end
end
if name:len() > 0 then
-- creature switch
local text = name
if hotkey:len() > 0 then
text = name .. " [" .. hotkey .. "]"
end
macro.switch = context.addSwitch("macro_" .. (#context._macros + 1), text, macro.toggle, parent)
-- load state
if context.storage._macros[name] == true then
macro.setOn()
end
end
local desc = "lua"
local info = debug.getinfo(2, "Sl")
if info then
desc = info.short_src .. ":" .. info.currentline
end
macro.callback = function(macro)
if not macro.delay or macro.delay < context.now then
context._currentExecution = macro
local start = g_clock.realMillis()
callback(macro)
local executionTime = g_clock.realMillis() - start
if executionTime > 100 then
context.warning("Slow macro (" .. executionTime .. "ms): " .. macro.name .. " - " .. desc)
end
context._currentExecution = nil
return true
end
end
return 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -38,23 +38,8 @@ BotSeparator < HorizontalSeparator
margin-top: 5
margin-bottom: 3
BotPanel < Panel
ScrollablePanel
id: content
anchors.fill: parent
margin-right: 8
margin-left: 1
margin-bottom: 5
vertical-scrollbar: botPanelScroll
layout:
type: verticalBox
UIScrollBar
id: botPanelScroll
BotSmallScrollBar < UIScrollBar
orientation: vertical
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
margin-bottom: 1
step: 20
width: 8
@ -114,6 +99,23 @@ BotPanel < Panel
color: white
text-align: center
BotPanel < Panel
ScrollablePanel
id: content
anchors.fill: parent
margin-right: 8
margin-left: 1
margin-bottom: 5
vertical-scrollbar: botPanelScroll
layout:
type: verticalBox
BotSmallScrollBar
id: botPanelScroll
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
CaveBotLabel < Label
background-color: alpha
text-offset: 2 0

View 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

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -266,15 +266,12 @@ 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
g_game.stop()
end
return
end
if player:isWalkLocked() then
@ -282,8 +279,17 @@ function walk(dir)
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 dash then
ignoredCanWalk = true
else
if ticksToNextWalk < 500 and lastWalkDir ~= dir then
nextWalkDir = dir
end
@ -292,12 +298,12 @@ function walk(dir)
end
return
end
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
@ -337,19 +343,28 @@ function walk(dir)
return
end
firstStep = not player:isWalking() and lastFinishedStep + 100 < g_clock.millis() and walkLock + 100 < g_clock.millis()
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()) or (player:isServerWalking() and not dash)
nextWalkDir = nil
removeEvent(autoWalkEvent)
autoWalkEvent = nil
local preWalked = false
if toTile and toTile:isWalkable() then
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

View File

@ -4,5 +4,6 @@ Module
author: otclient.ovh
website: http://otclient.ovh
scripts: [ walking ]
dependencies: [ game_interface ]
@onLoad: init()
@onUnload: terminate()

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.