• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

TFS 1.X+ Code not adding item to the selected container

E

Evil Puncker

Guest
I'm using this code for autoloot (not the onUse part), applied on latest TFS with several changes, it is working 99% fine, every function except the part where it should add the item to the selected container, it is adding everything into the main backpack only:

nNJRGEK.gif


and I can't even think where to search for it in order to "try" fixing, so here I am asking you guys for help once again, the C++ part is the same as the link above, and for the rest, here they are:

events/script/monster.lua
Lua:
function Monster:onDropLoot(corpse)
    if configManager.getNumber(configKeys.RATE_LOOT) == 0 then
        return
    end

    local player = Player(corpse:getCorpseOwner())
    local autolooted = ""
    local mType = self:getType()
    if not player or player:getStamina() > 840 then
        local monsterLoot = mType:getLoot()
        for i = 1, #monsterLoot do
            local item = corpse:createLootItem(monsterLoot[i])
            if not item then
                print('[Warning] DropLoot:', 'Could not add loot item to corpse.')
            end
            -- autoloot
            if item > 0 then
                local tmpItem = Item(item)
                if player and player:getAutoLootItem(tmpItem:getId()) then
                    if tmpItem:moveTo(player) then
                        autolooted = string.format("%s, %s", autolooted, tmpItem:getNameDescription())
                    end
                end
            end
        end

        if player then
            local text = ("Loot of %s: "):format(mType:getNameDescription())
            -- autoloot
            local lootMsg = corpse:getContentDescription()
            if autolooted ~= "" and corpse:getContentDescription() == "nothing" then
                lootMsg = autolooted:gsub(",", "", 1) .. " that was autolooted"
            elseif autolooted ~= "" then
                lootMsg = corpse:getContentDescription() .. " and " .. autolooted:gsub(",", "", 1) .. " that was autolooted"
            end
            text = string.format("%s%s", text, lootMsg)
            local party = player:getParty()
            if party then
                if autolooted ~= "" then
                    text = string.format("%s by %s", text, player:getName())
                end
                party:broadcastPartyLoot(text)
            else
                player:sendTextMessage(MESSAGE_LOOT, text)
            end
        end
    else
        local text = ("Loot of %s: nothing (due to low stamina)"):format(mType:getNameDescription())
        local party = player:getParty()
        if party then
            party:broadcastPartyLoot(text)
        else
            player:sendTextMessage(MESSAGE_LOOT, text)
        end
    end
end

lib/core/container.lua (I think this one is responsible for adding the item?)
Lua:
function Container.createLootItem(self, item)
    if self:getEmptySlots() == 0 then
        return true
    end

    local itemCount = 0
    local randvalue = getLootRandom()
    if randvalue < item.chance then
        if ItemType(item.itemId):isStackable() then
            itemCount = randvalue % item.maxCount + 1
        else
            itemCount = 1
        end
    end

    --if itemCount > 0 then
        local tmpItem = false
        if itemCount > 0 then
        tmpItem = self:addItem(item.itemId, math.min(itemCount, 100))
        --local tmpItem = self:addItem(item.itemId, math.min(itemCount, 100))
        if not tmpItem then
            return -1
            --return false
        end

        if tmpItem:isContainer() then
            for i = 1, #item.childLoot do
                if not tmpItem:createLootItem(item.childLoot[i]) then
                    tmpItem:remove()
                    return -1
                    --return false
                end
            end
        end

        if item.subType ~= -1 then
            tmpItem:setAttribute(ITEM_ATTRIBUTE_CHARGES, item.subType)
        end

        if item.actionId ~= -1 then
            tmpItem:setActionId(item.actionId)
        end

        if item.text and item.text ~= "" then
            tmpItem:setText(item.text)
        end
    end
    --return true
    return tmpItem and tmpItem.uid or 0
end

