• 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.3] Reward based on vocation

krafttomten

Well-Known Member
Joined
Jul 23, 2017
Messages
103
Solutions
1
Reaction score
75
Location
Sweden
Hello,

I have been stuck on this problem for too long now. I give up! Time to admit defeat and beg the gods of OTland for help.

Currently, the code I have gives the player the content of the chest as reward. But sometimes I want to give different rewards for different vocations. I have found similar threads on the subject, but the solutions I have found all rely on adding the item ID:s straight into the code, which basically means that I would need one script file for each quest. No good. I want standardized code for all quests, so much easier in the long run.

I'm thinking that this code only needs a small fix really, but I can't get my head around the LUA syntax to formulate the task properly.

Lua:
function onUse(cid, item, fromPosition, target, toPosition, isHotkey)
    local chest = Container(item.uid) --
    local player = Player(cid)
    if not chest or not player then
      return true
    end

    local uniqueid = chest:getUniqueId()
    if player:getStorageValue(uniqueid) == -2 then
      player:sendTextMessage(MESSAGE_INFO_DESCR, "It is empty.")
      return true
    end

    local start = player:getStorageValue(uniqueid) == -1 and 0 or player:getStorageValue(uniqueid)
    for i = start, chest:getSize() do
      local reward = chest:getItem(i) -- Here, instead of adding the chest content to the reward variable,
      if not reward then              -- I want it to add the first item in the chest to vocation 1,
        break                         -- the second item to vocation 2, etc...
      end

      local rewardWeight = reward.getWeight and reward:getWeight() or ItemType(reward:getId()):getWeight(reward:getCount())
      if rewardWeight > player:getFreeCapacity() then
        player:sendTextMessage(MESSAGE_INFO_DESCR, 'You have found a ' .. reward:getName() .. ' weighing ' .. rewardWeight/100 .. ' oz it\'s too heavy.')
        player:setStorageValue(uniqueid, i)
        break
      else
        reward = reward:clone()
        if player:addItemEx(reward) ~= RETURNVALUE_NOERROR then
          player:sendTextMessage(MESSAGE_INFO_DESCR, 'You have found a ' .. reward:getName() .. ' weighing ' .. rewardWeight/100 .. ' oz it\'s too heavy.')
          break
        end

        local reward_msg = reward:getArticle() .. ' ' .. reward:getName()
        if reward:getCount() > 1 then
          reward_msg = reward:getCount() .. ' ' .. reward:getPluralName()
        end

        player:sendTextMessage(MESSAGE_INFO_DESCR, 'You have found ' .. reward_msg .. '.')

        player:setStorageValue(uniqueid, -2)
      end
    end

    return true
end

I've been trying to combine container:getItem(index) with player:getVocation() and match them up that way but I don't get it to work.
Lua:
item:getItem(player:getVocation())

If I get this to work then all l I would have to do to make a new quest would be to make a chest in RME, give it an actionid that runs this code and add the reward items inside the chest (in the correct order).

Any help would be appriciated!
Post automatically merged:

Posting progress so far.

Lua:
function onUse(cid, item, fromPosition, target, toPosition, isHotkey)
    local chest = Container(item.uid)
    local player = Player(cid)
   


    local aids = { -- I'm trying to assign each number to one vocation (by index) here
        [1] = 13001, --
        [2] = 13002, --
        [3] = 13003, --
        [4] = 13004 --
    }




    if not chest or not player then
      return true
    end

    local uniqueid = chest:getUniqueId()
    if player:getStorageValue(uniqueid) == -2 then
      player:sendTextMessage(MESSAGE_INFO_DESCR, "It is empty.")
      return true
    end
   
    local start = player:getStorageValue(uniqueid) == -1 and 0 or player:getStorageValue(uniqueid)
    for i = start, chest:getSize() do
    if item.aid == aids.getPlayerVocation(cid) or item.aid == aids:getPlayerVocation(cid - 4)  then -- This is where it breaks. I cannot
        local reward = chest:getItem(i)             -- call aids.getPlayerVocation(cid) because it is a Nil value. I'm trying to match it with
      if not reward then              -- the corresponding aid above (aids)
        break
      end

      local rewardWeight = reward.getWeight and reward:getWeight() or ItemType(reward:getId()):getWeight(reward:getCount())
      if rewardWeight > player:getFreeCapacity() then
        player:sendTextMessage(MESSAGE_INFO_DESCR, 'You have found a ' .. reward:getName() .. ' weighing ' .. rewardWeight/100 .. ' oz it\'s too heavy.')
        player:setStorageValue(uniqueid, i)
        break
      else
        reward = reward:clone()
        if player:addItemEx(reward) ~= RETURNVALUE_NOERROR then
          player:sendTextMessage(MESSAGE_INFO_DESCR, 'You have found a ' .. reward:getName() .. ' weighing ' .. rewardWeight/100 .. ' oz it\'s too heavy.')
          break
        end

        local reward_msg = reward:getArticle() .. ' ' .. reward:getName()
        if reward:getCount() > 1 then
          reward_msg = reward:getCount() .. ' ' .. reward:getPluralName()
        end

        player:sendTextMessage(MESSAGE_INFO_DESCR, 'You have found ' .. reward_msg .. '.')

        player:setStorageValue(uniqueid, -2)
      end
    end
    end

    return true
