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

C++ Adding text to buyable books.

noshirtstan

New Member
Joined
Aug 2, 2020
Messages
68
Reaction score
2
Hey folks,

I'm having a small issue with having a shop add text to a scroll or book that is preset.

I've tried adding a text parameter to the shop module but it doesn't seem to be working.

Using TFS 1.3

Any thoughts or help would be awesome!
 
Lua:
function ShopModule:addBuyableItemContainer(names, container, itemid, cost, subType, realName, actionid, text) -- by dwarfer
        if names then
            for i, name in pairs(names) do
                local parameters = {
                        container = container,
                        itemid = itemid,
                        cost = cost,
                        eventType = SHOPMODULE_BUY_ITEM_CONTAINER,
                        module = self,
                        realName = realName or ItemType(itemid):getName(),
                        subType = subType or 1,
                  actionid = actionid,
                  text = text -- by noshirtstan
                    }
 
                keywords = {}
                keywords[#keywords + 1] = "buy"
                keywords[#keywords + 1] = name
                local node = self.npcHandler.keywordHandler:addKeyword(keywords, ShopModule.tradeItem, parameters)
                node:addChildKeywordNode(self.yesNode)
                node:addChildKeywordNode(self.noNode)
            end
        end
    end

So ive added this in various places within modules.lua

Code:
function doNpcSellItem(cid, itemid, amount, subType, ignoreCap, inBackpacks, backpack, actionid, text) -- by dwarfer
    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))
            if actionid > 0 then -- by dwarfer
                item:setActionId(actionid)
            end
            if itemid == 26384 then -- by noshirtstan
                item:setText(text)
            end
        else
            stuff = Game.createItem(itemid, math.min(100, amount))
            if actionid > 0 then -- by dwarfer
                stuff:setActionId(actionid)
            end
        end
        return Player(cid):addItemEx(stuff, ignoreCap) ~= RETURNVALUE_NOERROR and 0 or amount, 0
    end

i have also added this.

When i try to add the text in the lua for the npc it doesnt work.

Code:
local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)
NpcSystem.parseParameters(npcHandler)

local TopicState = {}

-- OTServ event handling functions start
function onCreatureAppear(cid)              npcHandler:onCreatureAppear(cid) end
function onCreatureDisappear(cid)           npcHandler:onCreatureDisappear(cid) end
function onCreatureSay(cid, type, msg)      npcHandler:onCreatureSay(cid, type, msg) end
function onPlayerEndTrade(cid)              npcHandler:onPlayerEndTrade(cid) end
function onPlayerCloseChannel(cid)          npcHandler:onPlayerCloseChannel(cid) end
function onThink()                          npcHandler:onThink() end
-- OTServ event handling functions end

local shopModule = ShopModule:new()
npcHandler:addModule(shopModule)

    -- Buy
    shopModule:addBuyableItem({"Recipe"}, 26384, 1, 1, "recipe", 50501, "101") -- add text to scroll at the end
    shopModule:addBuyableItem({"Torch"}, 2050, 5)
    shopModule:addBuyableItem({"Fishing Rod"}, 2580, 50)
    shopModule:addBuyableItem({"Pick"}, 2553, 150)
    shopModule:addBuyableItem({"Shovel"}, 2554, 150)
    shopModule:addBuyableItem({"Rope"}, 2120, 150)
    shopModule:addBuyableItem({"Worm"}, 3976, 1)
    shopModule:addBuyableItem({"BackPack"}, 1988, 30)
    shopModule:addBuyableItem({"Bag"}, 1987, 10)
    shopModule:addBuyableItem({"Teleport Crystal"}, 12508, 1000)
    -- Sell
    shopModule:addSellableItem({"Meat"}, 2666, 2)
    shopModule:addSellableItem({"Orc Leather"}, 12435, 10)
    shopModule:addSellableItem({"Orc Tooth"}, 11113, 10)
    shopModule:addSellableItem({"Bunch of Troll Hair"}, 10606, 10)
    shopModule:addSellableItem({"Rope"}, 2120, 10)


function creatureSayCallback(cid, type, msg)

    if (msgcontains(msg, "hello") or msgcontains(msg, "hi")) and (not npcHandler:isFocused(cid)) then
        npcHandler:say("Hello adventurer! Welcome to the tool shop.", cid)
        npcHandler:addFocus(cid)
        TopicState[cid] = 0

    elseif(not npcHandler:isFocused(cid)) then
        return false

    elseif msgcontains(msg, "bye") or msgcontains(msg, "farewell") then
        npcHandler:say("Goodbye.", cid, TRUE)
        npcHandler:releaseFocus(cid)

    end

    return true

end

npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
npcHandler:setMessage(MESSAGE_WALKAWAY, "How rude!")
npcHandler:setMessage(MESSAGE_SENDTRADE, "Here is what I have to offer.")
npcHandler:setMessage(MESSAGE_ONCLOSESHOP, "Thanks you for your business.")
npcHandler:setMessage(MESSAGE_IDLETIMEOUT, "Goodbye!")
 
there is no such thing as :setText (unless you are using otservbr global) 😁 you need to use
item:setAttribute(ITEM_ATTRIBUTE_TEXT, text)

so the donpcsell function would be something like this:

Lua:
function doNpcSellItem(cid, itemid, amount, subType, ignoreCap, inBackpacks, backpack, actionid, text) -- by dwarfer
    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))
            if actionid > 0 then -- by dwarfer
                item:setActionId(actionid)
            end
            if text ~= "" then
                item:setAttribute(ITEM_ATTRIBUTE_TEXT, text)
            end
        else
            stuff = Game.createItem(itemid, math.min(100, amount))
            if actionid > 0 then -- by dwarfer
                stuff:setActionId(actionid)
            end
            if text ~= "" then
                stuff:setAttribute(ITEM_ATTRIBUTE_TEXT, text)
            end
        end
        return Player(cid):addItemEx(stuff, ignoreCap) ~= RETURNVALUE_NOERROR and 0 or amount, 0
    end
 
In game it's telling me I cannot use the item.

Lua:
-- Including the Advanced NPC System
dofile('data/npc/lib/npcsystem/npcsystem.lua')
 
function msgcontains(message, keyword)
    local message, keyword = message:lower(), keyword:lower()
    if message == keyword then
        return true
    end
 
    return message:find(keyword) and not message:find('(%w+)' .. keyword)
end
 
function doNpcSellItem(cid, itemid, amount, subType, ignoreCap, inBackpacks, backpack, actionid, text) -- by dwarfer
    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))
            if actionid > 0 then -- by dwarfer
                item:setActionId(actionid)
            end
            if itemid == 26384 then -- by noshirtstan
                item:setAttribute(ITEM_ATTRIBUTE_TEXT, text)
            end
        else
            stuff = Game.createItem(itemid, math.min(100, amount))
            if actionid > 0 then -- by dwarfer
                stuff:setActionId(actionid)
            end
        end
        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 actionid > 0 then -- by dwarfer
                item:setActionId(actionid)
            end
            if itemid == 26384 then
                item:setAttribute(ITEM_ATTRIBUTE_TEXT, text)
            end
            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 actionid > 0 then -- by dwarfer
            item:setActionId(actionid)
        end
        if itemid == 26384 then
            item:setAttribute(ITEM_ATTRIBUTE_TEXT, text)
        end   
        
        if Player(cid):addItemEx(item, ignoreCap) ~= RETURNVALUE_NOERROR then
            break
        end
        a = i
    end
    return a, 0
end
 
local func = function(cid, text, type, e, pcid)
    if Player(pcid):isPlayer() then
        local creature = Creature(cid)
        creature:say(text, type, false, pcid, creature:getPosition())
        e.done = true
    end
end
 
function doCreatureSayWithDelay(cid, text, type, delay, e, pcid)
    if Player(pcid):isPlayer() then
        e.done = false
        e.event = addEvent(func, delay < 1 and 1000 or delay, cid, text, type, e, pcid)
    end
end
 
function doPlayerSellItem(cid, itemid, count, cost)
    local player = Player(cid)
    if player:removeItem(itemid, count) then
        if not player:addMoney(cost) then
            error('Could not add money to ' .. player:getName() .. '(' .. cost .. 'gp)')
        end
        return true
    end
    return false
end
 
function doPlayerBuyItemContainer(cid, containerid, itemid, count, cost, charges)
    local player = Player(cid)
    if not player:removeTotalMoney(cost) then
        return false
    end
 
    for i = 1, count do
        local container = Game.createItem(containerid, 1)
        for x = 1, ItemType(containerid):getCapacity() do
            container:addItem(itemid, charges)
        end
 
        if player:addItemEx(container, true) ~= RETURNVALUE_NOERROR then
            return false
        end
    end
    return true
end
 
function getCount(string)
    local b, e = string:find("%d+")
    return b and e and tonumber(string:sub(b, e)) or -1
end
 
function Player.removeTotalMoney(self, amount)
    local moneyCount = self:getMoney()
    local bankCount = self:getBankBalance()
 
    if amount <= moneyCount then
        self:removeMoney(amount)
        return true
 
    elseif amount <= (moneyCount + bankCount) then
        if moneyCount ~= 0 then
            self:removeMoney(moneyCount)
            local remains = amount - moneyCount
            self:setBankBalance(bankCount - remains)
            self:sendTextMessage(MESSAGE_INFO_DESCR, ("Paid %d from inventory and %d gold from bank account. Your account balance is now %d gold."):format(moneyCount, amount - moneyCount, self:getBankBalance()))
            return true
        else
            self:setBankBalance(bankCount - amount)
            self:sendTextMessage(MESSAGE_INFO_DESCR, ("Paid %d gold from bank account. Your account balance is now %d gold."):format(amount, self:getBankBalance()))
            return true
        end
    end
    return false