OnModalWindow event:
Lua:
function call(player, param, param2, tobpid)
    player:registerEvent('autoloot')
    local title = "Autoloot Helper!"
    if param == 'add' then
        local lootBlockList = lootBlockListm[player:getGuid()]
        local message = "Loot of "..string.gsub(" "..string.lower(lootBlockListn[player:getGuid()]), "%W%l", string.upper):sub(2)..":"
        local window = ModalWindow(1001, title, message)
        local check, sum = {}, 1
        for _, loot in pairs(lootBlockList) do
            local status = ''
            if player:getAutoLootItem(lootBlockList[sum].itemId) then
                status = '*'
            end
            if not table.contains(check, ItemType(lootBlockList[sum].itemId):getName()) then
                table.insert(check, ItemType(lootBlockList[sum].itemId):getName())
                local resultId = db.storeQuery('SELECT `cont_id` FROM `player_autoloot_persist` WHERE `player_guid` = ' .. player:getGuid() .. ' AND `item_id` = ' .. lootBlockList[sum].itemId .. '')
                if resultId then
                    local bp_id = result.getNumber(resultId, 'cont_id')
                end
                local backvinculo
                if result.getNumber(resultId, 'cont_id') and result.getNumber(resultId, 'cont_id') > 0 then
                    backvinculo = '( '..ItemType(result.getNumber(resultId, 'cont_id')):getName()..''
                    else
                    backvinculo = ''
                end
                window:addChoice(sum, "".. string.gsub(" "..status..""..ItemType(lootBlockList[sum].itemId):getName(), "%W%l", string.upper):sub(2, 21) .." ( "..lootBlockList[sum].maxCount.." ) "..(lootBlockList[sum].chance/1000).."% "..string.gsub(" "..string.lower(backvinculo), "%W%l", string.upper):sub(2).."")
            end
            sum = sum + 1
        end
        if autolootBP == 1 then
            window:addButton(105, "Backpack")
        end
        callwindow(window, player, 1)
        elseif param == 'remove' then
        local message = "You are currently looting the following items:"
        local window = ModalWindow(1000, title, message)
        local check, sum = player:getAutoLootList(), 1
        if check then
            table.sort(check, function(a, b) return ItemType(a):getName() < ItemType(b):getName() end)
            for _, item in ipairs(check) do
                local resultId = db.storeQuery('SELECT `cont_id` FROM `player_autoloot_persist` WHERE `player_guid` = ' .. player:getGuid() .. ' AND `item_id` = ' .. ItemType(check[sum]):getId() .. '')
                if resultId then
                    local bp_id = result.getNumber(resultId, 'cont_id')
                end
                local backvinculo
                if result.getNumber(resultId, 'cont_id') and result.getNumber(resultId, 'cont_id') > 0 then
                    backvinculo = '( '..ItemType(result.getNumber(resultId, 'cont_id')):getName()..''
                    else
                    backvinculo = ''
                end
                window:addChoice(sum, "".. string.gsub(" "..(ItemType(item)):getName(), "%W%l", string.upper):sub(2, 21) .." "..string.gsub(" "..string.lower(backvinculo), "%W%l", string.upper):sub(2).."")
                sum = sum + 1
            end
            else
            player:sendCancelMessage("The list is empty.")
            return false
        end
        if autolootBP == 1 then
            window:addButton(106, "Backpack")
        end
        callwindow(window, player, 2)
        elseif param == 'backpack' then
        local lootBlockList = lootBlockListm[player:getGuid()]

        local modalcode
        if param2 and param2 == 1001 then
            modalcode = 1005
        else
            modalcode = 1006
        end
        local message = "Choose a Backpack:"
        local container2 = player:getSlotItem(CONST_SLOT_BACKPACK)
        local window = ModalWindow(modalcode, title, message)
        local sum = 1
        local container, names = {}, {}
        if container2:getSize() then
            for i = 0, container2:getSize() - 1 do
                local thing = container2:getItem(i)
                container[i] = container2:getItem(i)
                if container[i]:isContainer() then
                    if not table.contains(names, container[i].itemId) then
                        table.insert(names, container[i].itemId)
                        window:addChoice(sum, ""..string.gsub(" "..string.lower(ItemType(container[i].itemid):getName()), "%W%l", string.upper):sub(2).."")
                    end
                    sum = sum + 1
                end
            end
            else
            player:sendCancelMessage("Main backpack not found.")
            return false
        end
        if sum == 1 then
            player:sendCancelMessage("Sub-backpack not found.")
            return false
        end
        callwindow(window, player, 3)
    end
end