end

I'm trying a list of action ID's now. That way I can add many items to each vocation and it won't matter what order I place them inside the map editor
 
Last edited:
Solution
data/scripts/rewardchests.lua
Lua:
local action = Action()

function action.onUse(player, item, fromPos, target, toPos, isHotkey)
    if not item:getType():isContainer() then
        return true
    end

    local uniqueId = item:getUniqueId()
    if player:getStorageValue(uniqueId) ~= -1 then
        player:sendTextMessage(MESSAGE_INFO_DESCR, "It is empty.")
        return true
    end

    local vocation = player:getVocation():getBase()
    local get = item:getItem(vocation:getId() -1)
    if get then
        local weight = get:getWeight()
        if player:getFreeCapacity() < weight then
            player:sendTextMessage(MESSAGE_INFO_DESCR, string.format("You need %.2f weight.", weight / 100))
            return true...
data/scripts/rewardchests.lua
Lua:
local action = Action()

function action.onUse(player, item, fromPos, target, toPos, isHotkey)
    if not item:getType():isContainer() then
        return true
    end

    local uniqueId = item:getUniqueId()
    if player:getStorageValue(uniqueId) ~= -1 then
        player:sendTextMessage(MESSAGE_INFO_DESCR, "It is empty.")
        return true
    end

    local vocation = player:getVocation():getBase()
    local get = item:getItem(vocation:getId() -1)
    if get then
        local weight = get:getWeight()
        if player:getFreeCapacity() < weight then
            player:sendTextMessage(MESSAGE_INFO_DESCR, string.format("You need %.2f weight.", weight / 100))
            return true
        end
        local reward = get:clone()
        if player:addItemEx(reward) == RETURNVALUE_NOERROR then
            player:setStorageValue(uniqueId, 1)
            if reward:getType():isContainer() then
                player:sendTextMessage(MESSAGE_INFO_DESCR, "You found: " .. reward:getContentDescription())
            else
                player:sendTextMessage(MESSAGE_INFO_DESCR, string.format("You found: %d %s.", reward:getCount(), reward:getName()))
            end
        else
            reward:remove()
            player:sendCancelMessage(RETURNVALUE_NOTENOUGHCAPACITY)
        end
    end
    return true
end

action:aid(7776)
action:register()

then the reward is listed as follows:
  • Sorcerer
  • Druid
  • Paladin
  • Knight
  • Custom Voc "Example"
1618875911718.png
 
Last edited:
Solution
data/scripts/rewardchests.lua
Lua:
local action = Action()

function action.onUse(player, item, fromPos, target, toPos, isHotkey)
    if not item:getType():isContainer() then
        return true
    end

    local uniqueId = item:getUniqueId()
    if player:getStorageValue(uniqueId) ~= -1 then
        player:sendTextMessage(MESSAGE_INFO_DESCR, "It is empty.")
        return true
    end

    local vocation = player:getVocation():getBase()
    local get = item:getItem(vocation:getId() -1)
    if get then
        local weight = get:getWeight()
        if player:getFreeCapacity() < weight then
            player:sendTextMessage(MESSAGE_INFO_DESCR, string.format("You need %.2f weight.", weight / 100))
            return true
        end
        local reward = get:clone()
        if player:addItemEx(reward) == RETURNVALUE_NOERROR then
            player:setStorageValue(uniqueId, 1)
            if reward:getType():isContainer() then
                player:sendTextMessage(MESSAGE_INFO_DESCR, "You found: " .. reward:getContentDescription())
            else
                player:sendTextMessage(MESSAGE_INFO_DESCR, string.format("You found: %d %s.", reward:getCount(), reward:getName()))
            end
        end
    end
    return true
