• 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 This free inventory check script won't work.

Demnish

Tibian Hero
Joined
Sep 28, 2011
Messages
402
Solutions
2
Reaction score
65
Location
Sweden
I need a check to determine if the player has any available slots where items can be placed.
This script will be used for quests etc, I've already made a check on the player's cap, now I need to check for the player's available slots.
Code:
function onUse(cid, item, frompos, item2, topos)
    local BP = getPlayerSlotItem(cid, CONST_SLOT_BACKPACK).uid
    if getContainerCapByID(BP) < 1 then
        doStuff
    else
        doOtherStuff
    end

Can't get it to work, all I get is:
attempt to call global 'getContainerCapByID' (a nil value)
With or without a backpack.

This is the function from functions.lua:
Code:
getContainerCapById(itemid)

Any help will be greatly appreciated! :)
 
Last edited:
Which tfs version are you running?

I think getContainerCapByID expects you to pass the items id, depending on the tfs version you are running the BP variable could be userdata or whatever it was in the earlier versions.

Maybe try
Code:
getContainerCapByID(BP.itemid)
or
getContainerCapByID(BP:getId())
or something like that.

Remember to always post the tfs version you are using, it is really helpful.
 
I'm not running TFS, I'm actually running OTServ 0.6.4 since I read it is the most stable distro.
I tried the ones you mentioned and while it didn't work. I got a new error which was quite interesting:
attempt to index local 'BP' (a number value)
(I also tried "getContainerCapByID(BP.uid)" and got the same result)

This works as far as checking for backpack, however checking for remaining slots does not:
Code:
function onUse(cid, item, frompos, item2, topos)'
    local BP = getPlayerSlotItem(cid, CONST_SLOT_BACKPACK)
    if BP.uid == 0 or getContainerCap(BP.uid) == false then
        doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "You have no backpack.")
    elseif getContainerCap(BP.uid) >= 1 then
        doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "Item added!")
    else
        doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "You have no room.")
    end
 
Last edited:
I'm not running TFS, I'm actually running OTServ 0.6.4 since I read it is the most stable distro.
I tried the ones you mentioned and while it didn't work. I got a new error which was quite interesting:

(I also tried "getContainerCapByID(BP.uid)" and got the same result)

This works as far as checking for backpack, however checking for remaining slots does not:
Code:
function onUse(cid, item, frompos, item2, topos)'
    local BP = getPlayerSlotItem(cid, CONST_SLOT_BACKPACK)
    if BP.uid == 0 or getContainerCap(BP.uid) == false then
        doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "You have no backpack.")
    elseif getContainerCap(BP.uid) >= 1 then
        doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "Item added!")
    else
        doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "You have no room.")
    end
I believe you are trying to use a cube in place of a triangle.

Try something like this instead.
Lua:
local item_id, count = 1988, 1

function onUse(cid, item, fromPosition, itemEx, toPosition)
    local reward, weight = doCreateItemEx(item_id, count), getItemWeightById(item_id, count)
    if doPlayerAddItemEx(cid, reward, false) == RETURNVALUE_NOERROR then
        doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "You have found a " .. getItemNameById(item_id) .. " weighing ".. string.format("%.2f", weight) .." oz.")
        return true
    else
        local cap = getPlayerFreeCap(cid)
        if cap < weight then
            doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "Require " .. string.format("%.2f", weight - cap) .. " more capacity to receive this reward weighing ".. string.format("%.2f", weight) .." oz.")
        else
            doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "You don't have any room to obtain this reward.")
        end
    end
    return true
end

-- Edit
If you are getting errors with 'weight' check below.

-- in case your lib doesn't have the function for whatever reason, put this into data/lib/050-function.lua
Lua:
function getItemWeightById(itemid, count, precision)
    local item, count, precision = getItemInfo(itemid), count or 1, precision or false
    if(not item) then
        return false
    end
   
    if(count > 100) then
        -- print a warning, as its impossible to have more than 100 stackable items without "cheating" the count
        --print('[Warning] getItemWeightById', 'Calculating weight for more than 100 items!')
    end
   
    local weight = item.weight * count
    return precission and weight or math.round(weight, 2)
end
 
I think it's easier if I just post my whole script:
Code:
local ITEM = 2195
local COUNT = 1
local DROPONGROUND = false

local ITEMNAME = getItemName(ITEM)
local STORAGE = getItemIdByName(ITEMNAME)
local WEIGHT = getItemWeightById(ITEM, COUNT)

