• 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!

Lua How to check items in bag?

Dibis

Member
Joined
Dec 1, 2022
Messages
73
Reaction score
16
Location
POLAND
Hello,
I have script in creaturescripts who check items on corpose, and send magic effect if is true, but if in corpose have bag and item inside, this script not work, and not found items.
How edit this code?

Lua:
RARE_ITEMS = {2148,5890}

function getTopItem(p) -- from Darkhaos's arena script
    p.stackpos = 0
    local v = getThingFromPos(p)
    repeat
        p.stackpos = p.stackpos + 1
        v = getThingFromPos(p)
    until v.itemid == 0
    p.stackpos = p.stackpos - 1
    return getThingFromPos(p)
end


function scanCorpseLoot(cid, pos)
    local corpse = getTopItem(pos)
    if isContainer(corpse.uid) then
        for n = (getContainerSize(corpse.uid) - 1), 0, -1 do
            if isInArray(RARE_ITEMS, getContainerItem(corpse.uid, n).itemid) then
                addEvent(warningRareLoot, 400, pos, 1)
                addEvent(warningRareLoot, 4000, pos, 1)
                addEvent(warningRareLoot, 8000, pos, 1)
                break
            end
        end
    end
end

function warningRareLoot(pos, rtype)
    if rtype == 1 then
        doSendAnimatedText(pos, "RARE LOOT", TEXTCOLOR_ORANGE)
        doSendMagicEffect(pos, 56) -- azul
    end
end



function onKill(cid, target, lastHit)
    if isMonster(target) then
        addEvent(scanCorpseLoot, 150, cid, getThingPos(target))
    end
    return true
end
 
Hello,
I have script in creaturescripts who check items on corpose, and send magic effect if is true, but if in corpose have bag and item inside, this script not work, and not found items.
How edit this code?

Lua:
RARE_ITEMS = {2148,5890}

function getTopItem(p) -- from Darkhaos's arena script
    p.stackpos = 0
    local v = getThingFromPos(p)
    repeat
        p.stackpos = p.stackpos + 1
        v = getThingFromPos(p)
    until v.itemid == 0
    p.stackpos = p.stackpos - 1
    return getThingFromPos(p)
end


function scanCorpseLoot(cid, pos)
    local corpse = getTopItem(pos)
    if isContainer(corpse.uid) then
        for n = (getContainerSize(corpse.uid) - 1), 0, -1 do
            if isInArray(RARE_ITEMS, getContainerItem(corpse.uid, n).itemid) then
                addEvent(warningRareLoot, 400, pos, 1)
                addEvent(warningRareLoot, 4000, pos, 1)
                addEvent(warningRareLoot, 8000, pos, 1)
                break
            end
        end
    end
end

function warningRareLoot(pos, rtype)
    if rtype == 1 then
        doSendAnimatedText(pos, "RARE LOOT", TEXTCOLOR_ORANGE)
        doSendMagicEffect(pos, 56) -- azul
    end
end



function onKill(cid, target, lastHit)
    if isMonster(target) then
        addEvent(scanCorpseLoot, 150, cid, getThingPos(target))
    end
    return true
end
Lua:
function scanCorpseLoot(cid, pos)
    local corpse = getTopItem(pos)
    if isContainer(corpse.uid) then
        for n = (getContainerSize(corpse.uid) - 1), 0, -1 do
            local item = getContainerItem(corpse.uid, n)
            if isInArray(RARE_ITEMS, item.itemid) then
                addEvent(warningRareLoot, 400, pos, 1)
                addEvent(warningRareLoot, 4000, pos, 1)
                addEvent(warningRareLoot, 8000, pos, 1)
                break
            end
            -- Check if the item is a bag
            if isContainer(item.uid) then
                -- Iterate through the bag's contents and check if it has any rare items
                for i = (getContainerSize(item.uid) - 1), 0, -1 do
                    local bagItem = getContainerItem(item.uid, i)
                    if isInArray(RARE_ITEMS, bagItem.itemid) then
                        addEvent(warningRareLoot, 400, pos, 1)
                        addEvent(warningRareLoot, 4000, pos, 1)
                        addEvent(warningRareLoot, 8000, pos, 1)
                        break
                    end
                end
            end
        end
    end
