• 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 TFS 1.0 | Reward chest system, some advises?

ATT3

Intermediate OT User
Joined
Sep 22, 2010
Messages
512
Reaction score
100
Well, I am trying to make somewhat the say reward chest system as RL tibia has.
If you don't know how the system works, here's something: http://www.tibia.com/news/?subtopic=newsarchive&id=2486


My script/system doesn't work like that at the moment, though the goal is to make it alike ;I
Just by thinking about it, how would you write it?
e.g like me~ (code below) or would you e.g make a table where certain storage value equals certain boss(base storage) then adding x storage value there would equal to x item.

Well, let's not get ahead of ourselves, I am in the "very beginning".

So far I've create a table like this:
Code:
local bosses = {
    ['rat'] = {bestLoot = {
        [1] = {"ferumbras hat", "hat of the mad", "magic plate armor", "golden armor", "golden helmet"},
        [2] = {"dragon shield", "war hammer", "plate armor", "golden shied", "blue robe"},
        [3] = {"gold coin", "crystal coin", "small emerald", "golden legs", "golden boots"}
    }},
    {goodLoot = {
        oneTimeItem = {"ferumbras hat", "hat of the mad"},
        singleItem = {"dragon shield", "war hammer"},
        multiItem = {"gold coin", "crystal coin", "small emerald"}
    }},
    {worseLoot = {
        oneTimeItem = {"ferumbras hat", "hat of the mad"},
        singleItem = {"dragon shield", "war hammer"},
        multiItem = {"gold coin", "crystal coin", "small emerald"}
    }},
    {worstLoot = {
        oneTimeItem = {"ferumbras hat", "hat of the mad"},
        singleItem = {"dragon shield", "war hammer"},
        multiItem = {"gold coin", "crystal coin", "small emerald"}
    }},
   
    ['another monster'] = {bestLoot = {
        [1] = {"ferumbras hat", "hat of the mad", "magic plate armor", "golden armor", "golden helmet"},
        [2] = {"dragon shield", "war hammer", "plate armor", "golden shied", "blue robe"},
        [3] = {"gold coin", "crystal coin", "small emerald", "golden legs", "golden boots"}
    }},
    {goodLoot = {
        oneTimeItem = {"ferumbras hat", "hat of the mad"},
        singleItem = {"dragon shield", "war hammer"},
        multiItem = {"gold coin", "crystal coin", "small emerald"}
    }},
    {worseLoot = {
        oneTimeItem = {"ferumbras hat", "hat of the mad"},
        singleItem = {"dragon shield", "war hammer"},
        multiItem = {"gold coin", "crystal coin", "small emerald"}
    }},
    {worstLoot = {
        oneTimeItem = {"ferumbras hat", "hat of the mad"},
        singleItem = {"dragon shield", "war hammer"},
        multiItem = {"gold coin", "crystal coin", "small emerald"}
    }},
}

Obviously adding multiple bosses with their "full loots" there the file will become very large.
Would you design this table differently? ("clearer")

Also instead of using item names, should I use their id's instead?
Least in that case the it would place the consonants/vowels there.

Problems:
1. I don't want it to get the same item twice e.g:
dragon shield, dragon shield

2. Add items to the corpse AND to the reward chest (adventurer's guild)
I don't know how to add "all the items" which the player will get to the reward container.
Ok, that would only solve the problem briefly.
Should it be like:
Code:
If reward item == "dragon shield" then
           player:setStorageValue(REWARD_RAT_STROAGE+ITEM_NUMBER_ON_ARRAY.. or table)
end

Current script: http://pastebin.com/Mp2ThEFk

If you understood what I am trying to say: great.
If not, please ask and I will clarify and update this post.
 
tl;dr

isn't there any lua function to get a table of monster loot? so you just use it to get the percentage of the loot and then build the table?
 
id's would probably be better because you can translate those id's into addItem() and makes your script smaller and faster,

I would only use names if I were adding entries into a separate file to use as a reference for other scripts and then converting them to id's which is something anyone can do.
 
tl;dr

isn't there any lua function to get a table of monster loot? so you just use it to get the percentage of the loot and then build the table?
That's exactly what I thought first, but since I found nothing I didn't even think that it was possible (without source modifications).. :confused:
Now when I think about it building something off from XML file could be as easy as it is with PHP.
Dno though, never done it.

Will definitely try to build something, if you know any better I appreciate any help. (how to build it)
Actually there is something better.. but its a secret :)
Come on!
Give us a hint :D
 
tl;dr