function onUse(cid, item, frompos, item2, topos)
    if getPlayerFreeCap(cid) >= WEIGHT then
        if getPlayerStorageValue(cid, STORAGE) ~= 1 then
            if COUNT == 1 then
                doPlayerAddItem(cid, ITEM, COUNT, DROPONGROUND)
                doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "You have found "..ITEMNAME.."!")
                doSendMagicEffect(getCreaturePosition(cid), CONST_ME_MAGIC_GREEN)
                setPlayerStorageValue(cid, STORAGE, 1)
            elseif COUNT > 1 then
                doPlayerAddItem(cid, ITEM, COUNT, DROPONGROUND)
                doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "You have found "..COUNT.."x "..ITEMNAME.."!")
                doSendMagicEffect(getCreaturePosition(cid), CONST_ME_MAGIC_GREEN)
                setPlayerStorageValue(cid, STORAGE, 1)
            end
        else
            doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "It is empty.")
            doSendMagicEffect(getCreaturePosition(cid), CONST_ME_POFF)
        end
    else
        doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "You do not have enough capacity.")
    end
end

I've solved the cap check, more or less. But what I haven't solved is the check to see if the player has any free inventory.
Since my script runs on "DROPONGROUND = false" the player will recieve the reward even if he lacks the inventory slot but has the capacity, which triggers the storage and the item can never again be claimed.
I managed to make a temporary fix like they used back in the old OT's by making DROPONGROUND = true, which in turn just drops the item on the ground, but then again other players can pick it up instead, which makes it just a temporary solution to a permanent problem.
 
Last edited:
I think it's easier if I just post my whole script:
Code:
local ITEM = 2195
local COUNT = 1
local DROPONGROUND = false

local ITEMNAME = getItemName(ITEM)
local STORAGE = getItemIdByName(ITEMNAME)
local WEIGHT = getItemWeightById(ITEM, COUNT)

function onUse(cid, item, frompos, item2, topos)
    if getPlayerFreeCap(cid) >= WEIGHT then
        if getPlayerStorageValue(cid, STORAGE) ~= 1 then
            if COUNT == 1 then
                doPlayerAddItem(cid, ITEM, COUNT, DROPONGROUND)
                doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "You have found "..ITEMNAME.."!")
                doSendMagicEffect(getCreaturePosition(cid), CONST_ME_MAGIC_GREEN)
                setPlayerStorageValue(cid, STORAGE, 1)
            elseif COUNT > 1 then
                doPlayerAddItem(cid, ITEM, COUNT, DROPONGROUND)
                doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "You have found "..COUNT.."x "..ITEMNAME.."!")
                doSendMagicEffect(getCreaturePosition(cid), CONST_ME_MAGIC_GREEN)
                setPlayerStorageValue(cid, STORAGE, 1)
            end
        else
            doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "It is empty.")
            doSendMagicEffect(getCreaturePosition(cid), CONST_ME_POFF)
        end
    else
        doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "You do not have enough capacity.")
    end
end

I've solved the cap check, more or less. But what I haven't solved is the check to see if the player has any free inventory.
Since my script runs on "DROPONGROUND = false" the player will recieve the reward even if he lacks the inventory slot but has the capacity, which triggers the storage and the item can never again be claimed.
I managed to make a temporary fix like they used back in the old OT's by making DROPONGROUND = true, which in turn just drops the item on the ground, but then again other players can pick it up instead, which makes it just a temporary solution to a permanent problem.
I posted exactly what you wanted 3 hours before you posted this reply.
Here's the exact same script.. but with your '1 time use storage' requirement.
Lua:
local item_id, count = 1988, 1
local storage = 45001

function onUse(cid, item, fromPosition, itemEx, toPosition)
    if getPlayerStorageValue(cid, storage) == 1 then
        doSendMagicEffect(fromPosition, CONST_ME_POFF)
        doPlayerSendCancel(cid, "Chest is empty.")
        return true
    end
   
    local reward, weight = doCreateItemEx(item_id, count), getItemWeightById(item_id, count)
    if doPlayerAddItemEx(cid, reward, false) == RETURNVALUE_NOERROR then
        doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "You have found a " .. getItemNameById(item_id) .. " weighing ".. string.format("%.2f", weight) .." oz.")
        setPlayerStorageValue(cid, storage, 1)
        return true
    else
        local cap = getPlayerFreeCap(cid)
        if cap < weight then
            doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "Require " .. string.format("%.2f", weight - cap) .. " more capacity to receive this reward weighing ".. string.format("%.2f", weight) .." oz.")
        else
            doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "You don't have any room to obtain this reward.")
        end
    end
    return true
