• 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 Buy more than 100 items from an NPC

X X X

Newb
Joined
Jul 26, 2015
Messages
146
Reaction score
13
Using TFS 1.2

Cannot figure out how to make it so an NPC can sell more than 100 of an item. Here is the "doNpcSellItem" function from my npc.lua:

Lua:
function doNpcSellItem(cid, itemid, amount, subType, ignoreCap, inBackpacks, backpack)
    local amount = amount or 1
    local subType = subType or 0
    local item = 0
    if ItemType(itemid):isStackable() then
        if inBackpacks then
            stuff = Game.createItem(backpack, 1)
            item = stuff:addItem(itemid, math.min(100, amount))
        else
            stuff = Game.createItem(itemid, math.min(100, amount))
        end
        print(stuff)
        print(amount)
        print(itemid)
        return Player(cid):addItemEx(stuff, ignoreCap) ~= RETURNVALUE_NOERROR and 0 or amount, 0
    end

    local a = 0
    if inBackpacks then
        local container, b = Game.createItem(backpack, 1), 1
        for i = 1, amount do
            local item = container:addItem(itemid, subType)
            if table.contains({(ItemType(backpack):getCapacity() * b), amount}, i) then
                if Player(cid):addItemEx(container, ignoreCap) ~= RETURNVALUE_NOERROR then
                    b = b - 1
                    break
                end

                a = i
                if amount > i then
                    container = Game.createItem(backpack, 1)
                    b = b + 1
                end
            end
        end
        return a, b
    end

    for i = 1, amount do -- normal method for non-stackable items
        local item = Game.createItem(itemid, subType)
        if Player(cid):addItemEx(item, ignoreCap) ~= RETURNVALUE_NOERROR then
            break
        end
        a = i
    end
    return a, 0
end

As you can see, I had added some prints in there as a sanity check to make sure that was the function being used.

After changing the "maxCount" variable in modules.lua

Lua:
ShopModule = {
        npcHandler = nil,
        yesNode = nil,
        noNode = nil,
        noText = "",
        maxCount = 500,
        amount = 0
    }

I can go to an NPC and say "buy 200 mana potions", and the NPC replies with the correct amount:

Code:
17:24 Test Player: buy 200 mana potion
17:24 Simon: Do you want to buy 200 mana potion for 15000 gold coins?
17:24 Test Player: yes

However, my output in the game console from the prints above is this:

Code:
userdata: 0x403189b8
100
5423

And the NPC only gives me 100 mana potions. So the NPC is successfully getting the correct input of 200, but somewhere the output is capped at 100 and I cannot figure out why. Is this a problem with the function "Player(cid):addItemEx"?

Thanks in advance, please let me know if there are any other bits of code that need to be included.
 
Been a little while, bumping. Still have not managed to make any progress on this myself, nor have I found the answer here on the forums.
 
Some more info, maybe this can help provide additional context:

I realized that the function for giving the player the item had math.min at (100, armount) which means that even if I try and buy more than 100, math.min will return 100 since it is lower. So, I changed the math.min function here in npc.lua to be 500 instead:

Lua:
stuff = Game.createItem(itemid, math.min(500, amount))

When I did that and tested in game, I got the following output from my prints:

Code:
table: 0x4167c320
103
5425

Lua Script Error: [Npc interface]
data/npc/scripts/magic.lua:onCreatureSay
luaPlayerAddItemEx(). Item not found

The NPC tells the player "You don't have enough capacity," and does not give the player any items or take any money. I'm still just as lost, maybe this will help someone else?? I just can't believe it should be this difficult to get an NPC to sell more than 100x of some stackable item in TFS 1.2.
 
Some more info, maybe this can help provide additional context:

I realized that the function for giving the player the item had math.min at (100, armount) which means that even if I try and buy more than 100, math.min will return 100 since it is lower. So, I changed the math.min function here in npc.lua to be 500 instead:

Lua:
stuff = Game.createItem(itemid, math.min(500, amount))

When I did that and tested in game, I got the following output from my prints:

Code:
table: 0x4167c320
103
5425

Lua Script Error: [Npc interface]
data/npc/scripts/magic.lua:onCreatureSay
luaPlayerAddItemEx(). Item not found