end
I guess this will check if the current item in the loop is a bag, and if it is, it will iterate through the bag's contents and check if any of the items are in the RARE_ITEMS list. If it finds a rare item, it will trigger the warningRareLoot events as before.
 
Lua:
function scanCorpseLoot(cid, pos)
    local corpse = getTopItem(pos)
    if isContainer(corpse.uid) then
        for n = (getContainerSize(corpse.uid) - 1), 0, -1 do
            local item = getContainerItem(corpse.uid, n)
            if isInArray(RARE_ITEMS, item.itemid) then
                addEvent(warningRareLoot, 400, pos, 1)
                addEvent(warningRareLoot, 4000, pos, 1)
                addEvent(warningRareLoot, 8000, pos, 1)
                break
            end
            -- Check if the item is a bag
            if isContainer(item.uid) then
                -- Iterate through the bag's contents and check if it has any rare items
                for i = (getContainerSize(item.uid) - 1), 0, -1 do
                    local bagItem = getContainerItem(item.uid, i)
                    if isInArray(RARE_ITEMS, bagItem.itemid) then
                        addEvent(warningRareLoot, 400, pos, 1)
                        addEvent(warningRareLoot, 4000, pos, 1)
                        addEvent(warningRareLoot, 8000, pos, 1)
                        break
                    end
                end
            end
        end
    end
end
I guess this will check if the current item in the loop is a bag, and if it is, it will iterate through the bag's contents and check if any of the items are in the RARE_ITEMS list. If it finds a rare item, it will trigger the warningRareLoot events as before.
If there are multiple bags in corpse, it can add events few times. break in inner for will break only this for, parent for will continue.
As there is nothing after these for's, you can just replace break with return to stop function execution.
Lua:
function scanCorpseLoot(cid, pos)
    local corpse = getTopItem(pos)
    if isContainer(corpse.uid) then
        for n = (getContainerSize(corpse.uid) - 1), 0, -1 do
            local item = getContainerItem(corpse.uid, n)
            if isInArray(RARE_ITEMS, item.itemid) then
                addEvent(warningRareLoot, 400, pos, 1)
                addEvent(warningRareLoot, 4000, pos, 1)
                addEvent(warningRareLoot, 8000, pos, 1)
                return
            end
            -- Check if the item is a bag
            if isContainer(item.uid) then
                -- Iterate through the bag's contents and check if it has any rare items
                for i = (getContainerSize(item.uid) - 1), 0, -1 do
                    local bagItem = getContainerItem(item.uid, i)
                    if isInArray(RARE_ITEMS, bagItem.itemid) then
                        addEvent(warningRareLoot, 400, pos, 1)
                        addEvent(warningRareLoot, 4000, pos, 1)
                        addEvent(warningRareLoot, 8000, pos, 1)
                        return
                    end
                end
            end
        end
    end
end
 
If there are multiple bags in corpse, it can add events few times. break in inner for will break only this for, parent for will continue.
As there is nothing after these for's, you can just replace break with return to stop function execution.
Lua:
function scanCorpseLoot(cid, pos)
    local corpse = getTopItem(pos)
    if isContainer(corpse.uid) then
        for n = (getContainerSize(corpse.uid) - 1), 0, -1 do
            local item = getContainerItem(corpse.uid, n)
            if isInArray(RARE_ITEMS, item.itemid) then
                addEvent(warningRareLoot, 400, pos, 1)
                addEvent(warningRareLoot, 4000, pos, 1)
                addEvent(warningRareLoot, 8000, pos, 1)
                return
            end
            -- Check if the item is a bag
            if isContainer(item.uid) then
                -- Iterate through the bag's contents and check if it has any rare items
                for i = (getContainerSize(item.uid) - 1), 0, -1 do
                    local bagItem = getContainerItem(item.uid, i)
                    if isInArray(RARE_ITEMS, bagItem.itemid) then
                        addEvent(warningRareLoot, 400, pos, 1)
                        addEvent(warningRareLoot, 4000, pos, 1)
                        addEvent(warningRareLoot, 8000, pos, 1)
                        return
                    end
                end
            end
        end
    end
