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

[Revscripts] TradeTimes System for TFS 1.4

farp

Member
Joined
Nov 18, 2022
Messages
20
Reaction score
8
I Tried to put this Sarah Wesker's [TFS 1.5] ❤ TradeTimes System ❤ into my TFS 1.4

the item shows the trade times it still have left or if there is no longer trades left on the item
but when there is no trades left, it was supposed to not let the player trade it or throw in the ground, but this part doesn't work.


there is no console errors as well so I have no idea what is missing.

Can Anyone help to find is missing to make this system work on TFS 1.4? or can point on how should I adapt it?

Here's the code:
Lua:
local tradeStoneId = 8302
local maxTradeTimes = 3
local tradeKey = "TradeTimes"
local effect = CONST_ME_FIREWORK_BLUE

-- Warning:
-- This prints a warning to the console if the execution order is not correct.
-- If the warning is triggered, it means that there is a possibility that an item with TradeTimes will fall to the ground.
-- If you are sure that the order is correct, you can disable this to make your script faster.
local checkDropLootOrder = true

-- If an item with TradeTimes is found on the corpse, should we remove it?
local removeDropedItem = true

-- If an item with TradeTimes is found on the corpse, should we reduce the times?
-- If removeDropedItem is false and this variable is true, then the item will be removed if it has no more times.
local reduceDropedItem = false

local function isSentToPlayer(player, toCylinder)
    if not toCylinder then
        return RETURNVALUE_NOTPOSSIBLE
    end
    if toCylinder:isTile() then
        return RETURNVALUE_NOTPOSSIBLE
    end
    if toCylinder == player or toCylinder:getTopParent() == player then
        return RETURNVALUE_NOERROR
    end
    return RETURNVALUE_NOTPOSSIBLE
end

local ec = EventCallback