end

action:aid(7776)
action:register()

then the reward is listed as follows:
  • Sorcerer
  • Druid
  • Paladin
  • Knight
  • Custom Voc "Example"
View attachment 57837
i get this error
/data/scripts/chestforvocation.lua:4: 'then' expected near 'isContainer'
 
data/scripts/rewardchests.lua
Lua:
local action = Action()

function action.onUse(player, item, fromPos, target, toPos, isHotkey)
    if not item:getType():isContainer() then
        return true
    end

    local uniqueId = item:getUniqueId()
    if player:getStorageValue(uniqueId) ~= -1 then
        player:sendTextMessage(MESSAGE_INFO_DESCR, "It is empty.")
        return true
    end

    local vocation = player:getVocation():getBase()
    local get = item:getItem(vocation:getId() -1)
    if get then
        local weight = get:getWeight()
        if player:getFreeCapacity() < weight then
            player:sendTextMessage(MESSAGE_INFO_DESCR, string.format("You need %.2f weight.", weight / 100))
            return true
        end
        local reward = get:clone()
        if player:addItemEx(reward) == RETURNVALUE_NOERROR then
            player:setStorageValue(uniqueId, 1)
            if reward:getType():isContainer() then
                player:sendTextMessage(MESSAGE_INFO_DESCR, "You found: " .. reward:getContentDescription())
            else
                player:sendTextMessage(MESSAGE_INFO_DESCR, string.format("You found: %d %s.", reward:getCount(), reward:getName()))
            end
        end
    end
    return true
end

action:aid(7776)
action:register()

then the reward is listed as follows:
  • Sorcerer
  • Druid
  • Paladin
  • Knight
  • Custom Voc "Example"
View attachment 57837
is a daily prize possible? with this script?

Make it every 24 hours and that this gives you 1 item like 2145, 10

and tell you how much time you need to request it again

I'm looking but couldn't find one that works
 
Sure, you could assign two player storage values to hold the date and time.

So the code above will give anything inside the chest as the reward. To give this reward many times you could use:
Lua:
local config = {
        storage = item.uid,
        exstorage = item.uid + 1
        }

if player:getStorageValue(config.storage) == tonumber(os.date("%w")) and player:getStorageValue(config.exstorage) > os.time() then
        return player:sendTextMessage(MESSAGE_INFO_DESCR, "The chest is empty, come back tomorrow for a new reward.")
    end
to check the player storages,

and you could use:
Lua:
player:setStorageValue(config.storage, tonumber(os.date("%w")))
player:setStorageValue(config.exstorage, os.time() + 24 * 60 * 60)
to set the storages.

You want to set the storage value at the moment that you give the player the reward and you want to check the storage value as early as possible in the script, to avoid unnecessary calculations.

In the script above, you can see that those code pieces are already there, so just replace the old with the new...
Lua:
local action = Action()

function action.onUse(player, item, fromPos, target, toPos, isHotkey)
    if not item:getType():isContainer() then
        return true
    end
 
    local config = {
        storage = item.uid,
        exstorage = item.uid + 1
        }

 
if player:getStorageValue(config.storage) == tonumber(os.date("%w")) and player:getStorageValue(config.exstorage) > os.time() then
        return player:sendTextMessage(MESSAGE_INFO_DESCR, "The chest is empty, come back tomorrow for a new reward.")
    end

    local vocation = player:getVocation():getBase()
    local get = item:getItem(vocation:getId() -1)
    if get then
        local weight = get:getWeight()
        if player:getFreeCapacity() < weight then
            player:sendTextMessage(MESSAGE_INFO_DESCR, string.format("You need %.2f weight.", weight / 100))
            return true
        end
        local reward = get:clone()
        if player:addItemEx(reward) == RETURNVALUE_NOERROR then
            player:setStorageValue(config.storage, tonumber(os.date("%w")))
            player:setStorageValue(config.exstorage, os.time() + 24 * 60 * 60)
            if reward:getType():isContainer() then
                player:sendTextMessage(MESSAGE_INFO_DESCR, "You found: " .. reward:getContentDescription())
            else
                player:sendTextMessage(MESSAGE_INFO_DESCR, string.format("You found: %d %s.", reward:getCount(), reward:getName()))
            end
        end
    end
    return true
end

action:aid(7776)
action:register()

Something like that. It should work. Just make sure that the storage values that you use are not already being used for something else.
 
Last edited:
Sure, you could assign two player storage values to hold the date and time.

