• 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+ Server Crashing tfs 1.2

Pifafa

Active Member
Joined
Nov 9, 2010
Messages
100
Reaction score
39
Hello, my server is having a small glitch, I don't understand what it is, but I suspect something related to my vending item, I have a log, I'll post it for you to see.

Bug log

I'm going to post the script that I suspect causes the bug but it works fine so I don't know why?


LUA:
-- rest of config (item prices) is under function, paste there your items list from npc
local config = {
    price_percent = 100, -- how many % of shop price player receive when sell by 'item seller'
    cash_to_bank = false -- send money to bank, not add to player BP
}

local shopItems = {}
local playerClickedItem = {}
local playerCooldown = {} -- Tabela para armazenar o tempo de cooldown por jogador

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if toPosition.x ~= 65535 and getDistanceBetween(player:getPosition(), toPosition) > 1 then
        player:sendTextMessage(MESSAGE_INFO_DESCR, 'This item is too far away.')
        return true
    end

    local targetTile = Tile(toPosition)
    if targetTile then
        local targetHouse = targetTile:getHouse()
        if targetHouse then
            player:sendTextMessage(MESSAGE_INFO_DESCR, 'You cannot sell items in house.')
            return true
        end
    end

    local itemEx = Item(target.uid)
    if not itemEx then
        player:sendTextMessage(MESSAGE_INFO_DESCR, 'This is not an item.')
        return true
    end

    if itemEx:getUniqueId() < 65535 or itemEx:getActionId() > 0 then
        player:sendTextMessage(MESSAGE_INFO_DESCR, 'You cannot sell quest item.')
        return true
    end

    if not shopItems[itemEx.itemid] then
        player:sendTextMessage(MESSAGE_INFO_DESCR, 'This is not sellable item.')
        return true
    end

    -- Verifica o tempo de cooldown do jogador
    if playerCooldown[player:getId()] and os.time() - playerCooldown[player:getId()] < 10 then
        player:sendTextMessage(MESSAGE_INFO_DESCR, 'You must wait a few seconds before selling another item.')
        return true
    end

    local itemCount = 1
    local itemType = ItemType(itemEx.itemid)
    if itemType:isStackable() then
        itemCount = itemEx.type
    end

    local itemName = itemEx:getName()
    local itemValue = math.ceil(shopItems[itemEx.itemid] * itemCount / 100 * config.price_percent)

    -- Verifica se o jogador já clicou no item
    if not playerClickedItem[player:getId()] then
        playerClickedItem[player:getId()] = { itemEx = itemEx, value = itemValue } -- Armazenar o item e o valor
        player:sendTextMessage(MESSAGE_INFO_DESCR, 'You can sell ' .. itemName .. ' for ' .. itemValue .. ' gold coins. Click again to confirm the sale.')
        return true
    end

    -- Verificar se o item é o mesmo da consulta
    if playerClickedItem[player:getId()].itemEx.uid ~= itemEx.uid then
        player:sendTextMessage(MESSAGE_INFO_DESCR, 'You must click on the same item to sell it.')
        playerClickedItem[player:getId()] = nil -- Resetar o estado
        return true
    end

    -- Agora realiza a venda
    if playerClickedItem[player:getId()].value > 0 then
        itemEx:getPosition():sendMagicEffect(CONST_ME_GIFT_WRAPS)
        itemEx:remove()
        local charges = item:getAttribute(ITEM_ATTRIBUTE_CHARGES)
        if charges > 1 then
            item:setAttribute(ITEM_ATTRIBUTE_CHARGES, charges - 1)
        else
            item:remove(1)
        end

        local message = 'You sold ' .. itemCount .. ' ' .. itemName .. ' for ' .. playerClickedItem[player:getId()].value .. ' gold coins.'
        if config.cash_to_bank then
            player:setBankBalance(player:getBankBalance() + playerClickedItem[player:getId()].value)
            message = message .. ' Money was added to your bank account.'
        else
            player:addMoney(playerClickedItem[player:getId()].value)
        end
        player:sendTextMessage(MESSAGE_INFO_DESCR, message)
    else
        player:sendTextMessage(MESSAGE_INFO_DESCR, itemName .. ' is worthless.')
    end

    -- Resetar o estado do jogador após a venda
    playerClickedItem[player:getId()] = nil

    -- Registrar o tempo de cooldown para o jogador
    playerCooldown[player:getId()] = os.time()

    return true
