• 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 onMoveItem - players can hold only ONE item

silveralol

Advanced OT User
Joined
Mar 16, 2010
Messages
1,480
Solutions
9
Reaction score
212
hello folks, I'm trying make players can carry just ONE item...
so I try it:
Code:
   if item:getTopParent() ~= self and item:getId() == ITEM_ID then
        if player:getItemCount(ITEM_ID) >= 1 then
            self:sendCancelMessage('You cannot hold more balls.')
        end
    end
but using it I got this:
1 - if the player not have the ITEM_ID on your backpack or inventory he can move the item to anywhere
2 - if the player have the ITEM_ID on your backpack or inventory he can't move the item to anywhere
so I need to able players move the ITEM_ID to depot, house etc while are holding one the item in your backpack or inventory, but not move more than one item to your backpack
 
Last edited:
Solution
it return an error...
Code:
data/events/scripts/player.lua:Player@onMoveItem
data/events/scripts/player.lua:37: bad argument #2 to 'band' (number expected, got nil)
stack traceback:
        [C]: at 0x7ff7136d1390
        [C]: in function 'band'
        data/events/scripts/player.lua:37: in function 'ownerIsPlayer'
        data/events/scripts/player.lua:232: in function <data/events/scripts/player.lua:223>
if I change the function to it
Code:
function ownerIsPlayer(player, fromPos)
    if not player then return end
    if fromPos.x ~= CONTAINER_POSITION then return end
    if bit.band(fromPos.y, 0x40) ~= 64 then return end
    local container = player:getContainerById(bit.band(fromPos.y, 0x40))
    return container:getTopParent() ==...
hello folks, I'm trying make players can carry just ONE item...
so I try it:
Code:
   if item:getTopParent() ~= self and item:getId() == ITEM_ID then
        if player:getItemCount(ITEM_ID) >= 1 then
            self:sendCancelMessage('You cannot hold more balls.')
        end
    end
but using it I got this:
1 - if the player not have the ITEM_ID on your backpack or inventory he can move the item to anywhere
2 - if the player have the ITEM_ID on your backpack or inventory he can't move the item to anywhere
so I need to able players move the ITEM_ID to depot, house etc while are holding one the item in your backpack or inventory, but not move more than one item to your backpack
Check the position that the item is being moved to?
I beleive player inventory has a unique X position.
 
@Xikini
fromPosition.x is = CONTAINER_POSITION or Tile...
fromPosition.y is = CONST_ANYSLOT...
did not tested it yet, could give some exemple
 
For one you are switching from player to self in your code... for 2...you could try something like this

Code:
function onRemoveItem(moveitem, tileitem, position, player)
    if player:getItemCount(moveitem.itemid) == 1 then
        local pos1 = {x = position.x, y = position.y, z = position.z, stackpos = CONST_SLOT_ANYWHERE}
        local pos2 = {x = player:getPosition().x, y = player:getPosition().y, z = player:getPosition().z, stackpos = CONST_SLOT_ANYWHERE}
       
        if pos1 = pos2 then
            player:sendCancelMessage(cid, "You cannot hold more balls")
            return false
        end
    end
return true
end
 
I really didn't make it to work as it. In all honesty I haven't make a code for stopping the player from picking up and item they already have.

You could try this. Maybe use the information xiki said to edit the code to work. I will try some things on a test server later.

Lua:
function onRemoveItem(moveitem, tileitem, position, player)
    if player:getItemCount(moveitem.itemid) >= 1 then
        local pos_check = {x = player:getPosition().x, y = player:getPosition().y, z = player:getPosition().z, slot = CONST_SLOT_WHEREEVER}
     
        if position == pos_check then
            player:sendCancelMessage(cid, "You cannot hold more balls")
            return false
        end
    end
return true
end
 
I really didn't make it to work as it. In all honesty I haven't make a code for stopping the player from picking up and item they already have.

You could try this. Maybe use the information xiki said to edit the code to work. I will try some things on a test server later.

Lua:
function onRemoveItem(moveitem, tileitem, position, player)
    if player:getItemCount(moveitem.itemid) >= 1 then
        local pos_check = {x = player:getPosition().x, y = player:getPosition().y, z = player:getPosition().z, slot = CONST_SLOT_WHEREEVER}
   
        if position == pos_check then
            player:sendCancelMessage(cid, "You cannot hold more balls")
            return false
        end
    end
