• 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+ onMoveItem, do not allow placing item inside a container.

Fabi Marzan

Intermediate OT User
Joined
Aug 31, 2020
Messages
170
Solutions
7
Reaction score
104
I can't understand the cylinder, it doesn't allow me to place things inside the container, but when I throw an item into the container it does allow me.

LUA:
local ec = Event()

local ITEM_LOOT_POUCH = 23742

function ec.onMoveItem(player, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
    if toPosition.x == CONTAINER_POSITION then
        local containerTo = toCylinder
        
        if containerTo and containerTo:getId() == ITEM_LOOT_POUCH then
            player:sendCancelMessage('Sorry, not possible to place items inside the Loot Pouch.')
            return false
        end
    end
    return true
end

ec:register()

I try to make it block the items outside the container.

Gif Example:
20240719_220123-ezgif.com-video-to-gif-converter.gif
 
Solution
I don't know where in the sources I can avoid this
Container::queryDestination

Alternatively you can modify your current code from Container::queryAdd
C++:
// loot pouch: allow item autoloot
if (getID() == ITEM_LOOT_POUCH && !hasBitSet(FLAG_NOLIMIT, flags)) {
    return RETURNVALUE_LOOTPOUCHINVALIDITEM;
}
This should block everything, however you can use FLAG_NOLIMIT on Lua methods to successfully add items to the container

Additionally you need an extra check here to also cover child containers
C++:
if (const Container* container = cylinder->getContainer()) {
    if (container->getID() == ITEM_LOOT_POUCH) {
        return RETURNVALUE_CONTAINERNOTENOUGHROOM;
    }
}

@Edit
I would...
toCylinder is the inventory space it's being put into.

So when you move the items directly, it's finding the loot pouch id.
When you are moving items onto the loot pouch, it's finding the grey backpack id.

To solve the grey backpack, I think you can use toPosition, to find if it's being moved on top of a container item.. then you check that container item to see if it's the loot pouch.
 
toCylinder is the inventory space it's being put into.

So when you move the items directly, it's finding the loot pouch id.
When you are moving items onto the loot pouch, it's finding the grey backpack id.

To solve the grey backpack, I think you can use toPosition, to find if it's being moved on top of a container item.. then you check that container item to see if it's the loot pouch.
I tried but I didn't have success, the closest thing I could do was this:
LUA:
local ec = Event()

local ITEM_LOOT_POUCH = 23742

function ec.onMoveItem(player, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
    if toPosition.x == CONTAINER_POSITION then
        local containerTo = toCylinder
        
        if containerTo and containerTo:getId() == ITEM_LOOT_POUCH then
            player:sendCancelMessage('Sorry, not possible to place items inside the Loot Pouch.')
            return false
        end
    end

    if toCylinder and toCylinder:isContainer() then
        local destinationItem = toCylinder:getItem(0)
        if destinationItem and destinationItem:getId() == ITEM_LOOT_POUCH then
            player:sendTextMessage(MESSAGE_INFO_DESCR, "You cannot move items inside a loot pouch.")
            return false
        end
    end
    return true
end

ec:register()

But now it doesn't allow me to move anything, only when the loot pouch is in my backpack.
Recording 2024-07-20 at 11.07.01.gif
 
I tried but I didn't have success, the closest thing I could do was this:
LUA:
local ec = Event()

local ITEM_LOOT_POUCH = 23742

function ec.onMoveItem(player, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
    if toPosition.x == CONTAINER_POSITION then
        local containerTo = toCylinder
        
        if containerTo and containerTo:getId() == ITEM_LOOT_POUCH then
            player:sendCancelMessage('Sorry, not possible to place items inside the Loot Pouch.')
            return false
        end
    end

    if toCylinder and toCylinder:isContainer() then
        local destinationItem = toCylinder:getItem(0)
        if destinationItem and destinationItem:getId() == ITEM_LOOT_POUCH then
            player:sendTextMessage(MESSAGE_INFO_DESCR, "You cannot move items inside a loot pouch.")
            return false
        end
    end
    return true
end

ec:register()

But now it doesn't allow me to move anything, only when the loot pouch is in my backpack.
View attachment 86146
After you figure this out, you'll need to stop players from getting a container item into that container, and putting items into that container. (check for item parent recursively.)

(like a grey backpack in the loot container, which they then fill up with items)
(which isn't unreasonable to expect, if they trade with an npc for a grey backpack, and they have no other empty space for the grey backpack, but inside the loot container)
(which can happen with anything.. quest loot, shop loot, trading with another player.. anytime they receive an item and have no other space, it can be put into the loot container.)
 
Using lua I couldn't solve it, it entered the sources and container.ccp in Container::queryAdd
what I did was add this:
LUA:
// loot pouch: allow item autoloot
    if (getID() == ITEM_LOOT_POUCH) {
        if (actor && dynamic_cast<Player*>(actor)) {
            return RETURNVALUE_LOOTPOUCHINVALIDITEM;
        }
        return RETURNVALUE_NOERROR;
    }
And yes I was successful. But of course taking this into account, if the player does not have a backpack or more capacity in the backpack, the items are added to the loot pouch
Recording 2024-07-20 at 18.58.40.gif
I don't know where in the sources I can avoid this. Maybe in game.cpp? Game::internalAddItem?

EDIT: I was looking over, and posted something like this:
in Game::internalAddItem under the
if (ret != RETURNVALUE_NOERROR) {
return ret;
}
LUA:
Item* toContainerItem = toCylinder->getItem();
if (toContainerItem && toContainerItem->getID() == ITEM_LOOT_POUCH) {
    return RETURNVALUE_NOTPOSSIBLE;
}

And if it worked perfectly, I would like to know a way through Lua and not through sources. Because I was not successful doing it through onMoveitem
 
Last edited:
I don't know where in the sources I can avoid this
Container::queryDestination

Alternatively you can modify your current code from Container::queryAdd
C++:
// loot pouch: allow item autoloot
if (getID() == ITEM_LOOT_POUCH && !hasBitSet(FLAG_NOLIMIT, flags)) {
    return RETURNVALUE_LOOTPOUCHINVALIDITEM;
}
This should block everything, however you can use FLAG_NOLIMIT on Lua methods to successfully add items to the container

Additionally you need an extra check here to also cover child containers
C++:
if (const Container* container = cylinder->getContainer()) {
    if (container->getID() == ITEM_LOOT_POUCH) {
        return RETURNVALUE_CONTAINERNOTENOUGHROOM;
    }
}

@Edit
I would like to know a way through Lua and not through sources.
Btw, this is how you solve it on Lua, however you will still face the issue where items are being moved to loot pouch if player doesn't have an available container or capacity at all.
LUA:
if toCylinder then

    if toCylinder:isContainer() then

        local indexItem = toCylinder:getItem(toPosition.z)
        if not indexItem then

            local parent = toCylinder
            while(parent) do
    
                if not parent:isItem() then
                    break
                end
    
                if parent:getId() == LOOT_ITEM_POUCH then
                    return RETURNVALUE_NOTPOSSIBLE
                end
    
                parent = parent:getParent()
            end

        elseif indexItem:getId() == LOOT_ITEM_POUCH or toCylinder:getId() == LOOT_ITEM_POUCH then
            return RETURNVALUE_NOTPOSSIBLE
        end

    elseif not toCylinder:isTile() then -- player
        local slotItem = toCylinder:getSlotItem(toPosition.y)
    
        if slotItem and slotItem:getId() == LOOT_ITEM_POUCH then
            return RETURNVALUE_NOTPOSSIBLE
        end
    end
end
 
Solution
Container::queryDestination

Alternatively you can modify your current code from Container::queryAdd
C++:
// loot pouch: allow item autoloot
if (getID() == ITEM_LOOT_POUCH && !hasBitSet(FLAG_NOLIMIT, flags)) {
    return RETURNVALUE_LOOTPOUCHINVALIDITEM;
}
This should block everything, however you can use FLAG_NOLIMIT on Lua methods to successfully add items to the container

Additionally you need an extra check here to also cover child containers
C++:
if (const Container* container = cylinder->getContainer()) {
    if (container->getID() == ITEM_LOOT_POUCH) {
        return RETURNVALUE_CONTAINERNOTENOUGHROOM;
    }
}

@Edit

Btw, this is how you solve it on Lua, however you will still face the issue where items are being moved to loot pouch if player doesn't have an available container or capacity at all.
LUA:
if toCylinder then

    if toCylinder:isContainer() then

        local indexItem = toCylinder:getItem(toPosition.z)
        if not indexItem then

            local parent = toCylinder
            while(parent) do
   
                if not parent:isItem() then
                    break
                end
   
                if parent:getId() == LOOT_ITEM_POUCH then
                    return RETURNVALUE_NOTPOSSIBLE
                end
   
                parent = parent:getParent()
            end

        elseif indexItem:getId() == LOOT_ITEM_POUCH or toCylinder:getId() == LOOT_ITEM_POUCH then
            return RETURNVALUE_NOTPOSSIBLE
        end

    elseif not toCylinder:isTile() then -- player
        local slotItem = toCylinder:getSlotItem(toPosition.y)
   
        if slotItem and slotItem:getId() == LOOT_ITEM_POUCH then
            return RETURNVALUE_NOTPOSSIBLE
        end
    end
end
Oooh thanks for that.
The scripts worked perfectly for me, thank you. I used it for another container I had and it worked great for me.
 
@Roddet

I added this:
Container::queryDestination

Alternatively you can modify your current code from Container::queryAdd
C++:
// loot pouch: allow item autoloot
if (getID() == ITEM_LOOT_POUCH && !hasBitSet(FLAG_NOLIMIT, flags)) {
    return RETURNVALUE_LOOTPOUCHINVALIDITEM;
}
This should block everything, however you can use FLAG_NOLIMIT on Lua methods to successfully add items to the container

And it worked


But how do I create an authorized item list?
 
I know this may not be the ideal location, but it is well connected.
I have a custom autoloot in actions.cpp that moves the item to the player when he opens the body.
I would like to improve it by moving the item to the loot pouch or gold pouch in the case of money.
but looking all day for a way to identify the container to move, how can I do it? The only way I could find was to place the slot but not a specific container.
 

Similar threads

Back
Top