QuickLoot = {} local function getFilter(id) local filter = { [1] = 0, [2] = 1 } return filter[id] end quickLootController = Controller:new() quickLootController:setUI('quickloot') function quickLootController:onInit() QuickLoot.Define() QuickLoot.data = { filter = 1, loots = { [0] = {}, {} } } quickLootController.ui:hide() quickLootController:registerEvents(g_game, { onQuickLootContainers = QuickLoot.start }) Keybind.new("Loot", "Quick Loot Nearby Corpses", "Alt+Q", "") Keybind.bind("Loot", "Quick Loot Nearby Corpses", { { type = KEY_DOWN, callback = function() g_game.sendQuickLoot(2) end, } }) end function quickLootController:onTerminate() Keybind.delete("Loot", "Quick Loot Nearby Corpses") if QuickLoot.mouseGrabberWidget then QuickLoot.mouseGrabberWidget:destroy() QuickLoot.mouseGrabberWidget = nil end QuickLoot = {} end function quickLootController:onGameStart() if not g_game.getFeature(GameThingQuickLoot) then return end if not QuickLoot.mouseGrabberWidget then QuickLoot.mouseGrabberWidget = g_ui.createWidget("UIWidget") end QuickLoot.mouseGrabberWidget:setVisible(false) QuickLoot.mouseGrabberWidget:setFocusable(false) QuickLoot.mouseGrabberWidget.onMouseRelease = QuickLoot.onChooseItem QuickLoot.lastSelectBag = nil QuickLoot.ErrorWindow = nil local player = g_game.getLocalPlayer() quickLootController.ui.information.vipPanel.premium:setOn(not (player and player:isPremium())) QuickLoot.load() g_game.requestQuickLootBlackWhiteList(getFilter(QuickLoot.data.filter), #QuickLoot.data.loots[QuickLoot.data.filter], QuickLoot.data.loots[QuickLoot.data.filter]) end function quickLootController:onGameEnd() if not g_game.getFeature(GameThingQuickLoot) then return end QuickLoot.save() QuickLoot.toggle() if quickLootController.ui:isVisible() then quickLootController.ui:hide() end end function QuickLoot.Define() function QuickLoot.filter(widget, isChecked) widget:setChecked(true) isChecked = true local accepted = quickLootController.ui.filters.accepted local skipped = quickLootController.ui.filters.skipped local add_text = string.format("Add to %s Loot List", widget:getId():gsub("^%l", string.upper)) local clear_text = string.format("Clear %s Loot List", widget:getId():gsub("^%l", string.upper)) if widget == skipped and isChecked then quickLootController.ui.filters.accepted:setChecked(false) quickLootController.ui.filters.add:setText(add_text) quickLootController.ui.filters.clear:setText(clear_text) QuickLoot.data.filter = 1 end if widget == accepted and isChecked then quickLootController.ui.filters.skipped:setChecked(false) quickLootController.ui.filters.add:setText(add_text) quickLootController.ui.filters.clear:setText(clear_text) QuickLoot.data.filter = 2 end g_game.requestQuickLootBlackWhiteList(getFilter(QuickLoot.data.filter), #QuickLoot.data.loots[QuickLoot.data.filter], QuickLoot.data.loots[QuickLoot.data.filter]) QuickLoot.loadFilterItems() end function QuickLoot.lootExists(itemId, filter) if not filter then filter = QuickLoot.data.filter end return table.contains(QuickLoot.data.loots[filter], itemId) end function QuickLoot.addLootList(itemId,filter) if not filter then filter = QuickLoot.data.filter end if table.contains(QuickLoot.data.loots[filter], itemId) then return end table.insert(QuickLoot.data.loots[filter], itemId) g_game.requestQuickLootBlackWhiteList(getFilter(filter), #QuickLoot.data.loots[filter], QuickLoot.data.loots[filter]) if quickLootController.ui:isVisible() then QuickLoot.loadFilterItems() end end function QuickLoot.clearFilterItems() QuickLoot.data.loots[QuickLoot.data.filter] = {} g_game.requestQuickLootBlackWhiteList(getFilter(QuickLoot.data.filter), #QuickLoot.data.loots[QuickLoot.data.filter], QuickLoot.data.loots[QuickLoot.data.filter]) QuickLoot.loadFilterItems() end function QuickLoot.removeLootList(itemId, filter) if not filter then filter = QuickLoot.data.filter end if not table.contains(QuickLoot.data.loots[filter], itemId) then return end table.removevalue(QuickLoot.data.loots[filter], itemId) g_game.requestQuickLootBlackWhiteList(getFilter(filter), #QuickLoot.data.loots[filter], QuickLoot.data.loots[filter]) if quickLootController.ui:isVisible() then QuickLoot.loadFilterItems() end end function QuickLoot.load() local player = g_game.getLocalPlayer() if not player then return end local file = string.format("/settings/%s_containers.json", player:getName():lower():gsub("%s+", "_")) if g_resources.fileExists(file) then local status, result = pcall(function() return json.decode(g_resources.readFileContents(file)) end) if not status then return g_logger.error("Error while reading containers settings file. " .. result) end if result == nil then QuickLoot.data = { filter = 1, loots = {{}, {}} } else QuickLoot.data = result end else QuickLoot.data = { filter = 1, loots = {{}, {}} } end end function QuickLoot.save() local file = string.format("/settings/%s_containers.json", g_game.getLocalPlayer():getName():lower():gsub("%s+", "_")) local status, result = pcall(function() return json.encode(QuickLoot.data, 2) end) if not status then return g_logger.warning("Error while saving QuickLoot settings. Data won't be saved. Details: " .. result) end if result:len() > 104857600 then return g_logger.error("Something went wrong, file is above 100MB, won't be saved") end -- Safely attempt to write the file, ignoring errors during logout local writeStatus, writeError = pcall(function() return g_resources.writeFileContents(file, result) end) if not writeStatus then -- Log the error but don't spam the console during normal logout g_logger.debug("Could not save QuickLoot settings during logout: " .. tostring(writeError)) end end function QuickLoot.start(quickLootFallbackToMainContainer, lootContainers) local player = g_game.getLocalPlayer() local vipPanel = quickLootController.ui.information.vipPanel local loots = lootContainers local fallback = quickLootFallbackToMainContainer -- Store lootContainers globally so other modules can access it -- Store a copy to avoid interfering with the local variable QuickLoot.lootContainers = {} if lootContainers then for i, container in ipairs(lootContainers) do QuickLoot.lootContainers[i] = {container[1], container[2], container[3]} end end QuickLoot.loadFilterItems() local filter = { [1] = "skipped", [2] = "accepted" } QuickLoot.filter(quickLootController.ui.filters[filter[QuickLoot.data.filter]], true) quickLootController.ui.list:getLayout():disableUpdates() quickLootController.ui.list:destroyChildren() quickLootController.ui.fallbackPanel.checkbox:setChecked(fallback) -- LuaFormatter off local slotBags = { { color = "#484848", name = "Unassigned", type = 31 }, { color = "#414141", name = "Gold", type = 30 }, { color = "#484848", name = "Armors", type = 1 }, { color = "#414141", name = "Amulets", type = 2 }, { color = "#484848", name = "Boots", type = 3 }, { color = "#414141", name = "Containers", type = 4 }, { color = "#484848", name = "Creature\nProducts", type = 24 }, { color = "#414141", name = "Decoration", type = 5 }, { color = "#484848", name = "Food", type = 6 }, { color = "#414141", name = "Helmets\nand Hats", type =7 }, { color = "#484848", name = "Legs", type = 8 }, { color = "#414141", name = "Others", type = 9 }, { color = "#414141", name = "Potions", type = 10 }, { color = "#484848", name = "Rings", type = 11 }, { color = "#414141", name = "Runes", type = 12 }, { color = "#484848", name = "Shields", type = 13 }, { color = "#414141", name = "Tools", type = 14 }, { color = "#484848", name = "Valuables", type = 15 }, { color = "#414141", name = "Weapons:\nAmmo", type = 16 }, { color = "#484848", name = "Weapons:\nAxes", type = 17 }, { color = "#414141", name = "Weapons:\nClubs", type = 18 }, { color = "#484848", name = "Weapons:\nDistance", type = 19 }, { color = "#414141", name = "Weapons:\nSwords", type = 20 }, { color = "#484848", name = "Weapons:\nWands", type = 21 }, --{ color = "#414141", name = "Quivers" , type = 25 }, } -- LuaFormatter on for _, slot in ipairs(slotBags) do local widget = g_ui.createWidget("QuicklootBagLabel", quickLootController.ui.list) local id = slot.type and slot.type or 0 widget:setId(id) widget:setBackgroundColor(slot.color) widget.label:setText(slot.name) for _, container in pairs(lootContainers) do if container[1] == id then local lootContainerId = container[3] local obtainerContainerId = container[2] widget.item:setItemId(lootContainerId) widget.item2:setItemId(obtainerContainerId) break end end end quickLootController.ui.list:getLayout():enableUpdates() quickLootController.ui.list:getLayout():update() end function QuickLoot.loadFilterItems() quickLootController.ui.ignoreList:destroyChildren() local color = "#484848" for _, itemId in ipairs(QuickLoot.data.loots[QuickLoot.data.filter]) do local name = g_things.getThingType(itemId, ThingCategoryItem):getName() local widget = g_ui.createWidget("QuicLootIgnoreItem", quickLootController.ui.ignoreList) widget:setId(itemId) widget:setBackgroundColor(color) widget.label:setText(name ~= "" and name or "Unknown") widget.item:setItemId(itemId) color = color == "#484848" and "#414141" or "#484848" end end function QuickLoot.search(text) return end function QuickLoot.clearSearch() local search = quickLootController.ui.search search:clearText() end function QuickLoot.fallback(widget, isChecked) g_game.openContainerQuickLoot(3, nil, {}, nil, nil, isChecked) end function QuickLoot:chooseItem() if g_ui.isMouseGrabbed() then return end QuickLoot.mouseGrabberWidget:grabMouse() -- Use native cursor when enabled, otherwise use custom cursor if modules.client_options and modules.client_options.getOption('nativeCursor') then g_window.setSystemCursor('cross') else g_mouse.pushCursor("target") end QuickLoot.lastSelectBag = self:getParent() QuickLoot.actionsId = self.Select quickLootController.ui:hide() end function QuickLoot.confirmError() QuickLoot.ErrorWindow:destroy() quickLootController.ui:show() end function QuickLoot:onChooseItem(mousePosition, mouseButton) local item if mouseButton == MouseLeftButton then local clickedWidget = modules.game_interface.getRootPanel():recursiveGetChildByPos(mousePosition, false) if clickedWidget then if clickedWidget:getClassName() == "UIGameMap" then local tile = clickedWidget:getTile(mousePosition) if tile then local thing = tile:getTopMoveThing() if thing and thing:isContainer() then item = thing else QuickLoot.ErrorWindow = displayGeneralBox(tr("Invalid Loot Container"), tr( "You can only select containers you carry in your inventory."), { { text = tr("Ok"), callback = QuickLoot.confirmError }, anchor = AnchorHorizontalCenter }) end end elseif clickedWidget:getClassName() == "UIItem" and not clickedWidget:isVirtual() then if clickedWidget:getItem() and clickedWidget:getItem():isContainer() then item = clickedWidget:getItem() g_game.openContainerQuickLoot(QuickLoot.actionsId, QuickLoot.lastSelectBag:getId(), item:getPosition(), item:getId(), item:getStackPos()) else QuickLoot.ErrorWindow = displayGeneralBox(tr("Invalid Loot Container"), tr( "You can only select containers you carry in your inventory."), { { text = tr("Ok"), callback = QuickLoot.confirmError }, anchor = AnchorHorizontalCenter }) end end end end if item then QuickLoot.lastSelectBag.item:setItem(item) quickLootController.ui:show() end -- Restore cursor if modules.client_options and modules.client_options.getOption('nativeCursor') then g_window.restoreMouseCursor() else g_mouse.popCursor("target") end self:ungrabMouse() return true end function QuickLoot:openContainer() for _, container in pairs(g_game.getContainers()) do if container:getContainerItem():getId() == self:getItemId() then return false end end g_game.openContainerQuickLoot(self.click, self:getParent():getId(), {}, nil, nil, nil) return true end function QuickLoot:clearItem() if self.borrar == 1 then self:getParent().item2:setItem(nil) else self:getParent().item:setItem(nil) end g_game.openContainerQuickLoot(self.borrar, self:getParent():getId(), {}, nil, nil, nil) end function QuickLoot:clearFilterItem() QuickLoot.removeLootList(self:getParent().item:getItemId()) QuickLoot.loadFilterItems() end function QuickLoot.toggle() if not quickLootController.ui then return end if quickLootController.ui:isVisible() then return QuickLoot.hide() end QuickLoot.show() QuickLoot.loadFilterItems() if QuickLoot.data.filter == 2 and not quickLootController.ui.filters.accepted:isChecked() then quickLootController.ui.filters.accepted:onClick() end end function QuickLoot.show() if not quickLootController.ui then return end quickLootController.ui:show() quickLootController.ui:raise() quickLootController.ui:focus() end function QuickLoot.hide() if not quickLootController.ui then return end quickLootController.ui:hide() end end