The NPC tells the player "You don't have enough capacity," and does not give the player any items or take any money. I'm still just as lost, maybe this will help someone else?? I just can't believe it should be this difficult to get an NPC to sell more than 100x of some stackable item in TFS 1.2.
Well, stackable items can only go to 100 in the client.

If you want to give 5 stacks of 100 items, you'd have to make a loop, you can see it happening here
Lua:
for i = 1, amount do -- normal method for non-stackable items

So you'd have to modify the code to do that for stackable items, in increments of 100.

something like
Lua:
local amount = 444 -- you get this from the function call.
while amount > 0 do
    local amountToGive = math.min(100, amount)
    -- give 100 items
    print(amountToGive)
    amount = amount - amountToGive
end
output
Code:
100
100
100
100
44
 
Thanks for the reply @Xikini. Using a loop does make sense, I hadn't thought of that. I actually tried looking at the script behind the GM command for creating item (/i) and it didn't use any loops at all so I guess I had tunnel vision:

Lua:
if count ~= nil then
        if itemType:isStackable() then
            count = math.min(10000, math.max(1, count))
        elseif not itemType:isFluidContainer() then
            count = math.min(100, math.max(1, count))
        else
            count = math.max(0, count)
        end
    else
        if not itemType:isFluidContainer() then
            count = 1
        else
            count = 0
        end
    end

    local result = player:addItem(itemType:getId(), count)

When you "/i meat, 400", the game will put 4x stacks of 100 meat in your bag. How does it do it without a loop?
 
Last edited:
Thanks for the reply @Xikini. Using a loop does make sense, I hadn't thought of that. I actually tried looking at the script behind the GM command for creating item (/i) and it didn't use any loops at all so I guess I had tunnel vision:

Lua:
if count ~= nil then
        if itemType:isStackable() then
            count = math.min(10000, math.max(1, count))
        elseif not itemType:isFluidContainer() then
            count = math.min(100, math.max(1, count))
        else
            count = math.max(0, count)
        end
    else
        if not itemType:isFluidContainer() then
            count = 1
        else
            count = 0
        end
    end

    local result = player:addItem(itemType:getId(), count)

When you "/i meat, 400", the game will put 4x stacks of 100 meat in your bag. How does it do it without a loop?
Looks like the player:addItem function has a loop in it itself.


However, player:addItemEx does not have that loop imbedded into the function, which is where you see the discrepancy between your function and the /i command.


/i command -> local result = player:addItem(itemType:getId(), count)
npc function -> return Player(cid):addItemEx(stuff, ignoreCap) ~= RETURNVALUE_NOERROR and 0 or amount, 0

-- Edit
This might help you to look at, if you're planning to do loops.
 
Last edited:
Aaahh ok. I did notice one was AddItemEx and one was AddItem, did not know what the difference was. Is it better to try and re-work this player:addItemEx to include or loop or should I just change the npc.lua function to player:addItem instead? When I say better I mean which one is "best practice" for coding?
------EDIT------

I certainly made progress! But, I'm a bit lost at what to return:

Lua:
if ItemType(itemid):isStackable() then
        if inBackpacks then
            stuff = Game.createItem(backpack, 1)
            item = stuff:addItem(itemid, math.min(100, amount))
        else
            while amount > 0 do
                local amountToGive = math.min(100, amount)
                stuff = Game.createItem(itemid, math.min(100, amount))
                Player(cid):addItemEx(stuff, ignoreCap)
                amount = amount - amountToGive
            end
        end
        print(stuff)
        print(amount)
        print(itemid)
        return --what do I return here since I'm adding the item up above already?
    end

If I just return true, the NPC does give me the items, but does not take my money and tells me I don't have enough capacity. Getting closer though!

----EDIT #2----

I think I figured it out!!

Lua:
function doNpcSellItem(cid, itemid, amount, subType, ignoreCap, inBackpacks, backpack)
    local amount = amount or 1
    local amountToReturn = amount
    local subType = subType or 0
    local item = 0
    if ItemType(itemid):isStackable() then
        if inBackpacks then
            stuff = Game.createItem(backpack, 1)
            item = stuff:addItem(itemid, math.min(100, amount))
        else
            while amount > 0 do
                local amountToGive = math.min(100, amount)
                stuff = Game.createItem(itemid, math.min(100, amount))
                Player(cid):addItemEx(stuff, ignoreCap)
                amount = amount - amountToGive
            end
        end
        return amountToReturn
    end