end
 
function Player.getTotalMoney(self)
    return self:getMoney() + self:getBankBalance()
end
 
function isValidMoney(money)
    return isNumber(money) and money > 0
end
 
function getMoneyCount(string)
    local b, e = string:find("%d+")
    local money = b and e and tonumber(string:sub(b, e)) or -1
    if isValidMoney(money) then
        return money
    end
    return -1
end
 
function getMoneyWeight(money)
    local gold = money
    local crystal = math.floor(gold / 10000)
    gold = gold - crystal * 10000
    local platinum = math.floor(gold / 100)
    gold = gold - platinum * 100
    return (ItemType(ITEM_CRYSTAL_COIN):getWeight() * crystal) + (ItemType(ITEM_PLATINUM_COIN):getWeight() * platinum) + (ItemType(ITEM_GOLD_COIN):getWeight() * gold)
end

here is the updated npc.lua
 
donpcsellitem function (removed all code from isStackable part, since stackable items can't have text on them):
Lua:
function doNpcSellItem(cid, itemid, amount, subType, ignoreCap, inBackpacks, backpack, actionid, text) -- by dwarfer
    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))
            if actionid > 0 then -- by dwarfer
                item:setActionId(actionid)
            end
        else
            stuff = Game.createItem(itemid, math.min(100, amount))
            if actionid > 0 then -- by dwarfer
                stuff:setActionId(actionid)
            end
        end
        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 actionid > 0 then -- by dwarfer
                item:setActionId(actionid)
            end
            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 actionid > 0 then -- by dwarfer
            item:setActionId(actionid)
        end
        if text ~= "" then
            item:setAttribute(ITEM_ATTRIBUTE_TEXT, text)
        end
      
        if Player(cid):addItemEx(item, ignoreCap) ~= RETURNVALUE_NOERROR then
            break
        end
        a = i
    end
    return a, 0
end

I just noticed you edited your addBuyableItemContainer but you need to edit the addBuyableItem:

