mirror of
https://github.com/OTCv8/otclientv8.git
synced 2025-04-29 18:59:20 +02:00
325 lines
11 KiB
Lua
325 lines
11 KiB
Lua
TargetBot.Looting = {}
|
|
TargetBot.Looting.list = {} -- list of containers to loot
|
|
|
|
local ui
|
|
local items = {}
|
|
local containers = {}
|
|
local itemsById = {}
|
|
local containersById = {}
|
|
local dontSave = false
|
|
|
|
TargetBot.Looting.setup = function()
|
|
ui = UI.createWidget("TargetBotLootingPanel")
|
|
UI.Container(TargetBot.Looting.onItemsUpdate, true, nil, ui.items)
|
|
UI.Container(TargetBot.Looting.onContainersUpdate, true, nil, ui.containers)
|
|
ui.everyItem.onClick = function()
|
|
ui.everyItem:setOn(not ui.everyItem:isOn())
|
|
TargetBot.save()
|
|
end
|
|
ui.maxDangerPanel.value.onTextChange = function()
|
|
local value = tonumber(ui.maxDangerPanel.value:getText())
|
|
if not value then
|
|
ui.maxDangerPanel.value:setText(0)
|
|
end
|
|
if dontSave then return end
|
|
TargetBot.save()
|
|
end
|
|
ui.minCapacityPanel.value.onTextChange = function()
|
|
local value = tonumber(ui.minCapacityPanel.value:getText())
|
|
if not value then
|
|
ui.minCapacityPanel.value:setText(0)
|
|
end
|
|
if dontSave then return end
|
|
TargetBot.save()
|
|
end
|
|
end
|
|
|
|
TargetBot.Looting.onItemsUpdate = function()
|
|
if dontSave then return end
|
|
TargetBot.save()
|
|
TargetBot.Looting.updateItemsAndContainers()
|
|
end
|
|
|
|
TargetBot.Looting.onContainersUpdate = function()
|
|
if dontSave then return end
|
|
TargetBot.save()
|
|
TargetBot.Looting.updateItemsAndContainers()
|
|
end
|
|
|
|
TargetBot.Looting.update = function(data)
|
|
dontSave = true
|
|
TargetBot.Looting.list = {}
|
|
ui.items:setItems(data['items'] or {})
|
|
ui.containers:setItems(data['containers'] or {})
|
|
ui.everyItem:setOn(data['everyItem'])
|
|
ui.maxDangerPanel.value:setText(data['maxDanger'] or 10)
|
|
ui.minCapacityPanel.value:setText(data['minCapacity'] or 100)
|
|
TargetBot.Looting.updateItemsAndContainers()
|
|
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
|
|
|
|
TargetBot.Looting.save = function(data)
|
|
data['items'] = ui.items:getItems()
|
|
data['containers'] = ui.containers:getItems()
|
|
data['maxDanger'] = tonumber(ui.maxDangerPanel.value:getText())
|
|
data['minCapacity'] = tonumber(ui.minCapacityPanel.value:getText())
|
|
data['everyItem'] = ui.everyItem:isOn()
|
|
end
|
|
|
|
TargetBot.Looting.updateItemsAndContainers = function()
|
|
items = ui.items:getItems()
|
|
containers = ui.containers:getItems()
|
|
itemsById = {}
|
|
containersById = {}
|
|
for i, item in ipairs(items) do
|
|
itemsById[item.id] = 1
|
|
end
|
|
for i, container in ipairs(containers) do
|
|
containersById[container.id] = 1
|
|
end
|
|
end
|
|
|
|
local waitTill = 0
|
|
local waitingForContainer = nil
|
|
local status = ""
|
|
local lastFoodConsumption = 0
|
|
|
|
TargetBot.Looting.getStatus = function()
|
|
return status
|
|
end
|
|
|
|
TargetBot.Looting.process = function(targets, dangerLevel)
|
|
if (not items[1] and not ui.everyItem:isOn()) or not containers[1] then
|
|
status = ""
|
|
return false
|
|
end
|
|
if dangerLevel > tonumber(ui.maxDangerPanel.value:getText()) then
|
|
status = "High danger"
|
|
return false
|
|
end
|
|
if player:getFreeCapacity() < tonumber(ui.minCapacityPanel.value:getText()) then
|
|
status = "No cap"
|
|
TargetBot.Looting.list = {}
|
|
return false
|
|
end
|
|
local loot = storage.extras.lootLast and TargetBot.Looting.list[#TargetBot.Looting.list] or TargetBot.Looting.list[1]
|
|
if loot == nil then
|
|
status = ""
|
|
return false
|
|
end
|
|
|
|
if waitTill > now then
|
|
return true
|
|
end
|
|
local containers = g_game.getContainers()
|
|
local lootContainers = TargetBot.Looting.getLootContainers(containers)
|
|
|
|
-- check if there's container for loot and has empty space for it
|
|
if not lootContainers[1] then
|
|
-- there's no space, don't loot
|
|
status = "No space"
|
|
return false
|
|
end
|
|
|
|
status = "Looting"
|
|
|
|
for index, container in pairs(containers) do
|
|
if container.lootContainer then
|
|
TargetBot.Looting.lootContainer(lootContainers, container)
|
|
return true
|
|
end
|
|
end
|
|
|
|
local pos = player:getPosition()
|
|
local dist = math.max(math.abs(pos.x-loot.pos.x), math.abs(pos.y-loot.pos.y))
|
|
local maxRange = storage.extras.looting or 40
|
|
if loot.tries > 30 or loot.pos.z ~= pos.z or dist > maxRange then
|
|
table.remove(TargetBot.Looting.list, storage.extras.lootLast and #TargetBot.Looting.list or 1)
|
|
return true
|
|
end
|
|
|
|
local tile = g_map.getTile(loot.pos)
|
|
if dist >= 3 or not tile then
|
|
loot.tries = loot.tries + 1
|
|
TargetBot.walkTo(loot.pos, 20, { ignoreNonPathable = true, precision = 2 })
|
|
return true
|
|
end
|
|
|
|
local container = tile:getTopUseThing()
|
|
if not container or not container:isContainer() then
|
|
table.remove(TargetBot.Looting.list, storage.extras.lootLast and #TargetBot.Looting.list or 1)
|
|
return true
|
|
end
|
|
|
|
g_game.open(container)
|
|
waitTill = now + math.min(g_game.getPing(),100)
|
|
waitingForContainer = container:getId()
|
|
|
|
return true
|
|
end
|
|
|
|
TargetBot.Looting.getLootContainers = function(containers)
|
|
local lootContainers = {}
|
|
local openedContainersById = {}
|
|
local toOpen = nil
|
|
for index, container in pairs(containers) do
|
|
openedContainersById[container:getContainerItem():getId()] = 1
|
|
if containersById[container:getContainerItem():getId()] and not container.lootContainer then
|
|
if container:getItemsCount() < container:getCapacity() or container:hasPages() then
|
|
table.insert(lootContainers, container)
|
|
else -- it's full, open next container if possible
|
|
for slot, item in ipairs(container:getItems()) do
|
|
if item:isContainer() and containersById[item:getId()] then
|
|
toOpen = {item, container}
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
if not lootContainers[1] then
|
|
if toOpen then
|
|
g_game.open(toOpen[1], toOpen[2])
|
|
waitTill = now + 500 -- wait 0.5s
|
|
return lootContainers
|
|
end
|
|
-- check containers one more time, maybe there's any loot container
|
|
for index, container in pairs(containers) do
|
|
if not containersById[container:getContainerItem():getId()] and not container.lootContainer then
|
|
for slot, item in ipairs(container:getItems()) do
|
|
if item:isContainer() and containersById[item:getId()] then
|
|
g_game.open(item)
|
|
waitTill = now + 500 -- wait 0.5s
|
|
return lootContainers
|
|
end
|
|
end
|
|
end
|
|
end
|
|
-- can't find any lootContainer, let's check slots, maybe there's one
|
|
for slot = InventorySlotFirst, InventorySlotLast do
|
|
local item = getInventoryItem(slot)
|
|
if item and item:isContainer() and not openedContainersById[item:getId()] then
|
|
-- container which is not opened yet, let's open it
|
|
g_game.open(item)
|
|
waitTill = now + 500 -- wait 0.5s
|
|
return lootContainers
|
|
end
|
|
end
|
|
end
|
|
return lootContainers
|
|
end
|
|
|
|
TargetBot.Looting.lootContainer = function(lootContainers, container)
|
|
-- loot items
|
|
local nextContainer = nil
|
|
for i, item in ipairs(container:getItems()) do
|
|
if item:isContainer() and not itemsById[item:getId()] then
|
|
nextContainer = item
|
|
elseif itemsById[item:getId()] or (ui.everyItem:isOn() and not item:isContainer()) then
|
|
item.lootTries = (item.lootTries or 0) + 1
|
|
if item.lootTries < 5 then -- if can't be looted within 0.5s then skip it
|
|
return TargetBot.Looting.lootItem(lootContainers, item)
|
|
end
|
|
elseif storage.foodItems and storage.foodItems[1] and lastFoodConsumption + 5000 < now then
|
|
for _, food in ipairs(storage.foodItems) do
|
|
if item:getId() == food.id then
|
|
g_game.use(item)
|
|
lastFoodConsumption = now
|
|
return
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- no more items to loot, open next container
|
|
if nextContainer then
|
|
nextContainer.lootTries = (nextContainer.lootTries or 0) + 1
|
|
if nextContainer.lootTries < 2 then -- max 0.6s to open it
|
|
g_game.open(nextContainer, container)
|
|
waitTill = now + 300 -- give it 0.3s to open
|
|
waitingForContainer = nextContainer:getId()
|
|
return
|
|
end
|
|
end
|
|
|
|
-- looting finished, remove container from list
|
|
container.lootContainer = false
|
|
g_game.close(container)
|
|
table.remove(TargetBot.Looting.list, storage.extras.lootLast and #TargetBot.Looting.list or 1)
|
|
end
|
|
|
|
onTextMessage(function(mode, text)
|
|
if TargetBot.isOff() then return end
|
|
if #TargetBot.Looting.list == 0 then return end
|
|
if string.find(text:lower(), "you are not the owner") then -- if we are not the owners of corpse then its a waste of time to try to loot it
|
|
table.remove(TargetBot.Looting.list, storage.extras.lootLast and #TargetBot.Looting.list or 1)
|
|
end
|
|
end)
|
|
|
|
TargetBot.Looting.lootItem = function(lootContainers, item)
|
|
if item:isStackable() then
|
|
local count = item:getCount()
|
|
for _, container in ipairs(lootContainers) do
|
|
for slot, citem in ipairs(container:getItems()) do
|
|
if item:getId() == citem:getId() and citem:getCount() < 100 then
|
|
g_game.move(item, container:getSlotPosition(slot - 1), count)
|
|
waitTill = now + 300 -- give it 0.3s to move item
|
|
return
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local container = lootContainers[1]
|
|
g_game.move(item, container:getSlotPosition(container:getItemsCount()), 1)
|
|
waitTill = now + 300 -- give it 0.3s to move item
|
|
end
|
|
|
|
onContainerOpen(function(container, previousContainer)
|
|
if container:getContainerItem():getId() == waitingForContainer then
|
|
container.lootContainer = true
|
|
waitingForContainer = nil
|
|
end
|
|
end)
|
|
|
|
onCreatureDisappear(function(creature)
|
|
if isInPz() then return end
|
|
if not TargetBot.isOn() then return end
|
|
if not creature:isMonster() then return end
|
|
local config = TargetBot.Creature.calculateParams(creature, {}) -- return {craeture, config, danger, priority}
|
|
if not config.config or config.config.dontLoot then
|
|
return
|
|
end
|
|
local pos = player:getPosition()
|
|
local mpos = creature:getPosition()
|
|
local name = creature:getName()
|
|
if pos.z ~= mpos.z or math.max(math.abs(pos.x-mpos.x), math.abs(pos.y-mpos.y)) > 6 then return end
|
|
schedule(20, function() -- check in 20ms if there's container (dead body) on that tile
|
|
if not containers[1] then return end
|
|
if TargetBot.Looting.list[20] then return end -- too many items to loot
|
|
local tile = g_map.getTile(mpos)
|
|
if not tile then return end
|
|
local container = tile:getTopUseThing()
|
|
if not container or not container:isContainer() then return end
|
|
if not findPath(player:getPosition(), mpos, 6, {ignoreNonPathable=true, ignoreCreatures=true, ignoreCost=true}) then return end
|
|
table.insert(TargetBot.Looting.list, {pos=mpos, creature=name, container=container:getId(), added=now, tries=0})
|
|
|
|
table.sort(TargetBot.Looting.list, function(a,b)
|
|
a.dist = distanceFromPlayer(a.pos)
|
|
b.dist = distanceFromPlayer(b.pos)
|
|
|
|
return a.dist > b.dist
|
|
end)
|
|
container:setMarked('#000088')
|
|
end)
|
|
end)
|