I realized the game wants you to return the amount sold so it can calculate the money it needs to deduct (modules.lua). Because the "amount" variable is changing in the loop, I made another variable "amountToReturn" the retains the original value, and then just return that at the end of the if statement. Seems to work so far: NPC takes the right amount of money, gives the right amount of items. Is there anything I'm missing?

-----EDIT #3-----
I did not get it. I realized that the code above does not account for what happens when a player has no cap/no space. The NPC will take your money and not give you the item instead of telling you "You need more capacity".

Lua:
function doNpcSellItem(cid, itemid, amount, subType, ignoreCap, inBackpacks, backpack)
    local amount = amount or 1
    local amountToReturn = amount
    local subType = subType or 0
    local item = 0
    if ItemType(itemid):isStackable() then
        if inBackpacks then
            stuff = Game.createItem(backpack, 1)
            item = stuff:addItem(itemid, math.min(100, amount))
        else
            while amount > 0 do
                local amountToGive = math.min(100, amount)
                stuff = Game.createItem(itemid, math.min(100, amount))
                if Player(cid):addItemEx(stuff, ignoreCap) ~= RETURNVALUE_NOERROR then
                    print("no cap") --this part works, the loop stops if the player doesn't have enough cap
                    break
                end
                amount = amount - amountToGive
            end
        end
        return amountToReturn, 0 --NPC still takes your money because the function returns success
    end

I tried to modify the loop so it breaks, similar to the method for non-stackable items, but I'm stuck. How do I make this function return the correct value if the player has no cap?
 
Last edited:
All of this fancy loop stuff is great and I'm sure there's a way to get it to work with player:addItemEx(), but why not just use the built in loop included in the player:addItem() function?

If you don't care about excess items going on the ground, then just do this:
Lua:
function doNpcSellItem(cid, itemid, amount, subType, ignoreCap, inBackpacks, backpack)
    local amount = amount or 1
    local amountToReturn = amount
    local subType = subType or 0
    local item = 0
    if ItemType(itemid):isStackable() then
        if inBackpacks then
            stuff = Game.createItem(backpack, 1)
            item = stuff:addItem(itemid, math.min(100, amount))
        return Player(cid):addItemEx(stuff, ignoreCap) ~= RETURNVALUE_NOERROR and 0 or amount, 0
    end
   
    if ItemType(itemid):isStackable() then
        return Player(cid):addItem(itemid, amount) and amount
    end

Split up the inBackpack and regular portion. If the player buys 100+ of an item, whatever they have enough cap/inventory space for goes in their bag, hand, arrow slot (whatever is free). everything else goes on the ground (similar to how RL used to work).

Maybe there's some ultra-efficient way to combine it all into one slick function, but it sounds like you want players to just be able to go to an NPC and buy however many potions they want without having to do it in chunks of 100, 100, etc. This will work for that.
 
All of this fancy loop stuff is great and I'm sure there's a way to get it to work with player:addItemEx(), but why not just use the built in loop included in the player:addItem() function?

If you don't care about excess items going on the ground, then just do this:
Lua:
function doNpcSellItem(cid, itemid, amount, subType, ignoreCap, inBackpacks, backpack)
    local amount = amount or 1
    local amountToReturn = amount
    local subType = subType or 0
    local item = 0
    if ItemType(itemid):isStackable() then
        if inBackpacks then
            stuff = Game.createItem(backpack, 1)
            item = stuff:addItem(itemid, math.min(100, amount))
        return Player(cid):addItemEx(stuff, ignoreCap) ~= RETURNVALUE_NOERROR and 0 or amount, 0
    end
  
    if ItemType(itemid):isStackable() then
        return Player(cid):addItem(itemid, amount) and amount
    end

Split up the inBackpack and regular portion. If the player buys 100+ of an item, whatever they have enough cap/inventory space for goes in their bag, hand, arrow slot (whatever is free). everything else goes on the ground (similar to how RL used to work).

Maybe there's some ultra-efficient way to combine it all into one slick function, but it sounds like you want players to just be able to go to an NPC and buy however many potions they want without having to do it in chunks of 100, 100, etc. This will work for that.
Does this work with tfs 1.5?
 
Back
Top