Lua:
function ShopModule:addBuyableItem(names, itemid, cost, itemSubType, realName, actionid, text)
        if SHOPMODULE_MODE ~= SHOPMODULE_MODE_TALK then
            if itemSubType == nil then
                itemSubType = 1
            end

            local shopItem = self:getShopItem(itemid, itemSubType)
            if shopItem == nil then
                self.npcHandler.shopItems[#self.npcHandler.shopItems + 1] = {id = itemid, buy = cost, sell = -1, subType = itemSubType, name = realName or ItemType(itemid):getName()}
            else
                shopItem.buy = cost
            end
        end

        if names and SHOPMODULE_MODE ~= SHOPMODULE_MODE_TRADE then
            for i, name in pairs(names) do
                local parameters = {
                        itemid = itemid,
                        cost = cost,
                        eventType = SHOPMODULE_BUY_ITEM,
                        module = self,
                        realName = realName or ItemType(itemid):getName(),
                        subType = itemSubType or 1,
                        actionid = actionid,
                        text = text
                    }

                keywords = {}
                keywords[#keywords + 1] = "buy"
                keywords[#keywords + 1] = name
                local node = self.npcHandler.keywordHandler:addKeyword(keywords, ShopModule.tradeItem, parameters)
                node:addChildKeywordNode(self.yesNode)
                node:addChildKeywordNode(self.noNode)
            end
        end

        if npcs_loaded_shop[getNpcCid()] == nil then
            npcs_loaded_shop[getNpcCid()] = getNpcCid()
            self.npcHandler.keywordHandler:addKeyword({'yes'}, ShopModule.onConfirm, {module = self})
            self.npcHandler.keywordHandler:addKeyword({'no'}, ShopModule.onDecline, {module = self})
        end
    end

and the line on npc file:
shopModule:addBuyableItem("Recipe", 26384, 1, 1, "recipe", 50501, "example text")
 
Last edited by a moderator:
That worked but, when i buy the scroll, it has no text in it, comes in blank.
ok, change
text = text or ""
to
text = text

if that doesn't work, on the donpcsellitem function add right after:

Lua:
local item = 0
print(text) -- add this

and buy the item and see what the console prints
 
your way isnt kickingou the action id, so i had to change the lines up to to do that. Back to I cant use the object.
Lua:
 -- Adds a new buyable item.
    --  names = A table containing one or more strings of alternative names to this item. Used only for old buy/sell system.
    --  itemid = The itemid of the buyable item
    --  cost = The price of one single item
    --  subType - The subType of each rune or fluidcontainer item. Can be left out if it is not a rune/fluidcontainer. Default value is 1.
    --  realName - The real, full name for the item. Will be used as ITEMNAME in MESSAGE_ONBUY and MESSAGE_ONSELL if defined. Default value is nil (ItemType(itemId):getName() will be used)
   -- actionid - The actionid of the buyable item (opcional) -- by dwarfer
    function ShopModule:addBuyableItem(names, itemid, cost, itemSubType, realName, actionid, text)
        if SHOPMODULE_MODE ~= SHOPMODULE_MODE_TALK then
            if itemSubType == nil then
                itemSubType = 1
            end

            local shopItem = self:getShopItem(itemid, itemSubType)
            if shopItem == nil then
                self.npcHandler.shopItems[#self.npcHandler.shopItems + 1] = {id = itemid, buy = cost, sell = -1, subType = itemSubType, name = realName or ItemType(itemid):getName(), aid = actionid}
            else
                shopItem.buy = cost
            end
        end

        if names and SHOPMODULE_MODE ~= SHOPMODULE_MODE_TRADE then
            for i, name in pairs(names) do
                local parameters = {
                        itemid = itemid,
                        cost = cost,
                        eventType = SHOPMODULE_BUY_ITEM,
                        module = self,
                        realName = realName or ItemType(itemid):getName(),
                        subType = itemSubType or 1,
                        actionid = actionid,
                        text = text
                    }

                keywords = {}
                keywords[#keywords + 1] = "buy"
                keywords[#keywords + 1] = name
                local node = self.npcHandler.keywordHandler:addKeyword(keywords, ShopModule.tradeItem, parameters)
                node:addChildKeywordNode(self.yesNode)
                node:addChildKeywordNode(self.noNode)
            end
        end

        if npcs_loaded_shop[getNpcCid()] == nil then
            npcs_loaded_shop[getNpcCid()] = getNpcCid()
            self.npcHandler.keywordHandler:addKeyword({'yes'}, ShopModule.onConfirm, {module = self})
            self.npcHandler.keywordHandler:addKeyword({'no'}, ShopModule.onDecline, {module = self})
        end
    end
 
    function ShopModule:getShopItem(itemId, itemSubType)
        if ItemType(itemId):isFluidContainer() then
            for i = 1, #self.npcHandler.shopItems do
                local shopItem = self.npcHandler.shopItems[i]
                if shopItem.id == itemId and shopItem.subType == itemSubType then
                    return shopItem
                end
            end
        else
            for i = 1, #self.npcHandler.shopItems do
                local shopItem = self.npcHandler.shopItems[i]
                if shopItem.id == itemId then
                    return shopItem
                end
            end
        end
        return nil
    end
 
    -- Adds a new buyable container of items.
    --  names = A table containing one or more strings of alternative names to this item.
    --  container = Backpack, bag or any other itemid of container where bought items will be stored
    --  itemid = The itemid of the buyable item
    --  cost = The price of one single item
    --  subType - The subType of each rune or fluidcontainer item. Can be left out if it is not a rune/fluidcontainer. Default value is 1.
    --  realName - The real, full name for the item. Will be used as ITEMNAME in MESSAGE_ONBUY and MESSAGE_ONSELL if defined. Default value is nil (ItemType(itemId):getName() will be used)
    -- actionid - The actionid of the buyable item (opcional) -- by dwarfer
   function ShopModule:addBuyableItemContainer(names, container, itemid, cost, subType, realName, actionid) -- by dwarfer
        if names then
            for i, name in pairs(names) do
                local parameters = {
                        container = container,
                        itemid = itemid,
                        cost = cost,
                        eventType = SHOPMODULE_BUY_ITEM_CONTAINER,
                        module = self,
                        realName = realName or ItemType(itemid):getName(),
                        subType = subType or 1,
                  actionid = actionid, -- by dwarfer
                  text = text
                    }
 
                keywords = {}
                keywords[#keywords + 1] = "buy"
                keywords[#keywords + 1] = name
                local node = self.npcHandler.keywordHandler:addKeyword(keywords, ShopModule.tradeItem, parameters)
                node:addChildKeywordNode(self.yesNode)
                node:addChildKeywordNode(self.noNode)
            end
        end
    end
Post automatically merged:

ok, change
text = text or ""
to
text = text

if that doesn't work, on the donpcsellitem function add right after:

Lua:
local item = 0
print(text) -- add this

and buy the item and see what the console prints


i added that and it's printing out nil
 
Last edited:
Back
Top