return true
end
function removeItem doens't have player as paramter, so how I can get the player ?
Code:
Lua Script Error: [MoveEvents Interface]
data/movements/scripts/others/balls.lua:onRemoveItem
data/movements/scripts/others/balls.lua:2: attempt to index local 'player' (a nil value)
stack traceback:
        [C]: in function '__index'
        data/movements/scripts/others/balls.lua:2: in function <data/movements/scripts/others/balls.lua:1>
 
I tested this. It needs to be modified a little but it works for now. The only problem with this right now is you cannot move an item up a floor/down a floor if you have the item.

Lua:
local allow_one_only = {25199}

function Player:onMoveItem(item, count, fromPosition, toPosition)

    if isInArray(allow_one_only, item.itemid) then
        if self:getItemCount(item.itemid) > 0 then
            if toPosition.z < fromPosition.z then
                self:sendCancelMessage("You cant pick this up.")
            return false
            end
        end
    end

    return true
end
 
data/events/scripts/player.lua
Lua:
local itemsOnlySingle = { 2667 }
function Player:onMoveItem(item, count, fromPosition, toPosition)
  local toDepotFlag = 66
  local moveUpDepotFlag = 68
  -- Is putting to backpack/inventory and is of itemsOnlySingle and (are moving more than one or player are already holding this item) and is not (inside depot or moving up inside depot)
  if toPosition.x == CONTAINER_POSITION and isInArray(itemsOnlySingle, item.itemid) and (count > 1 or self:getItemCount(item.itemid) > 0) and not (toPosition.y == toDepotFlag or toPosition.y == moveUpDepotFlag) then
    self:sendCancelMessage("You cannot get more than one of this item.")
    return false
  end
  return true
end

data/events/events.xml
Code:
<event enabled="1" class="Player" method="onMoveItem" />
 
data/events/scripts/player.lua
Lua:
local itemsOnlySingle = { 2667 }
function Player:onMoveItem(item, count, fromPosition, toPosition)
  local toDepotFlag = 66
  local moveUpDepotFlag = 68
  -- Is putting to backpack/inventory and is of itemsOnlySingle and (are moving more than one or player are already holding this item) and is not (inside depot or moving up inside depot)
  if toPosition.x == CONTAINER_POSITION and isInArray(itemsOnlySingle, item.itemid) and (count > 1 or self:getItemCount(item.itemid) > 0) and not (toPosition.y == toDepotFlag or toPosition.y == moveUpDepotFlag) then
    self:sendCancelMessage("You cannot get more than one of this item.")
    return false
  end
  return true
end

data/events/events.xml
Code:
<event enabled="1" class="Player" method="onMoveItem" />
the player can't move to the CONTAINER_POSITION same if it is the depot :/ I need that the players just cannot carry more than one, but be able to move it to the depot or house, seems that I need a source edit

I tested this. It needs to be modified a little but it works for now. The only problem with this right now is you cannot move an item up a floor/down a floor if you have the item.

Lua:
local allow_one_only = {25199}

function Player:onMoveItem(item, count, fromPosition, toPosition)

    if isInArray(allow_one_only, item.itemid) then
        if self:getItemCount(item.itemid) > 0 then
            if toPosition.z < fromPosition.z then
                self:sendCancelMessage("You cant pick this up.")
            return false
            end
        end
    end

    return true
end
also this code seems bugged somewhere, sometimes I can took more than two balls, and then I can't :eek: it's weird
 
Last edited by a moderator:
also this code seems bugged somewhere, sometimes I can took more than two balls, and then I can't :eek: it's weird

It's weird, since I tested in here and it worked fine.

Edit: Tried again, and it worked fine again. So I think you are doing something wrong or something else is bugging that.
 
TFS 1.2/3 @whitevo

It's weird, since I tested in here and it worked fine.

Edit: Tried again, and it worked fine again. So I think you are doing something wrong or something else is bugging that.
bro, test like that:
player have a ball in the inventory
try move to inside of the depot another ball
see the results...
try move balls from different map positions to the backpack of the player that already is carrying one ball, here it is weird, if you want I can make a video for u
 
Last edited by a moderator:
Code:
function ownerIsPlayer(player, fromPos)
    if not player then return end
    if fromPos.x ~= CONTAINER_POSITION then return end
    if bit.band(fromPos.y, BIT_CONTAINER) ~= 64 then return end
    local container = player:getContainerById(bit.band(fromPos.y, BIT_CONTAINER_ID))
    return container:getTopParent() == player
end
use this function to determine who owns the ball
 