isn't there any lua function to get a table of monster loot? so you just use it to get the percentage of the loot and then build the table?

There is.

https://github.com/otland/forgottenserver/wiki/Metatable:MonsterType
MonsterType:getLoot()

It returns the a table containing loot information from the respective monster XML files.
Here are the available fields (from luascript.CPP)

setField(L, "itemId", lootBlock.id);
setField(L, "chance", lootBlock.chance);
setField(L, "subType", lootBlock.subType);
setField(L, "maxCount", lootBlock.countmax);
setField(L, "actionId", lootBlock.actionId);
setField(L, "text", lootBlock.text);

I'm on my phone, can only do so much to help here, will expand in this when I get home later today.
 
Last edited:
Actually there is a better solution.. hmm idk if I should release it tho, I don't mind writing scripts for people or fixing their code even if it doesn't always work 100% but this forum is more of a take than giving community..

The tools I've built would speed up script writing by 1000% for everyone in this community and I'm not just talking out of my ass either lol
 
I agree with @Evan, you can use getLoot. Here is a example how to use it:
Code:
    local monsterName = "Demon"
    local loot = MonsterType(monsterName):getLoot()
    for i = 1, #loot do
        print(i, loot[i].itemId, ItemType(loot[i].itemId):getName())
    end
 
Actually there is a better solution.. hmm idk if I should release it tho, I don't mind writing scripts for people or fixing their code even if it doesn't always work 100% but this forum is more of a take than giving community..

The tools I've built would speed up script writing by 1000% for everyone in this community and I'm not just talking out of my ass either lol

No one needs any of your shit, I and many other people have been giving and providing support to this community for many years. When you removed your tutorials, it was quite obvious what kind of person you are.
 
No one needs any of your shit, I and many other people have been giving and providing support to this community for many years. When you removed your tutorials, it was quite obvious what kind of person you are.
What tutorials?
I never made a tutorial.
You know what @Evan I will release my work, not out of impulse to prove anything but just because i can.
 
Last edited:
I'll give some ideas:

= settings to count the amount of "deserved" loot
- druid
-- amount of healed points using spell/rune (*not potion)
-- amount of damage done (*less than sorc)
- sorcerer
-- amount of damage done
- knight
-- amount of damage taken
-- amount of damage done
- paladin
-- amount of damage done
 
If anyone is interested this is where I got this far:
Code:
local bosses = {
    ["demon"] = {dno = "dno yet.."},
    ["rat"] = {dno = "dno yet.."}
}