end
You are right we can also use another solution by adding a flag variable to keep track of whether a rare item has been found in the inner loop. We can then use this flag to determine whether to add the events in the outer loop and i guess it gonna work.
Lua:
function scanCorpseLoot(cid, pos)
    local corpse = getTopItem(pos)
    if isContainer(corpse.uid) then
        local rareFound = false
        for n = (getContainerSize(corpse.uid) - 1), 0, -1 do
            local item = getContainerItem(corpse.uid, n)
            if isInArray(RARE_ITEMS, item.itemid) then
                rareFound = true
                break
            end
            -- Check if the item is a bag
            if isContainer(item.uid) then
                -- Iterate through the bag's contents and check if it has any rare items
                for i = (getContainerSize(item.uid) - 1), 0, -1 do
                    local bagItem = getContainerItem(item.uid, i)
                    if isInArray(RARE_ITEMS, bagItem.itemid) then
                        rareFound = true
                        break
                    end
                end
                -- If a rare item was found in the inner loop, break out of the outer loop
                if rareFound then
                    break
                end
            end
        end
        -- If a rare item was found, add the events to the event queue
        if rareFound then
            addEvent(warningRareLoot, 400, pos, 1)
            addEvent(warningRareLoot, 4000, pos, 1)
            addEvent(warningRareLoot, 8000, pos, 1)
        end
    end
end
This way, the inner loop will break out as soon as a rare item is found, and the outer loop will also break out if a rare item is found in the inner loop. The events will only be added to the event queue if a rare item is found in either the outer loop or the inner loop. :)
 
You are right we can also use another solution by adding a flag variable to keep track of whether a rare item has been found in the inner loop. We can then use this flag to determine whether to add the events in the outer loop and i guess it gonna work.
Lua:
function scanCorpseLoot(cid, pos)
    local corpse = getTopItem(pos)
    if isContainer(corpse.uid) then
        local rareFound = false
        for n = (getContainerSize(corpse.uid) - 1), 0, -1 do
            local item = getContainerItem(corpse.uid, n)
            if isInArray(RARE_ITEMS, item.itemid) then
                rareFound = true
                break
            end
            -- Check if the item is a bag
            if isContainer(item.uid) then
                -- Iterate through the bag's contents and check if it has any rare items
                for i = (getContainerSize(item.uid) - 1), 0, -1 do
                    local bagItem = getContainerItem(item.uid, i)
                    if isInArray(RARE_ITEMS, bagItem.itemid) then
                        rareFound = true
                        break
                    end
                end
                -- If a rare item was found in the inner loop, break out of the outer loop
                if rareFound then
                    break
                end
            end
        end
        -- If a rare item was found, add the events to the event queue
        if rareFound then
            addEvent(warningRareLoot, 400, pos, 1)
            addEvent(warningRareLoot, 4000, pos, 1)
            addEvent(warningRareLoot, 8000, pos, 1)
        end
    end
end
This way, the inner loop will break out as soon as a rare item is found, and the outer loop will also break out if a rare item is found in the inner loop. The events will only be added to the event queue if a rare item is found in either the outer loop or the inner loop. :)

@Gesior.pl @Shalaby
We are the best. I check this.
Is there any way to not add a list and make it check which item has a lower chance than? (in monster.xml have loot chance)
 
