Updated to OTCv8 3.1 rev 118

This commit is contained in:
OTCv8 2022-01-12 21:08:58 +00:00
parent 8408102687
commit 031824178c
26 changed files with 1356 additions and 46 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1023 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -22,10 +22,12 @@ local luaFiles = {
"new_cavebot_lib", "new_cavebot_lib",
"configs", -- do not change this and above "configs", -- do not change this and above
"extras", "extras",
"cavebot",
"playerlist", "playerlist",
"BotServer", "BotServer",
"alarms", "alarms",
"Conditions", "Conditions",
"Equipper",
"pushmax", "pushmax",
"combo", "combo",
"HealBot", "HealBot",
@ -37,14 +39,12 @@ local luaFiles = {
"quiver_manager", "quiver_manager",
"tools", "tools",
"antiRs", "antiRs",
"cavebot",
"depot_withdraw", "depot_withdraw",
"cast_food", "cast_food",
"eat_food", "eat_food",
"equip", "equip",
"exeta", "exeta",
"analyzer", "analyzer",
"jewellery_equipper",
"spy_level", "spy_level",
"supplies", "supplies",
"depositer_config", "depositer_config",

View File

@ -1,5 +1,5 @@
CaveBot.Actions = {} CaveBot.Actions = {}
vBot.lastLabel = ""
local antiTrapTriggered = false local antiTrapTriggered = false
-- it adds an action widget to list -- it adds an action widget to list
@ -77,6 +77,7 @@ CaveBot.registerAction = function(action, color, callback)
end end
CaveBot.registerAction("label", "yellow", function(value, retries, prev) CaveBot.registerAction("label", "yellow", function(value, retries, prev)
vBot.lastLabel = value
return true return true
end) end)
@ -177,7 +178,8 @@ CaveBot.registerAction("goto", "green", function(value, retries, prev)
if not path2 then if not path2 then
local target = {} -- c = creature, d = distance local target = {} -- c = creature, d = distance
for i, spec in pairs(getSpectators()) do for i, spec in pairs(getSpectators()) do
if spec:isMonster() then local hppc = spec:getHealthPercent()
if spec:isMonster() and (hppc and hppc > 0) then
local path = findPath(playerPos, spec:getPosition(), 7, { ignoreNonPathable = true, precision = 1 }) local path = findPath(playerPos, spec:getPosition(), 7, { ignoreNonPathable = true, precision = 1 })
if path then if path then
local dist = getDistanceBetween(pos, spec:getPosition()) local dist = getDistanceBetween(pos, spec:getPosition())
@ -193,8 +195,7 @@ CaveBot.registerAction("goto", "green", function(value, retries, prev)
end end
g_game.setChaseMode(1) g_game.setChaseMode(1)
CaveBot.setOff() CaveBot.setOff()
antiTrapTriggered = true schedule(1000, function() CaveBot.setOn() end)
return "retry"
else else
return false -- no other way return false -- no other way
end end
@ -234,13 +235,6 @@ CaveBot.registerAction("goto", "green", function(value, retries, prev)
return "retry" return "retry"
end) end)
onAttackingCreatureChange(function(creature, oldCreature)
if antiTrapTriggered then
CaveBot.setOn()
antiTrapTriggered = false
end
end)
CaveBot.registerAction("use", "#FFB272", function(value, retries, prev) CaveBot.registerAction("use", "#FFB272", function(value, retries, prev)
local pos = regexMatch(value, "\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)") local pos = regexMatch(value, "\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)")
if not pos[1] then if not pos[1] then

View File

@ -1,5 +1,7 @@
CaveBot.Extensions.Bank = {} CaveBot.Extensions.Bank = {}
local balance = 0
CaveBot.Extensions.Bank.setup = function() CaveBot.Extensions.Bank.setup = function()
CaveBot.registerAction("bank", "#db5a5a", function(value, retries) CaveBot.registerAction("bank", "#db5a5a", function(value, retries)
local data = string.split(value, ",") local data = string.split(value, ",")
@ -7,7 +9,9 @@ CaveBot.Extensions.Bank.setup = function()
local amount = 0 local amount = 0
local actionType local actionType
local npcName local npcName
if #data ~= 3 and #data ~= 2 then local transferName
local balanceLeft
if #data ~= 3 and #data ~= 2 and #data ~= 4 then
warn("CaveBot[Bank]: incorrect value!") warn("CaveBot[Bank]: incorrect value!")
return false return false
else else
@ -16,10 +20,14 @@ CaveBot.Extensions.Bank.setup = function()
if #data == 3 then if #data == 3 then
amount = tonumber(data[3]:trim()) amount = tonumber(data[3]:trim())
end end
if #data == 4 then
transferName = data[3]:trim()
balanceLeft = tonumber(data[4]:trim())
end
end end
if actionType ~= "withdraw" and actionType ~= "deposit" then if actionType ~= "withdraw" and actionType ~= "deposit" and actionType ~= "transfer" then
warn("CaveBot[Bank]: incorrect action type! should be withdraw/deposit, is: " .. actionType) warn("CaveBot[Bank]: incorrect action type! should be withdraw/deposit/transfer, is: " .. actionType)
return false return false
elseif actionType == "withdraw" then elseif actionType == "withdraw" then
local value = tonumber(amount) local value = tonumber(amount)
@ -48,16 +56,37 @@ CaveBot.Extensions.Bank.setup = function()
CaveBot.Conversation("hi", "deposit all", "yes") CaveBot.Conversation("hi", "deposit all", "yes")
CaveBot.delay(storage.extras.talkDelay*3) CaveBot.delay(storage.extras.talkDelay*3)
return true return true
else elseif actionType == "withdraw" then
CaveBot.Conversation("hi", "withdraw", value, "yes") CaveBot.Conversation("hi", "withdraw", value, "yes")
CaveBot.delay(storage.extras.talkDelay*4) CaveBot.delay(storage.extras.talkDelay*4)
return true return true
else
-- first check balance
CaveBot.Conversation("hi", "balance")
schedule(5000, function()
local amountToTransfer = balance - balanceLeft
if amountToTransfer <= 0 then
warn("CaveBot[Bank] Not enough gold to transfer! proceeding")
return false
end
CaveBot.Conversation("hi", "transfer", amountToTransfer, transferName, "yes")
warn("CaveBot[Bank] transferred "..amountToTransfer.." gold to: "..transferName)
end)
CaveBot.delay(storage.extras.talkDelay*11)
return true
end end
end) end)
CaveBot.Editor.registerAction("bank", "bank", { CaveBot.Editor.registerAction("bank", "bank", {
value="action, NPC name", value="action, NPC name",
title="Banker", title="Banker",
description="action type(withdraw/deposit), NPC name, if withdraw: amount", description="action type(withdraw/deposit/transfer), NPC name, (if withdraw: amount|if transfer: name, balance left)",
}) })
end end
onTalk(function(name, level, mode, text, channelId, pos)
if mode == 51 and text:find("Your account balance is") then
balance = getFirstNumberInText(text)
end
end)

View File

@ -189,6 +189,149 @@ CaveBot.getCurrentProfile = function()
return storage._configs.cavebot_configs.selected return storage._configs.cavebot_configs.selected
end end
CaveBot.lastReachedLabel = function()
return vBot.lastLabel
end
CaveBot.gotoNextWaypointInRange = function()
local currentAction = ui.list:getFocusedChild()
local index = ui.list:getChildIndex(currentAction)
local actions = ui.list:getChildren()
-- start searching from current index
for i, child in ipairs(actions) do
if i > index then
local text = child:getText()
if string.starts(text, "goto:") then
local re = regexMatch(text, [[(?:goto:)([^,]+),([^,]+),([^,]+)]])
local pos = {x = tonumber(re[1][2]), y = tonumber(re[1][3]), z = tonumber(re[1][4])}
if posz() == pos.z then
if distanceFromPlayer(pos) <= storage.extras.gotoMaxDistance/2 then
return ui.list:focusChild(child)
end
end
end
end
end
-- if not found then damn go from start
for i, child in ipairs(actions) do
if i <= index then
local text = child:getText()
if string.starts(text, "goto:") then
local re = regexMatch(text, [[(?:goto:)([^,]+),([^,]+),([^,]+)]])
local pos = {x = tonumber(re[1][2]), y = tonumber(re[1][3]), z = tonumber(re[1][4])}
if posz() == pos.z then
if distanceFromPlayer(pos) <= storage.extras.gotoMaxDistance/2 then
return ui.list:focusChild(child)
end
end
end
end
end
-- not found
return false
end
CaveBot.getFirstWaypointBeforeLabel = function(label)
label = "label:"..label
label = label:lower()
local actions = ui.list:getChildren()
local index
-- find index of label
for i, child in pairs(actions) do
local name = child:getText():lower()
if name == label then
index = i
break
end
end
-- if there's no index then label was not found
if not index then return false end
for i=1,#actions do
if index - 1 < 1 then
-- did not found any waypoint in range before label
return false
end
local child = ui.list:getChildByIndex(index-i)
if child then
local text = child:getText()
if string.starts(text, "goto:") then
local re = regexMatch(text, [[(?:goto:)([^,]+),([^,]+),([^,]+)]])
local pos = {x = tonumber(re[1][2]), y = tonumber(re[1][3]), z = tonumber(re[1][4])}
if posz() == pos.z then
if distanceFromPlayer(pos) <= storage.extras.gotoMaxDistance/2 then
return ui.list:focusChild(child)
end
end
end
end
end
end
CaveBot.getPreviousLabel = function()
local actions = ui.list:getChildren()
-- check if config is empty
if #actions == 0 then return false end
local currentAction = ui.list:getFocusedChild()
--check we made any progress in waypoints, if no focused or first then no point checking
if not currentAction or currentAction == ui.list:getFirstChild() then return false end
local index = ui.list:getChildIndex(currentAction)
-- if not index then something went wrong and there's no selected child
if not index then return false end
for i=1,#actions do
if index - i < 1 then
-- did not found any waypoint in range before label
return false
end
local child = ui.list:getChildByIndex(index-i)
if child then
if child.action == "label" then
return child.value
end
end
end
end
CaveBot.getNextLabel = function()
local actions = ui.list:getChildren()
-- check if config is empty
if #actions == 0 then return false end
local currentAction = ui.list:getFocusedChild() or ui.list:getFirstChild()
local index = ui.list:getChildIndex(currentAction)
-- if not index then something went wrong
if not index then return false end
for i=1,#actions do
if index + i > #actions then
-- did not found any waypoint in range before label
return false
end
local child = ui.list:getChildByIndex(index+i)
if child then
if child.action == "label" then
return child.value
end
end
end
end
local botConfigName = modules.game_bot.contentsPanel.config:getCurrentOption().text local botConfigName = modules.game_bot.contentsPanel.config:getCurrentOption().text
CaveBot.setCurrentProfile = function(name) CaveBot.setCurrentProfile = function(name)
if not g_resources.fileExists("/bot/"..botConfigName.."/cavebot_configs/"..name..".cfg") then if not g_resources.fileExists("/bot/"..botConfigName.."/cavebot_configs/"..name..".cfg") then

View File

@ -6,7 +6,7 @@ CaveBot.Extensions.DWithdraw.setup = function()
local data = string.split(value, ",") local data = string.split(value, ",")
if retries > 600 then if retries > 600 then
print("CaveBot[DepotWithdraw]: actions limit reached, proceeding") print("CaveBot[DepotWithdraw]: actions limit reached, proceeding")
return true return false
end end
local destContainer local destContainer
local depotContainer local depotContainer
@ -32,7 +32,7 @@ CaveBot.Extensions.DWithdraw.setup = function()
end end
end end
print("CaveBot[DepotWithdraw]: cap limit reached, proceeding") print("CaveBot[DepotWithdraw]: cap limit reached, proceeding")
return true return false
end end
-- containers -- containers
@ -74,7 +74,7 @@ CaveBot.Extensions.DWithdraw.setup = function()
end end
end end
print("CaveBot[DepotWithdraw]: loot containers full!") print("CaveBot[DepotWithdraw]: loot containers full!")
return true return false
end end
if not CaveBot.OpenDepotBox(indexDp) then if not CaveBot.OpenDepotBox(indexDp) then

View File

@ -0,0 +1,111 @@
-- imbuing window should be handled separatly
-- reequiping should be handled separatly (ie. equipment manager)
CaveBot.Extensions.Imbuing = {}
local SHRINES = {25060, 25061, 25182, 25183}
local currentIndex = 1
local shrine = nil
local item = nil
local currentId = 0
local triedToTakeOff = false
local destination = nil
local function reset()
EquipManager.setOn()
shrine = nil
currentIndex = 1
item = nil
currentId = 0
triedToTakeOff = false
destination = nil
end
CaveBot.Extensions.Imbuing.setup = function()
CaveBot.registerAction("imbuing", "red", function(value, retries)
local data = string.split(value, ",")
local ids = {}
if #data == 0 then
warn("CaveBot[Imbuing] no items added, proceeding")
reset()
return false
end
-- setting of equipment manager so it wont disturb imbuing process
EquipManager.setOff()
-- convert to number
for i, id in ipairs(data) do
id = tonumber(id)
if not table.find(ids, id) then
table.insert(ids, id)
end
end
-- all items imbued, can proceed
if currentIndex > #ids then
warn("CaveBot[Imbuing] used shrine on all items, proceeding")
reset()
return true
end
for _, tile in ipairs(g_map.getTiles(posz())) do
for _, item in ipairs(tile:getItems()) do
local id = item:getId()
if table.find(SHRINES, id) then
shrine = item
break
end
end
end
-- if not shrine
if not shrine then
warn("CaveBot[Imbuing] shrine not found! proceeding")
reset()
return false
end
destination = shrine:getPosition()
currentId = ids[currentIndex]
item = findItem(currentId)
-- maybe equipped? try to take off
if not item then
-- did try before, still not found so item is unavailable
if triedToTakeOff then
warn("CaveBot[Imbuing] item not found! proceeding")
reset()
return false
end
triedToTakeOff = true
g_game.equipItemId(currentId)
delay(1000)
return "retry"
end
-- we are past unequiping so just in case we were forced before, reset var
triedToTakeOff = false
-- reaching shrine
if not CaveBot.MatchPosition(destination, 1) then
CaveBot.GoTo(destination, 1)
delay(200)
return "retry"
end
useWith(shrine, item)
currentIndex = currentIndex + 1
warn("CaveBot[Imbuing] Using shrine on item: "..currentId)
delay(2000)
return "retry"
end)
CaveBot.Editor.registerAction("imbuing", "imbuing", {
value="item id 1, item id 2",
title="Auto Imbuing",
description="insert below item ids to be imbued, separated by comma",
})
end

View File

@ -56,6 +56,15 @@ TargetBot.Looting.update = function(data)
ui.minCapacityPanel.value:setText(data['minCapacity'] or 100) ui.minCapacityPanel.value:setText(data['minCapacity'] or 100)
TargetBot.Looting.updateItemsAndContainers() TargetBot.Looting.updateItemsAndContainers()
dontSave = false dontSave = false
--vBot
vBot.lootConainers = {}
vBot.lootItems = {}
for i, item in ipairs(ui.containers:getItems()) do
table.insert(vBot.lootConainers, item['id'])
end
for i, item in ipairs(ui.items:getItems()) do
table.insert(vBot.lootItems, item['id'])
end
end end
TargetBot.Looting.save = function(data) TargetBot.Looting.save = function(data)

View File

@ -890,6 +890,10 @@ if rootWidget then
currentSettings.PvpSafe = not currentSettings.PvpSafe currentSettings.PvpSafe = not currentSettings.PvpSafe
settingsUI.PvpSafe:setChecked(currentSettings.PvpSafe) settingsUI.PvpSafe:setChecked(currentSettings.PvpSafe)
end end
settingsUI.Training.onClick = function(widget)
currentSettings.Training = not currentSettings.Training
settingsUI.Training:setChecked(currentSettings.Training)
end
settingsUI.BlackListSafe.onClick = function(widget) settingsUI.BlackListSafe.onClick = function(widget)
currentSettings.BlackListSafe = not currentSettings.BlackListSafe currentSettings.BlackListSafe = not currentSettings.BlackListSafe
settingsUI.BlackListSafe:setChecked(currentSettings.BlackListSafe) settingsUI.BlackListSafe:setChecked(currentSettings.BlackListSafe)
@ -950,7 +954,7 @@ if rootWidget then
settingsUI.Rotate:setChecked(currentSettings.Rotate) settingsUI.Rotate:setChecked(currentSettings.Rotate)
settingsUI.Kills:setChecked(currentSettings.Kills) settingsUI.Kills:setChecked(currentSettings.Kills)
settingsUI.KillsAmount:setValue(currentSettings.KillsAmount) settingsUI.KillsAmount:setValue(currentSettings.KillsAmount)
settingsUI.Training:setChecked(currentSettings.Training)
end end
loadSettings() loadSettings()
@ -1038,7 +1042,7 @@ function getMonstersInArea(category, posOrCreature, pattern, minHp, maxHp, safeP
if safePattern then if safePattern then
for i, spec in pairs(getSpectators(posOrCreature, safePattern)) do for i, spec in pairs(getSpectators(posOrCreature, safePattern)) do
if spec ~= player and spec:isPlayer() then if spec ~= player and (spec:isPlayer() and not spec:isPartyMember()) then
return 0 return 0
end end
end end
@ -1100,6 +1104,8 @@ macro(100, function()
if not currentSettings.enabled then return end if not currentSettings.enabled then return end
if #currentSettings.attackTable == 0 or isInPz() or not target() or modules.game_cooldown.isGroupCooldownIconActive(1) then return end if #currentSettings.attackTable == 0 or isInPz() or not target() or modules.game_cooldown.isGroupCooldownIconActive(1) then return end
if currentSettings.Training and target() and target():getName():lower():find("training") then return end
if g_game.getClientVersion() < 960 or not currentSettings.Cooldown then if g_game.getClientVersion() < 960 or not currentSettings.Cooldown then
delay(400) delay(400)
end end

View File

@ -504,6 +504,14 @@ SettingsPanel < Panel
width: 245 width: 245
text: PVP safe text: PVP safe
CheckBox
id: Training
anchors.top: prev.bottom
anchors.left: prev.left
margin-top: 8
width: 245
text: Stop when attacking trainers
CheckBox CheckBox
id: BlackListSafe id: BlackListSafe
anchors.top: prev.bottom anchors.top: prev.bottom

View File

@ -0,0 +1,638 @@
local panelName = "EquipperPanel"
local ui = setupUI([[
Panel
height: 19
BotSwitch
id: switch
anchors.top: parent.top
anchors.left: parent.left
text-align: center
width: 130
!text: tr('EQ Manager')
Button
id: setup
anchors.top: prev.top
anchors.left: prev.right
anchors.right: parent.right
margin-left: 3
height: 17
text: Setup
]])
ui:setId(panelName)
if not storage[panelName] then
storage[panelName] = {
enabled = false,
rules = {}
}
end
local config = storage[panelName]
ui.switch:setOn(config.enabled)
ui.switch.onClick = function(widget)
config.enabled = not config.enabled
widget:setOn(config.enabled)
end
local conditions = { -- always add new conditions at the bottom
"Item is available and not worn.", -- nothing 1
"Monsters around is more than: ", -- spinbox 2
"Monsters around is less than: ", -- spinbox 3
"Health precent is below:", -- spinbox 4
"Health precent is above:", -- spinbox 5
"Mana precent is below:", -- spinbox 6
"Mana precent is above:", -- spinbox 7
"Target name is:", -- BotTextEdit 8
"Hotkey is being pressed:", -- BotTextEdit 9
"Player is paralyzed", -- nothing 10
"Player is in protection zone", -- nothing 11
"Players around is more than:", -- spinbox 12
"Players around is less than:" -- spinbox 13
}
local conditionNumber = 1
local optionalConditionNumber = 2
local mainWindow = UI.createWindow("EquipWindow")
mainWindow:hide()
ui.setup.onClick = function()
mainWindow:show()
mainWindow:raise()
mainWindow:focus()
end
mainWindow.closeButton.onClick = function()
mainWindow:hide()
resetFields()
end
local inputPanel = mainWindow.inputPanel
local listPanel = mainWindow.listPanel
inputPanel.optionalCondition:hide()
inputPanel.useSecondCondition.onOptionChange = function(widget, option, data)
if option ~= "-" then
inputPanel.optionalCondition:show()
else
inputPanel.optionalCondition:hide()
end
end
inputPanel.unequip.onClick = function()
local value = 115
local panel = inputPanel.unequipPanel
local height = panel:getHeight()
if height == 0 then
panel:setHeight(value)
mainWindow:setHeight(mainWindow:getHeight()+value)
inputPanel:setHeight(inputPanel:getHeight()+value)
listPanel:setHeight(listPanel:getHeight()+value)
else
panel:setHeight(0)
mainWindow:setHeight(mainWindow:getHeight()-value)
inputPanel:setHeight(inputPanel:getHeight()-value)
listPanel:setHeight(listPanel:getHeight()-value)
end
end
local function setCondition(first, n)
local widget
local spinBox
local textEdit
if first then
widget = inputPanel.condition.description.text
spinBox = inputPanel.condition.spinbox
textEdit = inputPanel.condition.text
else
widget = inputPanel.optionalCondition.description.text
spinBox = inputPanel.optionalCondition.spinbox
textEdit = inputPanel.optionalCondition.text
end
-- reset values after change
spinBox:setValue(0)
textEdit:setText('')
if n == 1 or n == 10 or n == 11 then
spinBox:hide()
textEdit:hide()
elseif n == 9 or n == 8 then
spinBox:hide()
textEdit:show()
if n == 9 then
textEdit:setWidth(75)
else
textEdit:setWidth(200)
end
else
spinBox:show()
textEdit:hide()
end
widget:setText(conditions[n])
end
-- add default text & windows
setCondition(true, 1)
setCondition(false, 2)
-- in/de/crementation buttons
inputPanel.condition.nex.onClick = function()
local max = #conditions
if inputPanel.optionalCondition:isVisible() then
if conditionNumber == max then
if optionalConditionNumber == 1 then
conditionNumber = 2
else
conditionNumber = 1
end
else
local futureNumber = conditionNumber + 1
local safeFutureNumber = conditionNumber + 2 > max and 1 or conditionNumber + 2
conditionNumber = futureNumber ~= optionalConditionNumber and futureNumber or safeFutureNumber
end
else
conditionNumber = conditionNumber == max and 1 or conditionNumber + 1
if optionalConditionNumber == conditionNumber then
optionalConditionNumber = optionalConditionNumber == max and 1 or optionalConditionNumber + 1
setCondition(false, optionalConditionNumber)
end
end
setCondition(true, conditionNumber)
end
inputPanel.condition.pre.onClick = function()
local max = #conditions
if inputPanel.optionalCondition:isVisible() then
if conditionNumber == 1 then
if optionalConditionNumber == max then
conditionNumber = max-1
else
conditionNumber = max
end
else
local futureNumber = conditionNumber - 1
local safeFutureNumber = conditionNumber - 2 < 1 and max or conditionNumber - 2
conditionNumber = futureNumber ~= optionalConditionNumber and futureNumber or safeFutureNumber
end
else
conditionNumber = conditionNumber == 1 and max or conditionNumber - 1
if optionalConditionNumber == conditionNumber then
optionalConditionNumber = optionalConditionNumber == 1 and max or optionalConditionNumber - 1
setCondition(false, optionalConditionNumber)
end
end
setCondition(true, conditionNumber)
end
inputPanel.optionalCondition.nex.onClick = function()
local max = #conditions
if optionalConditionNumber == max then
if conditionNumber == 1 then
optionalConditionNumber = 2
else
optionalConditionNumber = 1
end
else
local futureNumber = optionalConditionNumber + 1
local safeFutureNumber = optionalConditionNumber + 2 > max and 1 or optionalConditionNumber + 2
optionalConditionNumber = futureNumber ~= conditionNumber and futureNumber or safeFutureNumber
end
setCondition(false, optionalConditionNumber)
end
inputPanel.optionalCondition.pre.onClick = function()
local max = #conditions
if optionalConditionNumber == 1 then
if conditionNumber == max then
optionalConditionNumber = max-1
else
optionalConditionNumber = max
end
else
local futureNumber = optionalConditionNumber - 1
local safeFutureNumber = optionalConditionNumber - 2 < 1 and max or optionalConditionNumber - 2
optionalConditionNumber = futureNumber ~= conditionNumber and futureNumber or safeFutureNumber
end
setCondition(false, optionalConditionNumber)
end
listPanel.up.onClick = function()
local n = listPanel.list:getChildIndex(listPanel.list:getFocusedChild())
local t = config.rules
t[n], t[n-1] = t[n-1], t[n]
listPanel.up:setEnabled(false)
listPanel.down:setEnabled(false)
refreshRules()
end
listPanel.down.onClick = function()
local n = listPanel.list:getChildIndex(listPanel.list:getFocusedChild())
local t = config.rules
t[n], t[n+1] = t[n+1], t[n]
listPanel.up:setEnabled(false)
listPanel.down:setEnabled(false)
refreshRules()
end
function getItemsFromBox()
local t = {}
for i, child in ipairs(inputPanel.itemBox:getChildren()) do
local id = child:getItemId()
if id > 100 then
table.insert(t, id)
end
end
return t
end
function refreshItemBox(reset)
local max = 8
local box = inputPanel.itemBox
local childAmount = box:getChildCount()
if reset then
box:destroyChildren()
local widget = UI.createWidget("BotItem", box)
widget.onItemChange = function(widget)
local id = widget:getItemId()
local index = box:getChildIndex(widget)
if id < 100 or (table.find(getItemsFromBox(), id) ~= index) then
widget:destroy()
end
refreshItemBox()
end
return
end
if childAmount == 0 then
local widget = UI.createWidget("BotItem", box)
widget.onItemChange = function(widget)
local id = widget:getItemId()
local index = box:getChildIndex(widget)
if id < 100 or (table.find(getItemsFromBox(), id) ~= index) then
widget:destroy()
end
refreshItemBox()
refreshItemBox()
end
elseif box:getLastChild():getItemId() > 100 and childAmount < max then
local widget = UI.createWidget("BotItem", box)
widget.onItemChange = function(widget)
local id = widget:getItemId()
local index = box:getChildIndex(widget)
if id < 100 or (table.find(getItemsFromBox(), id) ~= index) then
widget:destroy()
end
refreshItemBox()
refreshItemBox()
end
end
end
refreshItemBox()
local function resetFields()
refreshItemBox(true)
inputPanel.name:setText('')
conditionNumber = 1
optionalConditionNumber = 2
setCondition(false, optionalConditionNumber)
setCondition(true, conditionNumber)
inputPanel.useSecondCondition:setCurrentOption("-")
for i, child in pairs(inputPanel.unequipPanel:getChildren()) do
child:setChecked(false)
end
end
-- buttons disabled by default
listPanel.up:setEnabled(false)
listPanel.down:setEnabled(false)
function refreshRules()
local list = listPanel.list
list:destroyChildren()
for i,v in pairs(config.rules) do
local widget = UI.createWidget('Rule', list)
widget:setText(v.name)
widget.remove.onClick = function()
widget:destroy()
table.remove(config.rules, table.find(config.rules, v))
listPanel.up:setEnabled(false)
listPanel.down:setEnabled(false)
refreshRules()
end
widget.visible:setColor(v.visible and "green" or "red")
widget.visible.onClick = function()
v.visible = not v.visible
widget.visible:setColor(v.visible and "green" or "red")
end
widget.enabled:setChecked(v.enabled)
widget.enabled.onClick = function()
v.enabled = not v.enabled
widget.enabled:setChecked(v.enabled)
end
local desc
for i, v in ipairs(v.items) do
if i == 1 then
desc = "items: " .. v
else
desc = desc .. ", " .. v
end
end
widget:setTooltip(desc)
widget.onClick = function()
local panel = listPanel
if #panel.list:getChildren() == 1 then
panel.up:setEnabled(false)
panel.down:setEnabled(false)
elseif panel.list:getChildIndex(panel.list:getFocusedChild()) == 1 then
panel.up:setEnabled(false)
panel.down:setEnabled(true)
elseif panel.list:getChildIndex(panel.list:getFocusedChild()) == #panel.list:getChildren() then
panel.up:setEnabled(true)
panel.down:setEnabled(false)
else
panel.up:setEnabled(true)
panel.down:setEnabled(true)
end
end
widget.onDoubleClick = function()
-- main
conditionNumber = v.mainCondition
setCondition(true, conditionNumber)
if conditionNumber == 8 or conditionNumber == 9 then
inputPanel.condition.text:setText(v.mainValue)
elseif conditionNumber ~= 1 then
inputPanel.condition.spinbox:setValue(v.mainValue)
end
-- relation
inputPanel.useSecondCondition:setCurrentOption(v.relation)
-- optional
if v.relation ~= "-" then
optionalConditionNumber = v.optionalCondition
setCondition(false, optionalConditionNumber)
if optionalConditionNumber == 8 or optionalConditionNumber == 9 then
inputPanel.optionalCondition.text:setText(v.optValue)
elseif optionalConditionNumber ~= 1 then
inputPanel.optionalCondition.spinbox:setValue(v.optValue)
end
end
-- name
inputPanel.name:setText(v.name)
-- items
inputPanel.itemBox:destroyChildren()
for i, item in ipairs(v.items) do
local widget = UI.createWidget("BotItem", inputPanel.itemBox)
widget:setItemId(item)
widget.onItemChange = function(widget)
local id = widget:getItemId()
local index = box:getChildIndex(widget)
if id < 100 or (table.find(getItemsFromBox(), id) ~= index) then
widget:destroy()
end
refreshItemBox()
end
end
-- unequip
if type(v.unequip) == "table" then
for i, tick in ipairs(v.unequip) do
local checkbox = inputPanel.unequipPanel:getChildren()[i]
checkbox:setChecked(tick)
end
end
refreshItemBox()
-- remove value
table.remove(config.rules, table.find(config.rules, v))
refreshRules()
end
end
end
refreshRules()
inputPanel.addButton.onClick = function()
local mainVal
local optVal
local relation = inputPanel.useSecondCondition:getText()
local name = inputPanel.name:getText()
local items = getItemsFromBox()
local unequip = {}
for i, child in pairs(inputPanel.unequipPanel:getChildren()) do
if child:isChecked() then
table.insert(unequip, true)
else
table.insert(unequip, false)
end
end
if conditionNumber == 1 then
mainVal = nil
elseif conditionNumber == 8 then
mainVal = inputPanel.condition.text:getText()
if mainVal:len() == 0 then
return warn("[vBot Equipper] Please fill the name of the creature.")
end
elseif conditionNumber == 9 then
mainVal = inputPanel.condition.text:getText()
if mainVal:len() == 0 then
return warn("[vBot Equipper] Please set correct hotkey.")
end
else
mainVal = inputPanel.condition.spinbox:getValue()
end
if relation ~= "-" then
if optionalConditionNumber == 1 then
optVal = nil
elseif optionalConditionNumber == 8 then
optVal = inputPanel.optionalCondition.text:getText()
if optVal:len() == 0 then
return warn("[vBot Equipper] Please fill the name of the creature.")
end
elseif optionalConditionNumber == 9 then
optVal = inputPanel.optionalCondition.text:getText()
if optVal:len() == 0 then
return warn("[vBot Equipper] Please set correct hotkey.")
end
else
optVal = inputPanel.optionalCondition.spinbox:getValue()
end
end
if #items == 0 then
return warn("[vBot Equipper] Please add items.")
end
if #name == 0 then
return warn("[vBot Equipper] Please fill name of the profile.")
end
for i, child in pairs(listPanel.list:getChildren()) do
if child:getText() == name then
return warn("[vBot Equipper] There is already rule with this name! Choose different or remove old one.")
end
end
-- add
table.insert(config.rules, {
enabled = true,
visible = true,
mainCondition = conditionNumber,
optionalCondition = optionalConditionNumber,
mainValue = mainVal,
optValue = optVal,
relation = relation,
items = items,
name = name,
unequip = unequip
})
refreshRules()
resetFields()
end
--"Item is available and not worn.", -- nothing 1
--"Monsters around is more than: ", -- spinbox 2
--"Monsters around is less than: ", -- spinbox 3
--"Health precent is below:", -- spinbox 4
--"Health precent is above:", -- spinbox 5
--"Mana precent is below:", -- spinbox 6
--"Mana precent is above:", -- spinbox 7
--"Target name is:", -- BotTextEdit 8
--"Hotkey is being pressed:", -- Button 9
--"Player is paralyzed", -- nothing 10
local pressedKey = ""
onKeyPress(function(keys)
pressedKey = keys
end)
local function interpreteCondition(n, v)
local hp = hppercent()
local mp = manapercent()
local mobs = getMonsters()
local players = getPlayers()
if n == 1 then
return true
elseif n == 2 then
return mobs > v
elseif n == 3 then
return mobs < v
elseif n == 4 then
return hp < v
elseif n == 5 then
return hp > v
elseif n == 6 then
return mp < v
elseif n == 7 then
return mp > v
elseif n == 8 then
return target() and target():getName():lower() == v:lower() or false
elseif n == 9 then
return pressedKey == v
elseif n == 10 then
return isParalyzed()
elseif n == 11 then
return isInPz()
elseif n == 12 then
return players > v
elseif n == 13 then
return players < v
end
end
local function finalCheck(first,relation,second)
if relation == "-" then
return first
elseif relation == "and" then
return first and second
elseif relation == "or" then
return first or second
end
end
local function isEquipped(id)
local t = {getNeck(), getHead(), getBody(), getRight(), getLeft(), getLeg(), getFeet(), getFinger(), getAmmo()}
local ids = {id, getInactiveItemId(id), getActiveItemId(id)}
for i, slot in pairs(t) do
if slot and table.find(ids, slot:getId()) then
return true
end
end
return false
end
local function unequipItem(table)
--[[
head
neck
torso
left
right
legs
finger
ammo slot
boots
]]
local slots = {getHead(), getNeck(), getBody(), getLeft(), getRight(), getLeg(), getFinger(), getAmmo(), getFeet()}
if type(table) ~= "table" then return end
for i, slot in pairs(table) do
local physicalSlot = slots[i]
if slot and physicalSlot then
g_game.equipItemId(physicalSlot:getId())
return true
end
end
return false
end
EquipManager = macro(50, function()
if not config.enabled then return end
if #config.rules == 0 then return end
for i, rule in ipairs(config.rules) do
if rule.enabled then
local firstCondition = interpreteCondition(rule.mainCondition, rule.mainValue)
local optionalCondition = nil
if rule.relation ~= "-" then
optionalCondition = interpreteCondition(rule.optionalCondition, rule.optValue)
end
if finalCheck(firstCondition, rule.relation, optionalCondition) then
if unequipItem(rule.unequip) == true then
delay(200)
return
end
for i, item in ipairs(rule.items) do
if not isEquipped(item) then
if rule.visible then
if itemAmount(item) > 0 then
delay(200)
return g_game.equipItemId(item)
end
else
delay(200)
return g_game.equipItemId(item)
end
end
end
return
end
end
end
pressedKey = ""
end)

View File

@ -11,7 +11,6 @@
br, Vithrax br, Vithrax
]] ]]
local rightPanelButtons = modules.game_buttons.buttonsWindow.contentsPanel.buttons
local analyzerButton local analyzerButton
--destroy old windows --destroy old windows
@ -75,7 +74,8 @@ local toggleAnalyzer = function(window)
end end
-- create analyzers button -- create analyzers button
analyzerButton = rightPanelButtons.botAnalyzersButton analyzerButton = modules.game_buttons.buttonsWindow.contentsPanel and modules.game_buttons.buttonsWindow.contentsPanel.buttons.botAnalyzersButton
analyzerButton = analyzerButton or modules.client_topmenu.getButton("botAnalyzersButton")
if analyzerButton then if analyzerButton then
analyzerButton:destroy() analyzerButton:destroy()
end end
@ -85,7 +85,6 @@ analyzerButton = modules.client_topmenu.addRightGameToggleButton('botAnalyzersBu
analyzerButton:setOn(false) analyzerButton:setOn(false)
--toggles window --toggles window
local button = mainWindow.contentsPanel
mainWindow.contentsPanel.HuntingAnalyzer.onClick = function() mainWindow.contentsPanel.HuntingAnalyzer.onClick = function()
toggleAnalyzer(huntingWindow) toggleAnalyzer(huntingWindow)
end end
@ -901,6 +900,7 @@ onTextMessage(function(mode, text)
end) end)
function hourVal(v) function hourVal(v)
v = v or 0
return (v/uptime)*3600 return (v/uptime)*3600
end end

View File

@ -32,6 +32,7 @@ dofile("/cavebot/lure.lua")
dofile("/cavebot/bank.lua") dofile("/cavebot/bank.lua")
dofile("/cavebot/clear_tile.lua") dofile("/cavebot/clear_tile.lua")
dofile("/cavebot/tasker.lua") dofile("/cavebot/tasker.lua")
dofile("/cavebot/imbuing.lua")
-- main cavebot file, must be last -- main cavebot file, must be last
dofile("/cavebot/cavebot.lua") dofile("/cavebot/cavebot.lua")

View File

@ -0,0 +1,374 @@
ConditionBoxPopupMenu < ComboBoxPopupMenu
ConditionBoxPopupMenuButton < ComboBoxPopupMenuButton
ConditionBox < ComboBox
@onSetup: |
self:addOption("-")
self:addOption("and")
self:addOption("or")
PreButton < PreviousButton
background: #363636
height: 15
NexButton < NextButton
background: #363636
height: 15
CondidionLabel < FlatPanel
padding: 1
height: 15
Label
id: text
anchors.fill: parent
text-align: center
font: verdana-11px-rounded
background: #363636
Rule < UIWidget
background-color: alpha
text-offset: 18 2
focusable: true
height: 16
text-align: left
font: verdana-11px-rounded
CheckBox
id: enabled
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
width: 15
height: 15
margin-top: 2
margin-left: 3
tooltip: Entry enabled/disabled
$focus:
background-color: #00000055
Button
id: remove
text: X
anchors.right: parent.right
margin-right: 15
width: 14
height: 14
text-align: center
tooltip: Remove entry
anchors.verticalCenter: parent.verticalCenter
Button
id: visible
text: V
anchors.right: prev.left
margin-right: 3
width: 14
height: 14
text-align: center
tooltip: Items must be visible
anchors.verticalCenter: parent.verticalCenter
ConditionPanel < Panel
height: 55
NexButton
id: nex
anchors.top: parent.top
margin-top: 5
anchors.right: parent.right
PreButton
id: pre
anchors.top: parent.top
margin-top: 5
anchors.left: parent.left
CondidionLabel
id: description
anchors.top: parent.top
margin-top: 5
anchors.left: prev.right
anchors.right: nex.left
margin-left: 3
margin-right: 3
SpinBox
id: spinbox
anchors.top: description.bottom
margin-top: 5
anchors.horizontalCenter: parent.horizontalCenter
width: 100
text-align: center
minimum: 0
maximum: 100
step: 1
focusable: true
BotTextEdit
id: text
anchors.top: description.bottom
margin-top: 5
anchors.horizontalCenter: parent.horizontalCenter
width: 200
text-align: center
ListPanel < FlatPanel
size: 270 265
padding-left: 10
padding-right: 10
padding-bottom: 10
Label
id: title
anchors.verticalCenter: parent.top
anchors.left: parent.left
text: Rules List
font: verdana-11px-rounded
color: #FABD02
Label
id: mainLabel
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
margin-top: 10
margin-left: 2
!text: tr('More important methods come first.')
text-align: left
font: verdana-11px-rounded
color: #aeaeae
TextList
id: list
anchors.fill: parent
margin-top: 25
margin-bottom: 18
vertical-scrollbar: listScrollBar
padding: 2
VerticalScrollBar
id: listScrollBar
anchors.top: list.top
anchors.bottom: list.bottom
anchors.right: list.right
step: 14
pixels-scroll: true
Button
id: up
anchors.right: parent.right
anchors.top: list.bottom
size: 60 17
text: Move Up
text-align: center
font: cipsoftFont
margin-top: 5
Button
id: down
anchors.right: prev.left
anchors.verticalCenter: prev.verticalCenter
size: 60 17
margin-right: 5
text: Move Down
text-align: center
font: cipsoftFont
Unequip < Panel
height: 0
padding: 5
layout:
type: verticalBox
CheckBox
text: Head Slot
CheckBox
text: Neck Slot
CheckBox
text: Torso Slot
CheckBox
text: Left Hand Slot
CheckBox
text: Right Hand Slot
CheckBox
text: Legs Slot
CheckBox
text: Finger Slot
CheckBox
text: Ammo Slot
CheckBox
text: Feet Slot
InputPanel < FlatPanel
size: 270 265
padding-left: 10
padding-right: 10
padding-bottom: 10
Label
id: title
anchors.verticalCenter: parent.top
anchors.left: parent.left
text: Input Panel
font: verdana-11px-rounded
color: #FF0000
Panel
id: itemBox
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
margin-top: 10
height: 40
layout:
type: grid
cell-size: 34 34
cell-spacing: 2
num-columns: 9
Button
id: unequip
anchors.top: prev.bottom
anchors.left: parent.left
text: Unequip
height: 16
width: 70
Label
id: mainLabel
anchors.left: prev.right
anchors.right: parent.right
margin-top: 2
anchors.verticalCenter: prev.verticalCenter
margin-left: 2
!text: tr('& Equip above item(s) when:')
text-align: center
font: verdana-11px-rounded
color: #aeaeae
Unequip
id: unequipPanel
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
HorizontalSeparator
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin-top: 4
ConditionPanel
id: condition
anchors.left: parent.left
anchors.right: parent.right
anchors.top: unequipPanel.bottom
margin-top: 8
HorizontalSeparator
anchors.verticalCenter: next.verticalCenter
anchors.left: parent.left
anchors.right: parent.right
ConditionBox
id: useSecondCondition
anchors.top: condition.bottom
margin-top: 3
anchors.horizontalCenter: parent.horizontalCenter
width: 50
ConditionPanel
id: optionalCondition
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin-top: 8
HorizontalSeparator
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
BotTextEdit
id: name
anchors.left: parent.left
anchors.bottom: parent.bottom
width: 175
Label
anchors.horizontalCenter: prev.horizontalCenter
anchors.bottom: prev.top
margin-bottom: 2
text-align: center
text: Profile Name
font: verdana-11px-rounded
color: #aeaeae
Button
id: addButton
anchors.top: name.top
anchors.bottom: name.bottom
anchors.left: name.right
margin-left: 3
anchors.right: parent.right
text: Add
tooltip: On add above rule will be listed as Profile name - use friendly one!
EquipWindow < MainWindow
size: 600 345
text: Equipment Manager
@onEscape: self:hide()
ListPanel
id: listPanel
anchors.left: parent.left
anchors.top: parent.top
VerticalSeparator
anchors.top: parent.top
anchors.bottom: bottomSep.top
margin-bottom: 5
anchors.horizontalCenter: parent.horizontalCenter
InputPanel
id: inputPanel
anchors.right: parent.right
anchors.top: parent.top
HorizontalSeparator
id: bottomSep
anchors.right: parent.right
anchors.left: parent.left
anchors.bottom: closeButton.top
margin-bottom: 8
Button
id: closeButton
!text: tr('Close')
font: cipsoftFont
anchors.right: parent.right
anchors.bottom: parent.bottom
size: 45 21
margin-top: 15
margin-right: 5

View File

@ -93,7 +93,7 @@ addItem("scythe", "Scythe Item", 9596, leftPanel)
addScrollBar("talkDelay", "Global NPC Talk Delay", 0, 2000, 1000, leftPanel) addScrollBar("talkDelay", "Global NPC Talk Delay", 0, 2000, 1000, leftPanel)
addScrollBar("looting", "Max Loot Distance", 0, 50, 40, leftPanel) addScrollBar("looting", "Max Loot Distance", 0, 50, 40, leftPanel)
addScrollBar("huntRoutes", "Hunting Routes Limit", 0, 300, 50, leftPanel) addScrollBar("huntRoutes", "Hunting Routes Limit", 0, 300, 50, leftPanel)
addScrollBar("killUnder", "Kill monsters below", 0, 100, 30, leftPanel) addScrollBar("killUnder", "Kill monsters below", 0, 100, 1, leftPanel)
addScrollBar("gotoMaxDistance", "Max GoTo Distance", 0, 127, 30, leftPanel) addScrollBar("gotoMaxDistance", "Max GoTo Distance", 0, 127, 30, leftPanel)
addCheckBox("lootLast", "Start loot from last corpse", true, leftPanel) addCheckBox("lootLast", "Start loot from last corpse", true, leftPanel)
addCheckBox("joinBot", "Join TargetBot and CaveBot", false, leftPanel) addCheckBox("joinBot", "Join TargetBot and CaveBot", false, leftPanel)

View File

@ -930,7 +930,7 @@ LootItems = {
["sickle"] = 3, ["sickle"] = 3,
["sight of surrender's eye"] = 3000, ["sight of surrender's eye"] = 3000,
["signet ring"] = 480000, ["signet ring"] = 480000,
["silencer claws"] = 25000, ["silencer claws"] = 390,
["silencer resonating chamber"] = 600, ["silencer resonating chamber"] = 600,
["silken bookmark"] = 1300, ["silken bookmark"] = 1300,
["silkweaver bow"] = 12000, ["silkweaver bow"] = 12000,

View File

@ -1,3 +1,3 @@
UI.Label("vBot v4.0 \n Vithrax#5814") UI.Label("vBot v4.1 \n Vithrax#5814")
UI.Button("Official OTCv8 Discord!", function() g_platform.openUrl("https://discord.gg/yhqBE4A") end) UI.Button("Official OTCv8 Discord!", function() g_platform.openUrl("https://discord.gg/yhqBE4A") end)
UI.Separator() UI.Separator()

View File

@ -86,13 +86,6 @@ end
-- variables for config -- variables for config
local config = config
local pushDelay = tonumber(config.pushDelay)
local rune = tonumber(config.pushMaxRuneId)
local customMwall = config.mwallBlockId
local key = config.pushMaxKey
local enabled = config.enabled
local fieldTable = {2118, 105, 2122} local fieldTable = {2118, 105, 2122}
local cleanTile = nil local cleanTile = nil
@ -142,8 +135,8 @@ end
-- to mark -- to mark
local hold = 0 local hold = 0
onKeyDown(function(keys) onKeyDown(function(keys)
if not enabled then return end if not config.enabled then return end
if keys ~= key then return end if keys ~= config.pushMaxKey then return end
hold = now hold = now
local tile = getTileUnderCursor() local tile = getTileUnderCursor()
if not tile then return end if not tile then return end
@ -171,8 +164,8 @@ end)
-- mark tile to throw anything from it -- mark tile to throw anything from it
onKeyPress(function(keys) onKeyPress(function(keys)
if not enabled then return end if not config.enabled then return end
if keys ~= key then return end if keys ~= config.pushMaxKey then return end
local tile = getTileUnderCursor() local tile = getTileUnderCursor()
if not tile then return end if not tile then return end
@ -188,7 +181,7 @@ onKeyPress(function(keys)
end) end)
onCreaturePositionChange(function(creature, newPos, oldPos) onCreaturePositionChange(function(creature, newPos, oldPos)
if not enabled then return end if not config.enabled then return end
if creature == player then if creature == player then
resetData() resetData()
end end
@ -199,7 +192,11 @@ onCreaturePositionChange(function(creature, newPos, oldPos)
end) end)
macro(50, function() macro(50, function()
if not enabled then return end if not config.enabled then return end
local pushDelay = tonumber(config.pushDelay)
local rune = tonumber(config.pushMaxRuneId)
local customMwall = config.mwallBlockId
if cleanTile then if cleanTile then
local tilePos = cleanTile:getPosition() local tilePos = cleanTile:getPosition()

View File

@ -299,7 +299,7 @@ end
function onLevelChange(localPlayer, value, percent) function onLevelChange(localPlayer, value, percent)
setSkillValue('level', value) setSkillValue('level', value)
local text = tr('You have %s percent to go', 100 - percent) .. '\n' .. local text = tr('You have %s percent to go', 100 - percent) .. '\n' ..
tr('%s of experience left', comma_value(expToAdvance(localPlayer:getLevel(), localPlayer:getExperience()))) comma_value(expToAdvance(localPlayer:getLevel(), localPlayer:getExperience())) .. tr(' of experience left')
if localPlayer.expSpeed ~= nil then if localPlayer.expSpeed ~= nil then
local expPerHour = math.floor(localPlayer.expSpeed * 3600) local expPerHour = math.floor(localPlayer.expSpeed * 3600)
@ -308,7 +308,7 @@ function onLevelChange(localPlayer, value, percent)
local hoursLeft = (nextLevelExp - localPlayer:getExperience()) / expPerHour local hoursLeft = (nextLevelExp - localPlayer:getExperience()) / expPerHour
local minutesLeft = math.floor((hoursLeft - math.floor(hoursLeft))*60) local minutesLeft = math.floor((hoursLeft - math.floor(hoursLeft))*60)
hoursLeft = math.floor(hoursLeft) hoursLeft = math.floor(hoursLeft)
text = text .. '\n' .. tr('%d of experience per hour', comma_value(expPerHour)) text = text .. '\n' .. comma_value(expPerHour) .. ' of experience per hour'
text = text .. '\n' .. tr('Next level in %d hours and %d minutes', hoursLeft, minutesLeft) text = text .. '\n' .. tr('Next level in %d hours and %d minutes', hoursLeft, minutesLeft)
end end
end end

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.