end

local shopModule = {}
function shopModule:addBuyableItemContainer()
end
function shopModule:addBuyableItem()
end
function shopModule:addSellableItem(names, itemid, cost, realName)
    shopItems[itemid] = cost
end

function shopModule:parseList(data)
    for item in string.gmatch(data, "[^;]+") do
        local i = 1
        local itemid = -1
        local cost = 0
        for temp in string.gmatch(item, "[^,]+") do
            if i == 2 then
                itemid = tonumber(temp)
            elseif i == 3 then
                cost = tonumber(temp)
            end
            i = i + 1
        end

        shopItems[itemid] = cost
    end
end

-- here paste list of items from NPC lua file

shopModule:addSellableItem({ 'crystal necklace' }, 3008, 2000, 'crystal necklace')
shopModule:addSellableItem({ 'bronze necklace' }, 3009, 500, 'bronze necklace')
shopModule:addSellableItem({ 'wolf tooth chain' }, 3012, 800, 'wolf tooth chain')
 
Solution
The problem is here:

LUA:
playerClickedItem[player:getId()] = { itemEx = itemEx, value = itemValue } -- Armazenar o item e o valor

You cannot save items anywhere, as when you try to use them again, there is a high probability that the item has already been deleted from memory, resulting in a crash of the engine.

You also cannot track the item with the UniqueID since this ID is temporary

I haven't tried it but it should work fine and secure:
LUA:
-- rest of config (item prices) is under function, paste there your items list from npc
local config = {
    price_percent = 100, -- how many % of shop price player receive when sell by 'item seller'
    cash_to_bank = false -- send money to bank, not add to player BP
}

local shopItems = {}...
The problem is here:

LUA:
playerClickedItem[player:getId()] = { itemEx = itemEx, value = itemValue } -- Armazenar o item e o valor

You cannot save items anywhere, as when you try to use them again, there is a high probability that the item has already been deleted from memory, resulting in a crash of the engine.

You also cannot track the item with the UniqueID since this ID is temporary

I haven't tried it but it should work fine and secure:
LUA:
-- rest of config (item prices) is under function, paste there your items list from npc
local config = {
    price_percent = 100, -- how many % of shop price player receive when sell by 'item seller'
    cash_to_bank = false -- send money to bank, not add to player BP
}