Code:
function ownerIsPlayer(player, fromPos)
    if not player then return end
    if fromPos.x ~= CONTAINER_POSITION then return end
    if bit.band(fromPos.y, BIT_CONTAINER) ~= 64 then return end
    local container = player:getContainerById(bit.band(fromPos.y, BIT_CONTAINER_ID))
    return container:getTopParent() == player
end
use this function to determine who owns the ball
it return an error...
Code:
data/events/scripts/player.lua:Player@onMoveItem
data/events/scripts/player.lua:37: bad argument #2 to 'band' (number expected, got nil)
stack traceback:
        [C]: at 0x7ff7136d1390
        [C]: in function 'band'
        data/events/scripts/player.lua:37: in function 'ownerIsPlayer'
        data/events/scripts/player.lua:232: in function <data/events/scripts/player.lua:223>
if I change the function to it
Code:
function ownerIsPlayer(player, fromPos)
    if not player then return end
    if fromPos.x ~= CONTAINER_POSITION then return end
    if bit.band(fromPos.y, 0x40) ~= 64 then return end
    local container = player:getContainerById(bit.band(fromPos.y, 0x40))
    return container:getTopParent() == player
end
it return another error, but is different
Code:
Lua Script Error: [Event Interface]
data/events/scripts/player.lua:Player@onMoveItem
data/events/scripts/player.lua:39: attempt to index local 'container' (a nil value)
stack traceback:
        [C]: in function '__index'
        data/events/scripts/player.lua:39: in function 'ownerIsPlayer'
        data/events/scripts/player.lua:232: in function <data/events/scripts/player.lua:223>
I'm trying use it...
as just a code test
Code:
if item:getId() == ballId then
        local player = ownerIsPlayer(self, fromPosition)
        if player then
            print('test')
            return true
        end
    end
 
it return an error...
Code:
data/events/scripts/player.lua:Player@onMoveItem
data/events/scripts/player.lua:37: bad argument #2 to 'band' (number expected, got nil)
stack traceback:
        [C]: at 0x7ff7136d1390
        [C]: in function 'band'
        data/events/scripts/player.lua:37: in function 'ownerIsPlayer'
        data/events/scripts/player.lua:232: in function <data/events/scripts/player.lua:223>
if I change the function to it
Code:
function ownerIsPlayer(player, fromPos)
    if not player then return end
    if fromPos.x ~= CONTAINER_POSITION then return end
    if bit.band(fromPos.y, 0x40) ~= 64 then return end
    local container = player:getContainerById(bit.band(fromPos.y, 0x40))
    return container:getTopParent() == player
end
it return another error, but is different
Code:
Lua Script Error: [Event Interface]
data/events/scripts/player.lua:Player@onMoveItem
data/events/scripts/player.lua:39: attempt to index local 'container' (a nil value)
stack traceback:
        [C]: in function '__index'
        data/events/scripts/player.lua:39: in function 'ownerIsPlayer'
        data/events/scripts/player.lua:232: in function <data/events/scripts/player.lua:223>
I'm trying use it...
as just a code test
Code:
if item:getId() == ballId then
        local player = ownerIsPlayer(self, fromPosition)
        if player then
            print('test')
            return true
        end
    end

Damn... This one was hard.

Lua:
local BIT_CONTAINER = 0x40
local BIT_CONTAINER_ID = 0x0F

function Player:isContainerOwner(pos) -- Check if pos is with player (pos is in inventory or backpacks)
  if pos.x ~= CONTAINER_POSITION then return false end
  if pos.y >= CONST_SLOT_FIRST and pos.y <= CONST_SLOT_LAST then return true end
  if bit.band(pos.y, BIT_CONTAINER) ~= 64 then return false end
  local container = self:getContainerById(bit.band(pos.y, BIT_CONTAINER_ID))
  return container and container:getTopParent() == self or false
end

local itemsOnlySingle = { 2667 }
function Player:onMoveItem(item, count, fromPosition, toPosition)
  local isOnlySingleItem = isInArray(itemsOnlySingle, item.itemid)
  local movingToPlayer = not self:isContainerOwner(fromPosition) and self:isContainerOwner(toPosition)
  local movingMoreThanOne = count > 1 -- error condition
  local hasItemAlready = self:getItemCount(item.itemid) > 0 -- error condition
  local error = movingMoreThanOne or hasItemAlready
  if isOnlySingleItem and movingToPlayer and error then
    self:sendCancelMessage("You cannot get more than one of this item.")
    return false
  end
  return true
end

Credits of Player:isContainerOwner is almost 100% to @whitevo
 
Solution
Damn... This one was hard.