So the code above will give anything inside the chest as the reward. To give this reward many times you could use:
Lua:
local config = {
        storage = item.uid,
        exstorage = item.uid + 1
        }

if player:getStorageValue(config.storage) == tonumber(os.date("%w")) and player:getStorageValue(config.exstorage) > os.time() then
        return player:sendTextMessage(MESSAGE_INFO_DESCR, "The chest is empty, come back tomorrow for a new reward.")
    end
to check the player storages,

and you could use:
Lua:
player:setStorageValue(config.storage, tonumber(os.date("%w")))
player:setStorageValue(config.exstorage, os.time() + 24 * 60 * 60)
to set the storages.

You want to set the storage value at the moment that you give the player the reward and you want to check the storage value as early as possible in the script, to avoid unnecessary calculations.

In the script above, you can see that those code pieces are already there, so just replace the old with the new...
Lua:
local action = Action()

function action.onUse(player, item, fromPos, target, toPos, isHotkey)
    if not item:getType():isContainer() then
        return true
    end
 
    local config = {
        storage = item.uid,
        exstorage = item.uid + 1
        }

 
if player:getStorageValue(config.storage) == tonumber(os.date("%w")) and player:getStorageValue(config.exstorage) > os.time() then
        return player:sendTextMessage(MESSAGE_INFO_DESCR, "The chest is empty, come back tomorrow for a new reward.")
    end

    local vocation = player:getVocation():getBase()
    local get = item:getItem(vocation:getId() -1)
    if get then
        local weight = get:getWeight()
        if player:getFreeCapacity() < weight then
            player:sendTextMessage(MESSAGE_INFO_DESCR, string.format("You need %.2f weight.", weight / 100))
            return true
        end
        local reward = get:clone()
        if player:addItemEx(reward) == RETURNVALUE_NOERROR then
            player:setStorageValue(config.storage, tonumber(os.date("%w")))
            player:setStorageValue(config.exstorage, os.time() + 24 * 60 * 60)
            if reward:getType():isContainer() then
                player:sendTextMessage(MESSAGE_INFO_DESCR, "You found: " .. reward:getContentDescription())
            else
                player:sendTextMessage(MESSAGE_INFO_DESCR, string.format("You found: %d %s.", reward:getCount(), reward:getName()))
            end
        end
    end
    return true
end

action:aid(7776)
action:register()

Something like that. It should work. Just make sure that the storage values that you use are not already being used for something else.
sorry does this work as a revscript? or action? and where do I define the object to be used? Sorry, I don't understand. I come from the 760 xml version and thank you in advance for your help friend <3
 
sorry does this work as a revscript? or action? and where do I define the object to be used? Sorry, I don't understand. I come from the 760 xml version and thank you in advance for your help friend <3
Oh, I thought you had it working already xD

Ehh, hah I actually don't know. I thought I used it like this but apparantly I changed it on my server.

You can use this code instead,
Lua:
function onUse(player, item, fromPos, target, toPos, isHotkey)
    if not item:getType():isContainer() then
        return true
    end
    local config = {
        storage = item.uid,
        exstorage = item.uid + 1
        }
    if player:getStorageValue(config.storage) == tonumber(os.date("%w")) and player:getStorageValue(config.exstorage) > os.time() then
        return player:sendTextMessage(MESSAGE_INFO_DESCR, "The chest is empty, come back tomorrow for a new reward.")
    end

    local vocation = player:getVocation():getBase()
    local get = item:getItem(vocation:getId() -1)
    if get then
        local weight = get:getWeight()
        if player:getFreeCapacity() < weight then
            player:sendTextMessage(MESSAGE_INFO_DESCR, string.format("You need %.2f weight.", weight / 100))
            return true
        end
        local reward = get:clone()
        if player:addItemEx(reward) == RETURNVALUE_NOERROR then
            player:setStorageValue(config.storage, tonumber(os.date("%w")))
            player:setStorageValue(config.exstorage, os.time() + 24 * 60 * 60)
            if reward:getType():isContainer() then
                player:sendTextMessage(MESSAGE_INFO_DESCR, "You found: " .. reward:getContentDescription())
            else
                player:sendTextMessage(MESSAGE_INFO_DESCR, string.format("You found: %d %s.", reward:getCount(), reward:getName()))
            end
        end
    end
    return true
end

and just assign it to any vacant action id in your actions.xml

XML:
<action actionid="7776" script="quests/vocreward.lua" />