@Gesior.pl @Shalaby
We are the best. I check this.
Is there any way to not add a list and make it check which item has a lower chance than? (in monster.xml have loot chance)
You can get monster info - including loot list - on TFS 0.4:
It loads info by monster name, so you would need to add name of killed monster as parameter in onKill:
Code:
addEvent(scanCorpseLoot, 150, cid, getThingPos(target), getCreatureName(target))
and then in:
Code:
function scanCorpseLoot(cid, pos)
add parameter:
Code:
function scanCorpseLoot(cid, pos, monsterName)
and write a looot of code to read list of loot of monsterName, code without item parsing:
Lua:
function scanCorpseLoot(cid, pos, monsterName)
   local monsterInfo = getMonsterInfo(monsterName)
   local RARE_ITEMS = {}
   if monsterInfo then
       local monsterLoot = monsterInfo.loot
       for k, itemInfo in pairs(monsterLoot) do
         -- HERE code to check item id, count, chance and calculate if its rare
       end
    end
-- rest of scanCorpseLoot code
It may be not accurate [loads Demon loot, when player kills Demon (Goblin) (goblin with demon outfit)]
or fail sometimes [saying that there is no monster with given name ex . Butterfly].
getCreatureName(target) returns monster name visible to player ex. Butterfly
getMonsterInfo(name) probably expects name from monsters.xml (map editor name), which would be Red Butterfly, Yellow Butterfly etc.
but in most cases ex. Warlock, Ghoul, Dragon it should work fine.
 
What? how come? Can you specify what actually that isn't working? because everything that I write and Gesior both solutions work without problems. And also if you got errors can you post them here.

No have error in console.
Your first post working good.
Second post Gesior - not visible item when on corpose have bag.
Your second post - only on corpose found Rare Item list, when have in corpose do t work.
 
If there are multiple bags in corpse, it can add events few times. break in inner for will break only this for, parent for will continue.
As there is nothing after these for's, you can just replace break with return to stop function execution.
Lua:
function scanCorpseLoot(cid, pos)
    local corpse = getTopItem(pos)
    if isContainer(corpse.uid) then
        for n = (getContainerSize(corpse.uid) - 1), 0, -1 do
            local item = getContainerItem(corpse.uid, n)
            if isInArray(RARE_ITEMS, item.itemid) then
                addEvent(warningRareLoot, 400, pos, 1)
                addEvent(warningRareLoot, 4000, pos, 1)
                addEvent(warningRareLoot, 8000, pos, 1)
                return
            end
            -- Check if the item is a bag
            if isContainer(item.uid) then
                -- Iterate through the bag's contents and check if it has any rare items
                for i = (getContainerSize(item.uid) - 1), 0, -1 do
                    local bagItem = getContainerItem(item.uid, i)
                    if isInArray(RARE_ITEMS, bagItem.itemid) then
                        addEvent(warningRareLoot, 400, pos, 1)
                        addEvent(warningRareLoot, 4000, pos, 1)
                        addEvent(warningRareLoot, 8000, pos, 1)
                        return
                    end
                end
            end
        end
    end
end

All working good, but if corpose in stackpos = 1 have rare item, and i kill next monster and corpose is in the same position but on stackpos =2, scan corpose found item in all stackposition.... How change this ?
 
All working good, but if corpose in stackpos = 1 have rare item, and i kill next monster and corpose is in the same position but on stackpos =2, scan corpose found item in all stackposition.... How change this ?
The way I had solved a similar problem was to add some sort of tag to the corpse after it had been checked.
Description or ActionId.

So instead of finding the 'top item', you would simply find the first corpse without a 'tag' added to it, and check that body.
When finished checking everything for rare loot, add a tag to the corpse, so further iterations of your script know it's been checked before.

Or vise/versa.. when creature dies add a unique tag to the corpse, via onDeath, and then scan for a corpse with that tag.. then do regular function.
 
Back
Top