function onKill(creature, target)
    local targetMonster = target:getMonster()
    if not targetMonster then
        return true
    end

    local bossConfig = bosses[targetMonster:getName():lower()]
    if not bossConfig then
        return true
    end

    local monsterMaxHealth = targetMonster:getMaxHealth()
 
    for pid, damage in pairs(targetMonster:getDamageMap()) do
        local player = Player(pid)
        if player then
            if damage.total >= ((monsterMaxHealth / 100) * 30) and damage.total < ((monsterMaxHealth / 100) * 50) then
                lootChanceMin = (math.random(2000, 5000)
                lootChanceMax = (math.random(100000)
            elseif damage.total >= ((monsterMaxHealth / 100) * 50) and damage.total < ((monsterMaxHealth / 100) * 70) then
                lootChanceMin = (math.random(2000, 3500)
                lootChanceMax = (math.random(60000, 100000)
            elseif damage.total >= ((monsterMaxHealth / 100) * 70) and damage.total < ((monsterMaxHealth / 100) * 90) then
                lootChanceMin = (math.random(500, 2000, 100000)
                lootChanceMax = (math.random(40000, 100000)
            elseif damage.total >= ((monsterMaxHealth / 100) * 90) then
                lootChanceMin = (math.random(2000)
                lootChanceMax = (math.random(20000, 100000)
            end

            local loot = MonsterType(targetMonster:getName()):getLoot()
            local corpse = MonsterType(targetMonster:getName()):getCorpseId()
            local corpsePos = targetMonster:getPosition()
            local container = Game.createItem(21584, 1, corpsePos)
            for i = 1, #loot do
                if loot.chance >= lootChanceMin and loot.chance <= lootChanceMax then
                    container:addItem(loot.itemId, 1)
                    lootmsg = ItemType(loot[1].itemId):getName()
                    x = 0
                    if #loot >= 2 then
                        while x < 5 do
                            x = x + 1
                            item2 = ItemType(loot[x].itemId):getName()
                            lootmsg = "".. lootmsg ..", ".. item2
                        end
                    end
                end
            end
         
            player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your deeds have been noticed and the following items are available in your reward chest: ".. lootmsg ..".")
        end
    end
end
Much better.
Started lagging so fucking bad that I can't do dipshit, gonna continue tomorrow.

If you got better idea for handling "loot chances" please tell me :)
Anykind of feedback is welcome.
 
What tutorials?
I never made a tutorial.
You know what @Evan I will release my work, not out of impulse to prove anything but just because i can.

Not on Breed, you didn't. On a former alias, you did. We'll just leave it as that and move on.

You don't have to release anything and we're not here to force you either, but it'd be nice of you though.
However, if you come here and say "there is a better way, but I won't tell", then you're not contributing and you're just being an ass.
This is the Support board, people are here to ask for help, whether they're trying to be spoonfed or not.
 
Lagging from what?
My internet was lagging alot, kept getting kicks.
Had to share with somebody :D

-------------------
Slowly getting forward.
Code:
local messages = {
    'The reward chest will dissappear in 50 seconds. Afterwards you can loot the monster by opening your reward chest at the adventurer\'s guild.',
    'The reward chest will dissappear in 10 seconds. Afterwards you can loot the monster by opening your reward chest at the adventurer\'s guild.'
}

local function sendTextMessages(cid, text, position)
    local player = Player(cid)
    if not player then
        return true
    end

    player:sendTextMessage(MESSAGE_EVENT_ADVANCE, text)
end


local bosses = {
    ["demon"] = {dno = "dno yet.."},
    ["rat"] = {dno = "dno yet.."},
}

local function removeBossChest(pos, itemid)
    local chest = Tile(pos):getItemById(itemid)
    if not chest then
        return true
    end
  
    pos:sendMagicEffect(CONST_ME_POFF)
    chest:remove()
end

function onKill(creature, target)
    local targetMonster = target:getMonster()
    if not targetMonster then
        return true
    end

    local bossConfig = bosses[targetMonster:getName():lower()]
    if not bossConfig then
        return true
    end
  
    local monsterMaxHealth = targetMonster:getMaxHealth()
  
    for pid, damage in pairs(targetMonster:getDamageMap()) do
        local player = Player(pid)
        if player then
             if damage.total >= ((monsterMaxHealth / 100) * 30) and damage.total < ((monsterMaxHealth / 100) * 50) then
                lootChanceMin = math.random(4500)
                lootChanceMax = math.random(80000)
            elseif damage.total >= ((monsterMaxHealth / 100) * 50) and damage.total < ((monsterMaxHealth / 100) * 70) then
                lootChanceMin = math.random(3000)
                lootChanceMax = math.random(70000)
            elseif damage.total >= ((monsterMaxHealth / 100) * 70) and damage.total < ((monsterMaxHealth / 100) * 90) then
                lootChanceMin = math.random(1500)
                lootChanceMax = math.random(60000)
            elseif damage.total >= ((monsterMaxHealth / 100) * 90) then
                lootChanceMin = math.random(100)
                lootChanceMax = math.random(50000)
            end

            local loot = MonsterType(targetMonster:getName()):getLoot()
            local corpsePos = targetMonster:getPosition()
            local container = Game.createItem(21584, 1, corpsePos)
            local count = loot.maxCount
            print(#loot)
            for i = 1, #loot do
                local lootChance = loot[i].chance >= lootChanceMin and loot[i].chance <= lootChanceMax
                if lootChance then
                    container:addItem(loot[i].itemId, math.random(loot[i].maxCount) or 1)
                    local luck = math.random(#loot)
                    local x = 1
                    lootmsg = ItemType(loot[1].itemId):getName()
                    if #loot >= 2 then
                        while x < luck do
                            x = x + 1
                            print(i)
                            item1 = ItemType(loot[x].itemId):getName()
                            lootmsg = lootmsg ..", ".. item1
                        end
                    end
                end
            end
                  

            addEvent(removeBossChest, 60000, corpsePos, 21584)
            targetMonster:setDropLoot(false)
            player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your deeds have been noticed and the following items are available in your reward chest: ".. lootmsg ..".")
          
            for i = 1, #messages do
                addEvent(sendTextMessages, 30000, player.uid, messages[i], player:getPosition())
            end
        end
    end
end

Right now, I've got an issue that I have been trying to solve, but no success ;o

How can I make "container loot"(loot it adds inside the container) same as "lootmsg" is? (at the moment both are "different random")
 
I remember updating code for someone last week I think where they had a quest script which used a bag and of course items, you just have to use the search box on this forum or google.
I know your looking for a solution and maybe this response isn't your solution but its a general statement to help you in the future.
When I am looking for help with a script I usually use google with the search phrase of whatever my problem is
Code:
addEvent tfs 1.0 otland
Which would bring up a ton of forum posts from people with the same issues, so I hope this has been helpful although it doesn't exactly solve your current issue, but with a little research it will. :)
 
Let's pump it then.

Current problems
  • Loot chance, not sure what would be the best way to do it, but does anyone else have better idea?
  • Include player summon damages too
  • Without any source edits, is it possible to set corpses attiribute to depot? e.g setAttribute:depot?

Code:
local bosses = {
    ["Ferumbras"] = {oneTimeItem = "5903"}, -- ferumbra's hat
    ["Chizzoron the Distorter"] = {oneTimeItem = "nothing"},
    ["Furyosa"] = {oneTimeItem = "nothing"},
    ["gaz'haragoth"] = {oneTimeItem = "nothing"},
    ["Jaul"] = {oneTimeItem = "nothing"},
    ["Mad Mage"] = {oneTimeItem = "nothing"},
    ["Mawhawk"] = {oneTimeItem = "nothing"},
    ["morgaroth"] = {oneTimeItem = "nothing"},
    ["Obujos"] = {oneTimeItem = "nothing"},
    ["Omrafir"] = {oneTimeItem = "nothing"},
    ["orshabaal"] = {oneTimeItem = "nothing"},
    ["raging mage"] = {oneTimeItem = "nothing"},
    ["tanjis"] = {oneTimeItem = "nothing"},
    ["the mutated pumpkin"] = {oneTimeItem = "nothing"},
    ["the page count"] = {oneTimeItem = "nothing"},
    ["the welter"] = {oneTimeItem = "nothing"},
    ["zulazza the corruptor"] = {oneTimeItem = "nothing"},
    ["zushuka"] = {oneTimeItem = "nothing"},
    ["rat"] = {oneTimeItem = "nothing"}
}

function onKill(creature, target)

    local targetMonster = target:getMonster()
    if not targetMonster then
        return true
    end

    local bossConfig = bosses[targetMonster:getName():lower()]
    if not bossConfig then
        return true
    end
   
    local monsterMaxHealth = targetMonster:getMaxHealth()
   
    local LuckyPlayer = creature:getPlayer()
    if bossConfig.oneTimeItem ~= "nothing" then
        LuckyPlayer:getInbox():addItem(bossConfig.oneTimeItem, 1, true, 1)
        lootmsg = ItemType(bossConfig.oneTimeItem):getName()
    else
        lootmsg = ""
    end
   
    for pid, damage in pairs(targetMonster:getDamageMap()) do
        local player = Player(pid) 
        if player then
            local killChance = damage.total/monsterMaxHealth
            lootChanceMin = killChance*100000
            local loot = MonsterType(targetMonster:getName()):getLoot()
            local corpsePos = targetMonster:getPosition()
            local corpseId = MonsterType(targetMonster:getName()):getCorpseId()
            corpse = Game.createItem(corpseId, 1, corpsePos)
            local lootsBp = corpse:addItem(1988, 1)
            local count = loot.maxCount
           
            for i = 1, #loot do
                itemChance = math.random(lootChanceMin)
                local lootChance = itemChance <= loot[i].chance
                if lootChance then
                    local inbox = player:getInbox()
                    local lootcount  = math.random(loot[i].maxCount) or 1
                    local lootekBp = lootsBp:addItem(loot[i].itemId, lootcount)
                    lootekBp:moveTo(inbox)
                    local x = 1
                    if #loot >= 2 then
                        item1 = ItemType(loot[i].itemId):getName()
                        article = ItemType(loot[i].itemId):getName()
                        if lootcount == 1 then
                           lootmsg = lootmsg ..", ".. ItemType(loot[i].itemId):getArticle() .." ".. item1
                        else
                            lootmsg = lootmsg ..", ".. lootcount .. " " .. item1 .."s"
                        end
                    end
                end
            end
            targetMonster:setDropLoot(false)
            if lootmsg then
                player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your deeds have been noticed and the following items are available in your reward chest: ".. lootmsg ..".")
            end
        end
    end
    corpse:setAttribute("aid", 61240)
    corpse:decay()
end
 
@ATT3
The corpse itself is not the depot, if Orshabaal dies he will have a reward container in his corpse which contains your items (this container should be the depot).
Creating that depot is currently not possible in TFS 1.1, I might look into it soon as it looks really interesting.
 
Back
Top