function ec.onMoveItem(player, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
    local toTile = Tile(toPosition)
    if toTile and toTile:hasFlag(TILESTATE_TRASHHOLDER) then
        return RETURNVALUE_NOERROR
    elseif item:getCustomAttribute(tradeKey) then
        return isSentToPlayer(player, toCylinder)
    elseif item:getType():isContainer() then
        for _, item in pairs(item:getItems(true)) do
            if item:getCustomAttribute(tradeKey) then
                return isSentToPlayer(player, toCylinder)
            end
        end
    end
    return RETURNVALUE_NOERROR
end

ec:register(-1)

function ec.onTradeRequest(player, target, item)
    local itemTT = item:getCustomAttribute(tradeKey)
    if itemTT and itemTT < 1 then
        player:sendCancelMessage("You can't trade this item anymore.")
        return false
    end

    if item:getType():isContainer() then
        for _, it in pairs(item:getItems(true)) do
            local itTT = it:getCustomAttribute(tradeKey)
            if itTT and itTT < 1 then
                player:sendCancelMessage("You can't trade this item anymore.")
                return false
            end
        end
    end
    return true
end

ec:register(-1)

function ec.onTradeCompleted(player, target, item, targetItem, isSuccess)
    if not isSuccess then
        return
    end

    local itemTT = item:getCustomAttribute(tradeKey)
    if itemTT then
        item:setCustomAttribute(tradeKey, itemTT - 1)
    end

    if item:getType():isContainer() then
        for _, it in pairs(item:getItems(true)) do
            local itTT = it:getCustomAttribute(tradeKey)
            if itTT then
                it:setCustomAttribute(tradeKey, itTT - 1)
            end
        end
    end

    local targetItemTT = targetItem:getCustomAttribute(tradeKey)
    if targetItemTT then
        targetItem:setCustomAttribute(tradeKey, targetItemTT - 1)
    end

    if targetItem:getType():isContainer() then
        for _, it in pairs(targetItem:getItems(true)) do
            local itTT = it:getCustomAttribute(tradeKey)
            if itTT then
                it:setCustomAttribute(tradeKey, itTT - 1)
            end
        end
    end
end

ec:register(-1)

local function onLook(item, description)
    local tradeTimes = item:getCustomAttribute(tradeKey)
    if not tradeTimes then
        return description
    end
    if tradeTimes > 0 then
        return string.format("%s\nIt can be traded %d more times.", description, tradeTimes)
    end
    return string.format("%s\nIt can no longer be traded.", description)
end

function ec.onLook(player, thing, position, distance, description)
    if not thing:isItem() then
        return description
    end
    return onLook(thing, description)
end

ec:register(1)

function ec.onLookInTrade(player, partner, item, distance, description)
    return onLook(item, description)
end

ec:register(1)

local action = Action()

function action.onUse(player, item, fromPos, target, toPos, isHotkey)
    if not target or not target:isItem() then
        player:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
        return true
    end

    local tradeTimes = target:getCustomAttribute(tradeKey)
    if not tradeTimes then
        player:sendCancelMessage("This item not support trade times.")
        return true
    end

    if tradeTimes >= maxTradeTimes then
        player:sendCancelMessage("This item already has the maximum trade times.")
        return true
    end

    tradeTimes = tradeTimes + 1
    target:setCustomAttribute(tradeKey, tradeTimes)
    item:remove(1)
    player:getPosition():sendMagicEffect(effect)
    return true
end

action:id(tradeStoneId)
action:register()

local death = CreatureEvent("TradeTimesDeath")

function death.onDeath(player, corpse, lastHitKiller, mostDamageKiller, lastHitUnjustified, mostDamageUnjustified)
    if checkDropLootOrder then
        local foundDropLoot = false
        for _, eventName in pairs(player:getEvents(CREATURE_EVENT_DEATH)) do
            if eventName == "DropLoot" then
                foundDropLoot = true
            elseif eventName == "TradeTimesDeath" and not foundDropLoot then
                print("[TradeTimesDeath - Warning] must be after DropLoot.")
            end
        end
    end

    for _, item in pairs(corpse:getItems(true)) do
        local tradeTimes = item:getCustomAttribute(tradeKey)
        if tradeTimes then
            if removeDropedItem then
                item:remove()
            elseif reduceDropedItem then
                if tradeTimes > 1 then
                    item:setCustomAttribute(tradeKey, tradeTimes - 1)
                else
                    item:remove()
                end
            end
        end
    end
    return true
end

death:register()

local login = CreatureEvent("TradeTimesLogin")

function login.onLogin(player)
    player:registerEvent("TradeTimesDeath")
    return true
end

login:register()
 
Solution
I will assume that you're using an old version of 1.4, So change this part.
Lua:
local function isSentToPlayer(player, toCylinder)
    if not toCylinder then
        return RETURNVALUE_NOTPOSSIBLE
    end
    if toCylinder:isTile() then
        return RETURNVALUE_NOTPOSSIBLE
    end
    if toCylinder == player or toCylinder:getTopParent() == player then
        return RETURNVALUE_NOERROR
    end
    return RETURNVALUE_NOTPOSSIBLE
end

local ec = EventCallback

function ec.onMoveItem(player, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
    local toTile = Tile(toPosition)
    if toTile and toTile:hasFlag(TILESTATE_TRASHHOLDER) then
        return RETURNVALUE_NOERROR
    elseif item:getCustomAttribute(tradeKey) then...
In 1.4 for some reason, negative register numbers don't work.
So changing this ec:register(-1) to this ec:register(1) would solve your issue.
 
In 1.4 for some reason, negative register numbers don't work.
So changing this ec:register(-1) to this ec:register(1) would solve your issue.
Just tried those changes, ec:register(-1) to ec:register(1), still not working, also tried changing to ec:register()

Same thing...no console errors, but letting me trade and drop on the floor items that have 0 trading times.

I Think its better to not post on Sarah's topic for now, since its not for support, after a solution is found for sure then it should be good to post there and share with others
 
I just tested on a fresh 1.4 from here.
TestTrade.gif
Try changing ec:register(1) to a higher number something like ec:register(777). Just giving a random solution because it already works in 1.4 for me.
I Think its better to not post on Sarah's topic for now, since its not for support, after a solution is found for sure then it should be good to post there and share with others
Sure, I posted it there to help others who're using 1.4
 
Last edited:
I just tested on a fresh 1.4 from here.
View attachment 72453
Try changing ec:register(1) to a higher number something like ec:register(777). Just giving a random solution because it already works in 1.4 for me.

Sure, I posted it there to help others who're using 1.4
lol, then i Have no idea why it wouldn't work on mine, Im using tfs 1.4 with some modifications


but im pretty sure i didn't change any of those functions used on the script

Tried changing the register (1) to random numbers, didn't work as well
 
I will assume that you're using an old version of 1.4, So change this part.
Lua:
local function isSentToPlayer(player, toCylinder)
    if not toCylinder then
        return RETURNVALUE_NOTPOSSIBLE
    end
    if toCylinder:isTile() then
        return RETURNVALUE_NOTPOSSIBLE
    end
    if toCylinder == player or toCylinder:getTopParent() == player then
        return RETURNVALUE_NOERROR
    end
    return RETURNVALUE_NOTPOSSIBLE
end

local ec = EventCallback

function ec.onMoveItem(player, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
    local toTile = Tile(toPosition)
    if toTile and toTile:hasFlag(TILESTATE_TRASHHOLDER) then
        return RETURNVALUE_NOERROR
    elseif item:getCustomAttribute(tradeKey) then
        return isSentToPlayer(player, toCylinder)
    elseif item:getType():isContainer() then
        for _, item in pairs(item:getItems(true)) do
            if item:getCustomAttribute(tradeKey) then
                return isSentToPlayer(player, toCylinder)
            end
        end
    end
    return RETURNVALUE_NOERROR
end

ec:register(-1)

function ec.onTradeRequest(player, target, item)
    local itemTT = item:getCustomAttribute(tradeKey)
    if itemTT and itemTT < 1 then
        player:sendCancelMessage("You can't trade this item anymore.")
        return false
    end

    if item:getType():isContainer() then
        for _, it in pairs(item:getItems(true)) do
            local itTT = it:getCustomAttribute(tradeKey)
            if itTT and itTT < 1 then
                player:sendCancelMessage("You can't trade this item anymore.")
                return false
            end
        end
    end
    return true
end

ec:register(-1)
To this.
Lua:
local function isSentToPlayer(player, toCylinder)
    if not toCylinder then
        return false
    end
    if toCylinder:isTile() then
        return false
    end
    if toCylinder == player or toCylinder:getTopParent() == player then
        return true
    end
    return false
end

local ec = EventCallback

function ec.onMoveItem(player, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
    local toTile = Tile(toPosition)
    if toTile and toTile:hasFlag(TILESTATE_TRASHHOLDER) then
        return true
    elseif item:getCustomAttribute(tradeKey) then
        return isSentToPlayer(player, toCylinder)
    elseif item:getType():isContainer() then
        for _, item in pairs(item:getItems(true)) do
            if item:getCustomAttribute(tradeKey) then
                return isSentToPlayer(player, toCylinder)
            end
        end
    end
    return true
end

ec:register(1)

function ec.onTradeRequest(player, target, item)
    local itemTT = item:getCustomAttribute(tradeKey)
    if itemTT and itemTT < 1 then
        player:sendCancelMessage("You can't trade this item anymore.")
        return false
    end

    if item:getType():isContainer() then
        for _, it in pairs(item:getItems(true)) do
            local itTT = it:getCustomAttribute(tradeKey)
            if itTT and itTT < 1 then
                player:sendCancelMessage("You can't trade this item anymore.")
                return false
            end
        end
    end
    return true
end

ec:register(1)
 
Solution
I will assume that you're using an old version of 1.4, So change this part.
Lua:
local function isSentToPlayer(player, toCylinder)
    if not toCylinder then
        return RETURNVALUE_NOTPOSSIBLE
    end
    if toCylinder:isTile() then
        return RETURNVALUE_NOTPOSSIBLE
    end
    if toCylinder == player or toCylinder:getTopParent() == player then
        return RETURNVALUE_NOERROR
    end
    return RETURNVALUE_NOTPOSSIBLE
end

local ec = EventCallback

function ec.onMoveItem(player, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
    local toTile = Tile(toPosition)
    if toTile and toTile:hasFlag(TILESTATE_TRASHHOLDER) then
        return RETURNVALUE_NOERROR
    elseif item:getCustomAttribute(tradeKey) then
        return isSentToPlayer(player, toCylinder)
    elseif item:getType():isContainer() then
        for _, item in pairs(item:getItems(true)) do
            if item:getCustomAttribute(tradeKey) then
                return isSentToPlayer(player, toCylinder)
            end
        end
    end
    return RETURNVALUE_NOERROR
end

ec:register(-1)

function ec.onTradeRequest(player, target, item)
    local itemTT = item:getCustomAttribute(tradeKey)
    if itemTT and itemTT < 1 then
        player:sendCancelMessage("You can't trade this item anymore.")
        return false
    end

    if item:getType():isContainer() then
        for _, it in pairs(item:getItems(true)) do
            local itTT = it:getCustomAttribute(tradeKey)
            if itTT and itTT < 1 then
                player:sendCancelMessage("You can't trade this item anymore.")
                return false
            end
        end
    end
    return true
end

ec:register(-1)
To this.
Lua:
local function isSentToPlayer(player, toCylinder)
    if not toCylinder then
        return false
    end
    if toCylinder:isTile() then
        return false
    end
    if toCylinder == player or toCylinder:getTopParent() == player then
        return true
    end
    return false
end

local ec = EventCallback

function ec.onMoveItem(player, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
    local toTile = Tile(toPosition)
    if toTile and toTile:hasFlag(TILESTATE_TRASHHOLDER) then
        return true
    elseif item:getCustomAttribute(tradeKey) then
        return isSentToPlayer(player, toCylinder)
    elseif item:getType():isContainer() then
        for _, item in pairs(item:getItems(true)) do
            if item:getCustomAttribute(tradeKey) then
                return isSentToPlayer(player, toCylinder)
            end
        end
    end
    return true
end

ec:register(1)

function ec.onTradeRequest(player, target, item)
    local itemTT = item:getCustomAttribute(tradeKey)
    if itemTT and itemTT < 1 then
        player:sendCancelMessage("You can't trade this item anymore.")
        return false
    end

    if item:getType():isContainer() then
        for _, it in pairs(item:getItems(true)) do
            local itTT = it:getCustomAttribute(tradeKey)
            if itTT and itTT < 1 then
                player:sendCancelMessage("You can't trade this item anymore.")
                return false
            end
        end
    end
    return true
end

ec:register(1)
Yes the TFS 1.4 im using I Downloaded on Feb, I checked the github and there is some fix related to functions/events (moveItem onItemMoved) used on this script, maybe that's it...

I will try to apply those changes


Edit: Yes the problem was those "RETURNVALUE_NOTPOSSIBLE" and "RETURNVALUE_NOERROR"

Now its working, thanks
 
Last edited:
Back
Top