end
 
Yeah, thanks a lot for helping me out mate, however I had to abandon that distro. Way too many bugs and glitches to be worth working on, I switched to a 10.98 distro instead since the nature of my project doesn't really depend on the client version. Also a newer distro might be more worth putting time into, the OTServ 0.6.4 had problems such as manas not usable on ladders and this problem I mentioned in this thread among a lot of other problems. Since my VC17 is problematic I really have no energy to work with the sources either so I chose TFS 1.2 instead since it seems to have what I'm looking for, more or less anyway.

Keep helping the community, we appreciate you around here!
 
Lua:
function _getContainerFreeSlots(container)
    return getContainerCap(container) - getContainerSize(container)
end

function getContainerFreeSlots(container)
    if not isContainer(container) then
        return 0
    end

    local t, v = {}, 0
    for i = 0, getContainerSize(container)-1 do
        local item = getContainerItem(container, i)
        if isContainer(item.uid) then
            table.insert(t, item.uid)
        end
    end

    for _, check in pairs(t) do
        v = v + _getContainerFreeSlots(check)
    end

    return v + _getContainerFreeSlots(container)
end

usage
Lua:
if (getContainerFreeSlots(getPlayerSlotItem(cid, CONST_SLOT_BACKPACK).uid) == 0) then
-- has full bp!
 
Lua:
function _getContainerFreeSlots(container)
    return getContainerCap(container) - getContainerSize(container)
end

function getContainerFreeSlots(container)
    if not isContainer(container) then
        return 0
    end

    local t, v = {}, 0
    for i = 0, getContainerSize(container)-1 do
        local item = getContainerItem(container, i)
        if isContainer(item.uid) then
            table.insert(t, item.uid)
        end
    end

    for _, check in pairs(t) do
        v = v + _getContainerFreeSlots(check)
    end

    return v + _getContainerFreeSlots(container)
end

usage
Lua:
if (getContainerFreeSlots(getPlayerSlotItem(cid, CONST_SLOT_BACKPACK).uid) == 0) then
-- has full bp!
Has a small issue that isn't noticeable at first glance, but it only checks 1 layer deep.
container1 -> container2(InsideContainer1) -> container3(InsideContainer2)(not found)

Here is my fixed version, that loops through all the containers no matter how deep inside the inventory they are.

Lua:
function _getContainerFreeSlots(container)
    return getContainerCap(container) - getContainerSize(container)
end

function getContainerFreeSlots(container)
    if not isContainer(container) then
        return 0
    end
   
    local temp, containers, slots = {}, {}, 0
    table.insert(temp, container)
    while #temp > 0 do
        for i = 0, getContainerSize(temp[1]) - 1 do
            local item = getContainerItem(temp[1], i)
            if isContainer(item.uid) then
                table.insert(temp, item.uid)
                table.insert(containers, item.uid)
            end
        end
        table.remove(temp, 1)
    end
   
    for _, check in pairs(containers) do
        slots = slots + _getContainerFreeSlots(check)
    end
   
    return slots + _getContainerFreeSlots(container)
end
 
Last edited:
Lua:
function getAllContainerFree(cid)
    local containers,soma = {},0
        local sitem = getPlayerSlotItem(cid, 3)
        if sitem.uid > 0 then
            if isContainer(sitem.uid) then
                table.insert(containers, sitem.uid)
        soma = soma + getContainerSlotsFree(sitem.uid)
            end
        end
    while #containers > 0 do
        for k = (getContainerSize(containers[1]) - 1), 0, -1 do
            local tmp = getContainerItem(containers[1], k)
            if isContainer(tmp.uid) then
                table.insert(containers, tmp.uid)
                soma = soma + getContainerSlotsFree(tmp.uid)
            end
        end
        table.remove(containers, 1)
    end
    return soma
end
function getContainerSlotsFree(container)
         return getContainerCap(container)-getContainerSize(container)
end

-- code --

local x = getAllContainerFree(cid)
    if x > 0 then
        doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE,"You have ".. x .. " slots free.")
    end
 
Back
Top