I think that should work, right? I haven't used the 760 version in ages
 
Last edited:
Oh, I thought you had it working already xD

Ehh, hah I actually don't know. I thought I used it like this but apparantly I changed it on my server.

You can use this code instead,
Lua:
function onUse(player, item, fromPos, target, toPos, isHotkey)
    if not item:getType():isContainer() then
        return true
    end
    local config = {
        storage = item.uid,
        exstorage = item.uid + 1
        }
    if player:getStorageValue(config.storage) == tonumber(os.date("%w")) and player:getStorageValue(config.exstorage) > os.time() then
        return player:sendTextMessage(MESSAGE_INFO_DESCR, "The chest is empty, come back tomorrow for a new reward.")
    end

    local vocation = player:getVocation():getBase()
    local get = item:getItem(vocation:getId() -1)
    if get then
        local weight = get:getWeight()
        if player:getFreeCapacity() < weight then
            player:sendTextMessage(MESSAGE_INFO_DESCR, string.format("You need %.2f weight.", weight / 100))
            return true
        end
        local reward = get:clone()
        if player:addItemEx(reward) == RETURNVALUE_NOERROR then
            player:setStorageValue(config.storage, tonumber(os.date("%w")))
            player:setStorageValue(config.exstorage, os.time() + 24 * 60 * 60)
            if reward:getType():isContainer() then
                player:sendTextMessage(MESSAGE_INFO_DESCR, "You found: " .. reward:getContentDescription())
            else
                player:sendTextMessage(MESSAGE_INFO_DESCR, string.format("You found: %d %s.", reward:getCount(), reward:getName()))
            end
        end
    end
    return true
end

and just assign it to any vacant action id in your actions.xml

XML:
<action actionid="7776" script="quests/vocreward.lua" />
I am testing but I have a question where I define which item is the one that the chest will give daily?
 
I'm not sure if I understand..

You give an item the actionID 7776 and some uniqueID (let's say 73486) in RME, then you add that line in actions.xml, then you create the lua file which is being referred to in the XML (in my example named and located as "quests/vocreward.lua"), that's all there is to it

You can have as many different chests as you like running this code as long as the chest has the action ID 7776. They could even give out different rewards on the same timer, depending on the contents of the chest, if they use the same unique ID
 
data/scripts/rewardchests.lua
Lua:
local action = Action()

function action.onUse(player, item, fromPos, target, toPos, isHotkey)
    if not item:getType():isContainer() then
        return true
    end

    local uniqueId = item:getUniqueId()
    if player:getStorageValue(uniqueId) ~= -1 then
        player:sendTextMessage(MESSAGE_INFO_DESCR, "It is empty.")
        return true
    end

    local vocation = player:getVocation():getBase()
    local get = item:getItem(vocation:getId() -1)
    if get then
        local weight = get:getWeight()
        if player:getFreeCapacity() < weight then
            player:sendTextMessage(MESSAGE_INFO_DESCR, string.format("You need %.2f weight.", weight / 100))
            return true
        end
        local reward = get:clone()
        if player:addItemEx(reward) == RETURNVALUE_NOERROR then
            player:setStorageValue(uniqueId, 1)
            if reward:getType():isContainer() then
                player:sendTextMessage(MESSAGE_INFO_DESCR, "You found: " .. reward:getContentDescription())
            else
                player:sendTextMessage(MESSAGE_INFO_DESCR, string.format("You found: %d %s.", reward:getCount(), reward:getName()))
            end
        else
            reward:remove()
            player:sendCancelMessage(RETURNVALUE_NOTENOUGHCAPACITY)
        end
    end
    return true
end

action:aid(7776)
action:register()

then the reward is listed as follows:
  • Sorcerer
  • Druid
  • Paladin
  • Knight
  • Custom Voc "Example"
you can pick up the chest to backpack and also move it on the ground , what do i need to do for the chest to be static
 
you can pick up the chest to backpack and also move it on the ground , what do i need to do for the chest to be static
I have always solved this by adding a uid (unique id) to the container. (using TFS 1.X). But maybe that is not possible for you? This code already assumes that you use an uid for the player storage, so you might have to do something else, depending on your version..


Personally to solve these kinds of issues I usually just search through all files in theforgottenserver/data with a IDE like notepad++ or VS Code. It's usually possible to patch existing code together to solve problems. Like, is there any other codes in your game that makes items unmovable? Except for those items that are always unmovable obviously. About that, you can always just use an unmovable container as a last resort.
 
Last edited:
Back
Top