Lua:
local BIT_CONTAINER = 0x40
local BIT_CONTAINER_ID = 0x0F

function Player:isContainerOwner(pos) -- Check if pos is with player (pos is in inventory or backpacks)
  if pos.x ~= CONTAINER_POSITION then return false end
  if pos.y >= CONST_SLOT_FIRST and pos.y <= CONST_SLOT_LAST then return true end
  if bit.band(pos.y, BIT_CONTAINER) ~= 64 then return false end
  local container = self:getContainerById(bit.band(pos.y, BIT_CONTAINER_ID))
  return container and container:getTopParent() == self or false
end

local itemsOnlySingle = { 2667 }
function Player:onMoveItem(item, count, fromPosition, toPosition)
  local isOnlySingleItem = isInArray(itemsOnlySingle, item.itemid)
  local movingToPlayer = not self:isContainerOwner(fromPosition) and self:isContainerOwner(toPosition)
  local movingMoreThanOne = count > 1 -- error condition
  local hasItemAlready = self:getItemCount(item.itemid) > 0 -- error condition
  local error = movingMoreThanOne or hasItemAlready
  if isOnlySingleItem and movingToPlayer and error then
    self:sendCancelMessage("You cannot get more than one of this item.")
    return false
  end
  return true
end

Credits of Player:isContainerOwner is almost 100% to @whitevo
got an error
Code:
data/events/scripts/player.lua:Player@onMoveItem
data/events/scripts/player.lua:39: attempt to compare nil with number
stack traceback:
        [C]: in function '__le'
        data/events/scripts/player.lua:39: in function 'isContainerOwner'
        data/events/scripts/player.lua:236: in function <data/events/scripts/player.lua:226>
line
Code:
if pos.y >= CONST_SLOT_FIRST and pos.y <= CONST_SLOT_LAST then return true end
 
got an error
Code:
data/events/scripts/player.lua:Player@onMoveItem
data/events/scripts/player.lua:39: attempt to compare nil with number
stack traceback:
        [C]: in function '__le'
        data/events/scripts/player.lua:39: in function 'isContainerOwner'
        data/events/scripts/player.lua:236: in function <data/events/scripts/player.lua:226>
line
Code:
if pos.y >= CONST_SLOT_FIRST and pos.y <= CONST_SLOT_LAST then return true end

CONST_SLOT_FIRST or CONST_SLOT_LAST are not defined.

Edit:

The best way is to register the enum of CONST_SLOT_FIRST and CONST_SLOT_LAST.
Find this:
C++:
    registerEnum(CONST_SLOT_HEAD)
    registerEnum(CONST_SLOT_NECKLACE)
    registerEnum(CONST_SLOT_BACKPACK)
    registerEnum(CONST_SLOT_ARMOR)
    registerEnum(CONST_SLOT_RIGHT)
    registerEnum(CONST_SLOT_LEFT)
    registerEnum(CONST_SLOT_LEGS)
    registerEnum(CONST_SLOT_FEET)
    registerEnum(CONST_SLOT_RING)
    registerEnum(CONST_SLOT_AMMO)
Then add:
C++:
    registerEnum(CONST_SLOT_FIRST)
    registerEnum(CONST_SLOT_LAST)
At the bottom and recompile. It will make you able to use the constants CONST_SLOT_FIRST and CONST_SLOT_LAST on Lua code.
 
Last edited:
CONST_SLOT_FIRST or CONST_SLOT_LAST are not defined.

Edit:

The best way is to register the enum of CONST_SLOT_FIRST and CONST_SLOT_LAST.
Find this:
C++:
    registerEnum(CONST_SLOT_HEAD)
    registerEnum(CONST_SLOT_NECKLACE)
    registerEnum(CONST_SLOT_BACKPACK)
    registerEnum(CONST_SLOT_ARMOR)
    registerEnum(CONST_SLOT_RIGHT)
    registerEnum(CONST_SLOT_LEFT)
    registerEnum(CONST_SLOT_LEGS)
    registerEnum(CONST_SLOT_FEET)
    registerEnum(CONST_SLOT_RING)
    registerEnum(CONST_SLOT_AMMO)
Then add:
C++:
    registerEnum(CONST_SLOT_FIRST)
    registerEnum(CONST_SLOT_LAST)
At the bottom and recompile. It will make you able to use the constants CONST_SLOT_FIRST and CONST_SLOT_LAST on Lua code.
edit, i'm compiling it ...
@River KA it work, thank you very much <3 also thanks for the another guys that help with something
 
Last edited:
Back
Top