function callwindow(window, player, param)
    if param == 3 then
        window:setDefaultEnterButton(100, "Confirm")
        window:addButton(100, "Confirm")
        else
        window:addButton(100, "Confirm")
        window:addButton(102, "Remove")
        window:setDefaultEnterButton(106, "Backpack")
        if param == 1 then
            window:addButton(103, "Add")
            window:setDefaultEnterButton(103, "Add")
            window:addButton(105, "Backpack")
        end
    end
    window:sendToPlayer(player)
end

local creatureevent = CreatureEvent("autoloot")

function creatureevent.onModalWindow(player, modalWindowId, buttonId, choiceId)
    player:unregisterEvent('autoloot')
    local limiteAutoloot = 100
    local autolootlist, sum = {}, 1
    if buttonId == 102 and modalWindowId == 1000 then
        local playerlist = player:getAutoLootList()
        if playerlist then
            table.sort(playerlist, function(a, b) return ItemType(a):getName() < ItemType(b):getName() end)
            for _, item in ipairs(playerlist) do
                table.insert(autolootlist, "".. item .."")
            end
            local itemType = ItemType(tonumber(autolootlist[choiceId]))
            player:sendTextMessage(MESSAGE_INFO_DESCR,'Removed '.. string.gsub(" "..ItemType(tonumber(autolootlist[choiceId])):getName(), "%W%l", string.upper):sub(2, 21)..' from autoloot list!')
            db.query('DELETE FROM `player_autoloot_persist` WHERE `player_guid` = ' .. player:getGuid() .. ' AND `item_id` = ' .. itemType:getId() .. '')
            player:removeAutoLootItem(itemType:getId())
            call(player, 'remove')
        end
        elseif buttonId == 102 and modalWindowId == 1001 or buttonId == 103 then
        local lootBlockList = lootBlockListm[player:getGuid()]
        if lootBlockList == nil or lootBlockList == -1 then
            return false
        end
        for _, loot in pairs(lootBlockList) do
            table.insert(autolootlist, lootBlockList[sum].itemId)
            sum = sum + 1
        end
        local itemType = ItemType(tonumber(autolootlist[choiceId]))
        if buttonId == 102 then
            player:sendTextMessage(MESSAGE_INFO_DESCR,'Removed '.. string.gsub(" "..ItemType(itemType:getId()):getName(), "%W%l", string.upper):sub(2, 21)..' from autoloot list!')
            db.query('DELETE FROM `player_autoloot_persist` WHERE `player_guid` = ' .. player:getGuid() .. ' AND `item_id` = ' .. itemType:getId() .. '')
            player:removeAutoLootItem(itemType:getId())
            elseif buttonId == 103 then
            if player:getAutoLootList() then
            local playerlist = player:getAutoLootList()
            end
            if playerlist then
                for _, item in ipairs(playerlist) do
                    table.insert(autolootlist, "".. item .."")
                end
            end
            if playerlist and #playerlist >= limiteAutoloot then
                player:sendCancelMessage("Reached the limit <"..#playerlist.."> for itens, first remove using !autoloot or !add <monster>, selecting option remove.")
                return false
                else
                player:sendTextMessage(MESSAGE_INFO_DESCR,'Add '.. string.gsub(" "..ItemType(lootBlockList[choiceId].itemId):getName(), "%W%l", string.upper):sub(2, 21) ..' to autoloot list!')
                player:addAutoLootItem(itemType:getId())
            end
        end
        call(player, 'add')
        elseif buttonId == 105 then
        local lootBlockList = lootBlockListm[player:getGuid()]
        if lootBlockList == nil or lootBlockList == -1 then
            return false
        end
        for _, loot in pairs(lootBlockList) do
            table.insert(autolootlist, lootBlockList[sum].itemId)
            sum = sum + 1
        end
        local itemType = ItemType(tonumber(autolootlist[choiceId]))
        lastitem[player:getGuid()] = lootBlockList[choiceId].itemId
        call(player, 'backpack', modalWindowId, lastitem[player:getGuid()])
        elseif buttonId == 106 then
        local lootBlockList = player:getAutoLootList()
        table.sort(lootBlockList, function(a, b) return ItemType(a):getName() < ItemType(b):getName() end)
        if lootBlockList == nil or lootBlockList == -1 then
            return false
        end
        for _, loot in pairs(lootBlockList) do
            table.insert(autolootlist, lootBlockList[sum])
            sum = sum + 1
        end
        local itemType = ItemType(tonumber(autolootlist[choiceId]))
        lastitem[player:getGuid()] = lootBlockList[choiceId]
        call(player, 'backpack', modalWindowId, lastitem[player:getGuid()])
        elseif buttonId == 100 then
        if modalWindowId == 1005 then
            local container, bp, sequencer = {}, {}, 1
            local container2 = player:getSlotItem(CONST_SLOT_BACKPACK)
            local bp2 = {}
            for i = 0, container2:getSize() - 1 do
                local thing = container2:getItem(i)
                container[i] = container2:getItem(i)
                if container[i]:isContainer() then
                    container[i] = Item(container[i].uid)
                    bp[sequencer] = container[i]
                    bp2[sequencer] = container[i]:getId()
                    sequencer = sequencer + 1
                end
            end
            if sequencer > 1 then
                if player:getAutoLootItem(lastitem[player:getGuid()]) then
                    local resultId = db.storeQuery('SELECT `cont_id` FROM `player_autoloot_persist` WHERE `player_guid` = ' .. player:getGuid() .. ' AND `item_id` = ' .. lastitem[player:getGuid()] .. '')
                    if resultId then
                        local bp_id = result.getNumber(resultId, 'cont_id')
                        else
                        db.query("INSERT INTO `player_autoloot_persist` (`player_guid`, `cont_id`, `item_id`) VALUES (".. player:getGuid() ..", ".. bp2[choiceId] ..", ".. lastitem[player:getGuid()] ..") ON DUPLICATE KEY UPDATE `cont_id` = ".. bp2[choiceId])
                    end
                    if result.getNumber(resultId, 'cont_id') and result.getNumber(resultId, 'cont_id') ~= bp2[choiceId] then
                        db.query('UPDATE `player_autoloot_persist` SET `cont_id` = '..bp2[choiceId]..' WHERE `player_guid` = ' .. player:getGuid() .. ' AND `item_id` = ' .. lastitem[player:getGuid()] .. '')
                    end
                end
            end
            call(player, 'add')
        end
        if modalWindowId == 1006 then
            local container, bp, sequencer = {}, {}, 1
            local container2 = player:getSlotItem(CONST_SLOT_BACKPACK)
            local bp2 = {}
            for i = 0, container2:getSize() - 1 do
                local thing = container2:getItem(i)
                container[i] = container2:getItem(i)
                if container[i]:isContainer() then
                    container[i] = Item(container[i].uid)
                    bp[sequencer] = container[i]
                    bp2[sequencer] = container[i]:getId()
                    sequencer = sequencer + 1
                end
            end
            if sequencer > 1 then
                local resultId = db.storeQuery('SELECT `cont_id` FROM `player_autoloot_persist` WHERE `player_guid` = ' .. player:getGuid() .. ' AND `item_id` = ' .. lastitem[player:getGuid()] .. '')
                if resultId then
                    local bp_id = result.getNumber(resultId, 'cont_id')
                    else
                    db.query("INSERT INTO `player_autoloot_persist` (`player_guid`, `cont_id`, `item_id`) VALUES (".. player:getGuid() ..", ".. bp2[choiceId] ..", ".. lastitem[player:getGuid()] ..") ON DUPLICATE KEY UPDATE `cont_id` = ".. bp2[choiceId])
                end
                if result.getNumber(resultId, 'cont_id') and result.getNumber(resultId, 'cont_id') ~= bp2[choiceId] then
                    db.query('UPDATE `player_autoloot_persist` SET `cont_id` = '..bp2[choiceId]..' WHERE `player_guid` = ' .. player:getGuid() .. ' AND `item_id` = ' .. lastitem[player:getGuid()] .. '')
                end
            end
            call(player, 'remove')
        end
    end
end

creatureevent:register()

OnStartup event:
Lua:
local globalevent = GlobalEvent("autoloot")

function globalevent.onStartup()
    lootBlockListm = {}
    lootBlockListn = {}
    lastitem = {}
    autolootBP = 1 -- 0 = disable, 1 = enable (only works with autolootmode = 2)
    return true
end

globalevent:register()

functions that were needed and I don't have any idea why lol:
Lua:
local function pushValues(buffer, sep, ...)
    local argv = {...}
    local argc = #argv
    for k, v in ipairs(argv) do
        table.insert(buffer, v)
        if k < argc and sep then
            table.insert(buffer, sep)
        end
    end
end

function Item.getNameDescription(self)
    local subType = self:getSubType()
    local itemType = self:getType()

    local buffer = {}

    local name = self:getName() or ''
    if(#name ~= 0) then
        if(itemType:isStackable() and subType > 1) then
            pushValues(buffer, ' ', subType, self:getPluralName())
        else
            local article = self:getArticle() or ''
            pushValues(buffer, ' ', select(#article ~= 0 and 1 or 2, article, name))
        end
    else
        pushValues(buffer, ' ', 'an item of type', self:getId())
    end

    return table.concat(buffer)
end

talkaction to add items to list and chose loot backpack:
Lua:
local talk = TalkAction("!add")

function talk.onSay(player, words, param)
    local monsterType = MonsterType(param)
    if not monsterType then
        player:sendCancelMessage("Can't find monster.")
        return false
    end

    player:registerEvent('autoloot')
    local title = "Autoloot Helper!"
    local message = "Loot of "..string.gsub(" "..string.lower(param), "%W%l", string.upper):sub(2)..":"
    local lootBlockList = monsterType:getLoot()
    table.sort(lootBlockList, function(a, b) return ItemType(a.itemId):getName() < ItemType(b.itemId):getName() end)

    lootBlockListm[player:getGuid()] = lootBlockList
    lootBlockListn[player:getGuid()] = param

    local window = ModalWindow(1001, title, message)
    local check, sum = {}, 1
    for _, loot in pairs(lootBlockList) do
        local status = ''
        if player:getAutoLootItem(lootBlockList[sum].itemId) then
            status = '*'
        end
        if not table.contains(check, ItemType(lootBlockList[sum].itemId):getName()) then
            table.insert(check, ItemType(lootBlockList[sum].itemId):getName())
            local resultId = db.storeQuery('SELECT `cont_id` FROM `player_autoloot_persist` WHERE `player_guid` = ' .. player:getGuid() .. ' AND `item_id` = ' .. lootBlockList[sum].itemId .. '')
            if resultId then
            local bp_id = result.getNumber(resultId, 'cont_id')
            end

            local backvinculo

            if result.getNumber(resultId, 'cont_id') and result.getNumber(resultId, 'cont_id') > 0 then
            backvinculo = '| '..ItemType(result.getNumber(resultId, 'cont_id')):getName()..''
            else
            backvinculo = ''
            end
            window:addChoice(sum, "".. string.gsub(" "..status..""..ItemType(lootBlockList[sum].itemId):getName(), "%W%l", string.upper):sub(2, 21) .." | "..lootBlockList[sum].maxCount.." | "..(lootBlockList[sum].chance/1000).."% "..string.gsub(" "..string.lower(backvinculo), "%W%l", string.upper):sub(2).."")
        end
        sum = sum + 1
    end
    window:addButton(105, "Backpack")
    window:setDefaultEnterButton(103, "Add")
    window:addButton(100, "Confirm")
    if autolootBP == 1 then
    window:addButton(102, "Remove")
    end
    window:addButton(103, "Add")

    window:sendToPlayer(player)
    return false
end

talk:separator(" ")
talk:register()


As I said, everything is working 99% except the loot destination (bp_id I guess), the item is always going to the main backpack (CONST_SLOT_BACKPACK) no matter what
 
Last edited by a moderator:
Solution
You need to push on the item.uid of the container and at the end inside moveTo you just push Container(container[i].uid) which should now result in the right container
You're using tmpItem:moveTo(player) which moves it anywhere it can onto the player, you should be using tmpItem:moveTo(player:getAutoLootItem(tmpItem:getId()))
 
Use tmpItem:moveTo(player:getItemById(tmpItem:getId())) instead then. If that still doesn't work, you have to use the same chunk of code you used to list the backpacks in the modalwindow and index the container list by choice id, then you'll have the container userdata to use freely as you choose.
Lua:
        local container, names = {}, {}
        if container2:getSize() then
            for i = 0, container2:getSize() - 1 do
                local thing = container2:getItem(i)
                container[i] = container2:getItem(i)
                if container[i]:isContainer() then
                    if not table.contains(names, container[i].itemId) then
                        table.insert(names, container[i].itemId)
                        window:addChoice(sum, ""..string.gsub(" "..string.lower(ItemType(container[i].itemid):getName()), "%W%l", string.upper):sub(2).."")
                    end
                    sum = sum + 1
                end
            end
 
Last edited:
Just edited my post, refresh and read again.

I really really tried a lot of edits before coming back here again, but everything didn't work (index nil value or no error but neither autolooting lol):

Lua:
            if item > 0 then
                local tmpItem = Item(item)
                if player and player:getAutoLootItem(tmpItem:getId()) then
                    --if tmpItem:moveTo(player) then
                local container2 = player:getSlotItem(CONST_SLOT_BACKPACK)
                local window = ModalWindow(modalcode, title, message)
                local sum = 1
                local container, names = {}, {}
                if container2:getSize() then
                    for i = 0, container2:getSize() - 1 do
                        local thing = container2:getItem(i)
                        container[i] = container2:getItem(i)
                        if container[i]:isContainer() then
                            if not table.contains(names, container[i].itemId) then
                                table.insert(names, container[i].itemId)
                                window:addChoice(sum, ""..string.gsub(" "..string.lower(ItemType(container[i].itemid):getName()), "%W%l", string.upper):sub(2).."")
                            end
                            sum = sum + 1
                        end
                    end
                end
                    if tmpItem:moveTo(container[i].itemId) then
                        autolooted = string.format("%s, %s", autolooted, tmpItem:getNameDescription())
                    end
                end
            end

Tried:
  • if tmpItem:moveTo(player:getItemById(ItemType(container.itemid))) then
    [*]container.itemid
    [*]container
    [*]container
    [*]tmpItem:moveTo(container.itemId)
    [*]etc
 
You need to push on the item.uid of the container and at the end inside moveTo you just push Container(container[i].uid) which should now result in the right container
 
Solution
I said to use choice id, not the loop variable to index the container userdata. You literally already have the list of containers to choose from, that's how you generate the list in modalwindows, all you have to do is get the id (index) of the choice the user selects, and index the container table with the id like container[choiceId], and use that for the moveTo argument.
 
You need to push on the item.uid of the container and at the end inside moveTo you just push Container(container[i].uid) which should now result in the right container
I said to use choice id, not the loop variable to index the container userdata. You literally already have the list of containers to choose from, that's how you generate the list in modalwindows, all you have to do is get the id (index) of the choice the user selects, and index the container table with the id like container[choiceId], and use that for the moveTo argument.

thanks for the help, but now I hate myself, i've been literally trying to get it working for hours now (with my limited knowledge) 😁 and I dont quite understand what you guys are telling me to do, so I tried to do it my on way, the far I got was getting the containers ID using a query, but now I don't know how to use them on the moveTo, it always 'attempt to index a nil value', even with the "print(bp_id)" returning the container IDs:

Lua:
            if item > 0 then
                local tmpItem = Item(item)
                if player and player:getAutoLootItem(tmpItem:getId()) then
                    --if tmpItem:moveTo(player) then
        local check, sum = player:getAutoLootList(), 1
        if check then
            table.sort(check, function(a, b) return ItemType(a):getName() < ItemType(b):getName() end)
            for _, item in ipairs(check) do
                local resultId = db.storeQuery('SELECT `cont_id` FROM `player_autoloot_persist` WHERE `player_guid` = ' .. player:getGuid() .. ' AND `item_id` = ' .. ItemType(check[sum]):getId() .. '')
                if resultId then
                    local bp_id = result.getNumber(resultId, 'cont_id')
                    print(bp_id) -- it prints all containers IDs results from the query above
                end
                sum = sum + 1
            end
        end
                    if tmpItem:moveTo(bp_id) then
                        autolooted = string.format("%s, %s", autolooted, tmpItem:getNameDescription())
                    end
                end
            end
2019-11-06 17_39_25-Window.png
(ham and meat set to 23782 and 1987 containers respectively)
 
Back
Top