local shopItems = {}
local playerClickedItem = {}
local playerCooldown = {} -- Tabela para armazenar o tempo de cooldown por jogador

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if toPosition.x ~= 65535 and getDistanceBetween(player:getPosition(), toPosition) > 1 then
        player:sendTextMessage(MESSAGE_INFO_DESCR, 'This item is too far away.')
        return true
    end

    local targetTile = Tile(toPosition)
    if targetTile then
        local targetHouse = targetTile:getHouse()
        if targetHouse then
            player:sendTextMessage(MESSAGE_INFO_DESCR, 'You cannot sell items in house.')
            return true
        end
    end

    local itemEx = Item(target.uid)
    if not itemEx then
        player:sendTextMessage(MESSAGE_INFO_DESCR, 'This is not an item.')
        return true
    end

    if itemEx:getUniqueId() < 65535 or itemEx:getActionId() > 0 then
        player:sendTextMessage(MESSAGE_INFO_DESCR, 'You cannot sell quest item.')
        return true
    end

    if not shopItems[itemEx.itemid] then
        player:sendTextMessage(MESSAGE_INFO_DESCR, 'This is not sellable item.')
        return true
    end

    -- Verifica o tempo de cooldown do jogador
    if playerCooldown[player:getId()] and os.time() - playerCooldown[player:getId()] < 10 then
        player:sendTextMessage(MESSAGE_INFO_DESCR, 'You must wait a few seconds before selling another item.')
        return true
    end

    local itemCount = 1
    local itemType = ItemType(itemEx.itemid)
    if itemType:isStackable() then
        itemCount = itemEx.type
    end

    local itemName = itemEx:getName()
    local itemValue = math.ceil(shopItems[itemEx.itemid] * itemCount / 100 * config.price_percent)

    -- Verifica se o jogador já clicou no item
    if not playerClickedItem[player:getId()] then
        playerClickedItem[player:getId()] = { itemid = itemEx.itemid, position = itemEx:getPosition(), value = itemValue } -- Armazenar o itemid, posição e o valor
        player:sendTextMessage(MESSAGE_INFO_DESCR, 'You can sell ' .. itemName .. ' for ' .. itemValue .. ' gold coins. Click again to confirm the sale.')
        return true
    end

    -- Verificar se o item é o mesmo da consulta
    local clickedItem = playerClickedItem[player:getId()]
    local itemExPos = itemEx:getPosition()
    if clickedItem.itemid ~= itemEx.itemid or (itemExPos.x ~= clickedItem.position.x or itemExPos.y ~= clickedItem.position.y or itemExPos.z ~= clickedItem.position.z) then
        player:sendTextMessage(MESSAGE_INFO_DESCR, 'You must click on the same item to sell it.')
        playerClickedItem[player:getId()] = nil -- Resetar o estado
        return true
    end

    -- Agora realiza a venda
    if clickedItem.value > 0 then
        itemEx:getPosition():sendMagicEffect(CONST_ME_GIFT_WRAPS)
        itemEx:remove()
        local charges = item:getAttribute(ITEM_ATTRIBUTE_CHARGES)
        if charges > 1 then
            item:setAttribute(ITEM_ATTRIBUTE_CHARGES, charges - 1)
        else
            item:remove(1)
        end

        local message = 'You sold ' .. itemCount .. ' ' .. itemName .. ' for ' .. clickedItem.value .. ' gold coins.'
        if config.cash_to_bank then
            player:setBankBalance(player:getBankBalance() + clickedItem.value)
            message = message .. ' Money was added to your bank account.'
        else
            player:addMoney(clickedItem.value)
        end
        player:sendTextMessage(MESSAGE_INFO_DESCR, message)
    else
        player:sendTextMessage(MESSAGE_INFO_DESCR, itemName .. ' is worthless.')
    end

    -- Resetar o estado do jogador após a venda
    playerClickedItem[player:getId()] = nil

    -- Registrar o tempo de cooldown para o jogador
    playerCooldown[player:getId()] = os.time()

    return true
end

local shopModule = {}
function shopModule:addBuyableItemContainer()
end
function shopModule:addBuyableItem()
end
function shopModule:addSellableItem(names, itemid, cost, realName)
    shopItems[itemid] = cost
end

function shopModule:parseList(data)
    for item in string.gmatch(data, "[^;]+") do
        local i = 1
        local itemid = -1
        local cost = 0
        for temp in string.gmatch(item, "[^,]+") do
            if i == 2 then
                itemid = tonumber(temp)
            elseif i == 3 then
                cost = tonumber(temp)
            end
            i = i + 1
        end

        shopItems[itemid] = cost
    end
end

-- here paste list of items from NPC lua file

shopModule:addSellableItem({ 'crystal necklace' }, 3008, 2000, 'crystal necklace')
shopModule:addSellableItem({ 'bronze necklace' }, 3009, 500, 'bronze necklace')
shopModule:addSellableItem({ 'wolf tooth chain' }, 3012, 800, 'wolf tooth chain')
 
Last edited:
Solution
Yes, it works well, and the most incredible thing is that it even asks the player to confirm the sale. At first, it shows the value, then it makes the sale. I am perfect. I hope the bug has been resolved. Thank you for helping me!
 
Last edited:

Similar threads

Back
Top