• 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!
  • New resources must be posted under Resources tab. A discussion thread will be created automatically, you can't open threads manually anymore.

[TFS 1.X] Rarity Rolls & Custom Attributes Library

I can't seem to get onInventoryUpdate to work correctly, I have tried numerous times... and compiled my heart out...I am burned out trying

Is there another way to get items to update correctly instead of log off/log on?
 
Hi, Im using nekitro 1.5 tfs tbia 7.7 downgrade and i have this kind of problem. Anyone can help?
LUA:
Lua Script Error: [CreatureScript Interface]
data/creaturescripts/scripts/attributes.lua:onHealthChange
data/lib/core/item.lua:505: attempt to compare nil with number
stack traceback:
        [C]: in function '__le'
        data/lib/core/item.lua:505: in function 'getDescription'
        data/creaturescripts/scripts/attributes.lua:249: in function 'statChange'
        data/creaturescripts/scripts/attributes.lua:533: in function <data/creaturescripts/scripts/attributes.lua:530>

Lua Script Error: [CreatureScript Interface]
data/creaturescripts/scripts/attributes.lua:onHealthChange
data/lib/core/item.lua:505: attempt to compare nil with number
stack traceback:
        [C]: in function '__le'
        data/lib/core/item.lua:505: in function 'getDescription'
        data/creaturescripts/scripts/attributes.lua:249: in function 'statChange'
        data/creaturescripts/scripts/attributes.lua:533: in function <data/creaturescripts/scripts/attributes.lua:530>

bump anyone can help?
 
Hi, Im using nekitro 1.5 tfs tbia 7.7 downgrade and i have this kind of problem. Anyone can help?
LUA:
Lua Script Error: [CreatureScript Interface]
data/creaturescripts/scripts/attributes.lua:onHealthChange
data/lib/core/item.lua:505: attempt to compare nil with number
stack traceback:
        [C]: in function '__le'
        data/lib/core/item.lua:505: in function 'getDescription'
        data/creaturescripts/scripts/attributes.lua:249: in function 'statChange'
        data/creaturescripts/scripts/attributes.lua:533: in function <data/creaturescripts/scripts/attributes.lua:530>

Lua Script Error: [CreatureScript Interface]
data/creaturescripts/scripts/attributes.lua:onHealthChange
data/lib/core/item.lua:505: attempt to compare nil with number
stack traceback:
        [C]: in function '__le'
        data/lib/core/item.lua:505: in function 'getDescription'
        data/creaturescripts/scripts/attributes.lua:249: in function 'statChange'
        data/creaturescripts/scripts/attributes.lua:533: in function <data/creaturescripts/scripts/attributes.lua:530>

Did you copy statchange modifications to player.lua/wherever it is required?
 
Well this is bizarre

I finally got onInventoryUpdate to work, hurray!

I do however, do not ever get any rare item drops, or anything.. no console errors.. /roll function works properly .. but hmm...
 
< 10.94
The first post is for versions earlier than 10.94, before crit and mana/life leech was added to the game.
Someone should try it on an 8.6 server ;)

10.94+
If you are using the latest TFS release, refer to the post here.

What is this?
A newer version of this:
A variant of this, this and this mod.
It gives items a chance to roll rare, epic or legendary when it drops from a monster:

iSCVyA6.png


With the following possible attributes:
(For config and if you want to understand the code, start at the stats table in lib/core/attributes.lua)
LUA:
[1] = { -- Attack
[2] = { -- Defense
[3] = { -- Extra Defense
[4] = { -- Armor
[5] = { -- Accuracy
[6] = { -- Range
[7] = { -- Equipment with < 50 charges
[8] = { -- Equipment with >= 50 charges
[9] = { -- Time
[10] = { -- Crit Chance
[11] = { -- Crit Amount (Currently Unused)
[12] = { -- Fire Damage
[13] = { -- Ice Damage
[14] = { -- Energy Damage
[15] = { -- Fire Resistance
[16] = { -- Ice Resistance
[17] = { -- Energy Resistance
[18] = { -- Earth Resistance
[19] = { -- Physical Resistance
[20] = { -- Death Resistance
[21] = { -- Spell Damage
[22] = { -- Multi Shot
[23] = { -- Stun Chance
[24] = { -- Mana Shield
[25] = { -- Sword Skill
[26] = { -- Skill Axe
[27] = { -- Skill Club
[28] = { -- Skill Melee
[29] = { -- Skill Distance
[30] = { -- Skill Shielding
[31] = { -- Magic Level
[32] = { -- Max Health i.e +100
[33] = { -- Max Mana i.e +100
[34] = { -- Max Health % i.e +10%
[35] = { -- Max Mana % i.e +10%
[36] = { -- Life Leech Chance (Currently Unused)
[37] = { -- Life Leech Amount
[38] = { -- Mana Leech Chance (Currently Unused)
[39] = { -- Mana Leech Amount


Cw1kJDN.png


Some of these are completely custom attributes, like elemental damage:

56C8xHU.gif


This requires the following updates/features:

1) Loot drop handled via Lua
2) Add the new health/mana gain coloured text messages
3) onInventoryUpdate()
4) onSpawn()


Installation:
📁 rollAttributes.zip
paste in /data

lib/core/core.lua
add below:
LUA:
-- Rolls & Custom Item Attributes
dofile('data/lib/core/attributes.lua')

talkactions.xml
add below:
XML:
<talkaction words="/roll" separator=" " script="roll.lua" />

creaturescripts.xml
add below:
XML:
<!-- Roll & Attribute Damage -->
<event type="healthchange" name="rollHealth" script="attributes.lua"/>
<event type="manachange" name="rollMana" script="attributes.lua"/>

creaturescripts/scripts/login.lua
add below:
LUA:
-- Activate Custom Item Attributes
for i = 1,10 do -- CONST_SLOT_FIRST,CONST_SLOT_LAST
    local item = player:getSlotItem(i)
    if item then
        itemAttributes(player, item, i, true)
    end
end
-- If player logged with more 'current health' than their db 'max health' due to an item attribute
local query = db.storeQuery("SELECT `health`,`mana` FROM players where `id`="..player:getGuid())
if query then
    local health = tonumber(result.getDataString(query, 'health'))
    local mana = tonumber(result.getDataString(query, 'mana'))
    local playerHealth = player:getHealth()
    local playerMana = player:getMana()
    if playerHealth < health then
        player:addHealth(health - playerHealth)
    end
    if playerMana < mana then
        player:addMana(mana - playerMana)
    end
    result.free(query)
end

add below:
LUA:
player:registerEvent("rollHealth")
player:registerEvent("rollMana")

events/scripts/player.lua
add to the bottom:
LUA:
function Player:onInventoryUpdate(item, slot, equip)
    itemAttributes(self, item, slot, equip)
end

events/scripts/monster.lua
add to the top of the file:
LUA:
-- Rarity Animations
local rare_popup = true
local rare_effect = true
local rare_effect_id = CONST_ME_STUN
add between:
LUA:
-- Apply rarity chance to corpse contents and apply animation
if rollRarity(corpse) > 0 then -- If a rare item was rolled, play animation
        if rare_popup then
            local spectators = Game.getSpectators(corpse:getPosition(), false, true, 7, 7, 5, 5)
            for i = 1, #spectators do
                spectators[i]:say(rare_text, TALKTYPE_MONSTER_SAY, false, spectators[i], corpse:getPosition())
            end
        end
    if rare_effect then
        corpse:getPosition():sendMagicEffect(rare_effect_id)
    end
end
add at the end:
LUA:
function Monster:onSpawn(position, startup, artificial)
    self:registerEvent("rollHealth")
    self:registerEvent("rollMana")
   return true
end


The core scripts are attached because they are to big to embed in post, so they're attached as rollAttributes.zip
Don't forget to paste the core scripts into your /data dir.

Extras
  • 'Stun Target' is disabled by default, add the condition from here and uncomment the lines in creaturescripts/scripts/attributes.lua
  • primaryDamage and primaryType are swapped with secondaryDamage and secondaryType on elemental damage (better, consistent visuals)
  • Use the included /roll <rarity> talkaction for testing i.e /roll legendary
  • Mana Leech and Life Leech apply 5ms after damage is done, this may feel different to vanilla Tibia.
  • Multi shot ignores creature armor/shielding - its quite primitive.
  • If you want to re-roll an item you should item:remove() it and re-create it (so it has stock base stats).
  • Custom resistances apply after natural resistances and are additive.
  • A unique weapon & shield using this systems on-hit mechanics can be found in extras.xml
    Overwrite their information in items.xml and uncomment their code in attributes.lua for cool points.
does it work for a tfs 1.2 8.0?
 
Got it to slightly work! But I now have to relog to update changes. Please help!

Using tfs 1.5 772
 
Got it to slightly work! But I now have to relog to update changes. Please help!

Using tfs 1.5 772
finally got it to work! Now it seems i got the same problem as people above also have.

Lua Script Error: [CreatureScript Interface]
data/creaturescripts/scripts/attributes.lua:onHealthChange
data/creaturescripts/scripts/attributes.lua:418: attempt to call global 'doTargetCombatCondition' (a nil value)
stack traceback:
[C]: in function 'doTargetCombatCondition'
data/creaturescripts/scripts/attributes.lua:418: in function 'statChange'
data/creaturescripts/scripts/attributes.lua:685: in function <data/creaturescripts/scripts/attributes.lua:682>

tfs 1.5 772 downgrade
 
How can i edit crit amount?
seems that crit amount when crit chance is rolled goes by default to 100%.
any idea?


Thanks
 
Last edited:
I'm having this problem when equipping the item and its attributes are not showing correctly. I'll post some pictures for better understanding. if anyone can help me thanks.

I just installed that part to my server.

Prints:

mace atributos.png

equiped 1.png


 
Im using Sabrehaven 8.0 sources (based on tfs 1.2)
but im experiencing some difficulties, is it possible to adapt it?

i have this error.
1684682021664.png
 
this is from the onInventoryUpdate function:

it looks like TFS code has changed in a way that now conflicts
I'd say my code is now out-of-date and isn't just plug and play anymore, it could be used as a base but requires changes to work properly.
I don't really bother with OTs anymore so it would be up to someone else to clean up this codebase and resolve the conflicts.

sorry bruz
 
this is from the onInventoryUpdate function:

it looks like TFS code has changed in a way that now conflicts
I'd say my code is now out-of-date and isn't just plug and play anymore, it could be used as a base but requires changes to work properly.
I don't really bother with OTs anymore so it would be up to someone else to clean up this codebase and resolve the conflicts.

sorry bruz
appreciate your comment, the sources are kind old and also modified, i hope someone is interested in adapt the current script, i only know very basics of c++ i think i could not achieve that alone u.u
 
I'd say my code is now out-of-date
Its the other way around, his source code is old

Im using Sabrehaven 8.0 sources (based on tfs 1.2)
but im experiencing some difficulties, is it possible to adapt it?

Okay, the error tells you that info is not declared
Thats because on recent versions, the events are stored inside a struct while on your sources is not

So the solution would be to remove the struct access <info.> on the code, on here:


 
Pretty nice system! I want to implement the roll on chests using this code: [TFS 1.3] Advanced quest chests (https://otland.net/threads/tfs-1-3-advanced-quest-chests.277772/) is is posible?
LUA:
function capAll(str)
    return (str:gsub("(%l)(%w*)", function(a,b) return string.upper(a)..b end))
end

local advanceChest = Action()

function advanceChest.onUse(player, item, fromPosition, itemEx, toPosition)
   -----------------------------------------------------------------------------------
   -- Local Variables --
   -----------------------------------------------------------------------------------
   local questChest = item:getUniqueId()
   -----------------------------------------------------------------------------------
   -- Check if player has already opened box --
   -----------------------------------------------------------------------------------
   if player:getStorageValue(questChest) == 1 then
       player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The chest is empty.")
       toPosition:sendMagicEffect(10)
       return true
   end
 
   local storageOne = questChests[questChest].storageUnique
   -----------------------------------------------------------------------------------
   -- Check if player has already opened box multiple chest only 1 reward --
   -----------------------------------------------------------------------------------
   if player:getStorageValue(storageOne) == 1 then
       player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The chest is empty.")
       toPosition:sendMagicEffect(10)
       return true
   end
 
   -----------------------------------------------------------------------------------
   -- Check if player meets level requirment
   -----------------------------------------------------------------------------------
   local playerLevel = player:getLevel()
   local minLevel = questChests[questChest].minLevel
   if questChests[questChest].minLevel => playerLevel then
       player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You need to be level "..minLevel.." to open this chest.")
       return true
   end
   -----------------------------------------------------------------------------------
 
   -- Give rewward if player has not yet opened box --
 
   -----------------------------------------------------------------------------------
   for i = 1, #questChests[questChest].items do
       local rewardType = questChests[questChest].items[i].type
       -----------------------------------------------------------------------------------
       -- Item Type Reward --
       -----------------------------------------------------------------------------------
       if rewardType == "item" then
           local item = questChests[questChest].items[i].item
           local count = questChests[questChest].items[i].count
           player:addItem(item, count)
           player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "You earned ["..count.."x] "..capAll(getItemName(item)))
       end
       -----------------------------------------------------------------------------------
       -- Experience Type Reward --
       -----------------------------------------------------------------------------------
       if rewardType == "experience" then
           local amount = questChests[questChest].items[i].amount
           player:addExperience(amount)
           player:say(amount.." EXP gained!", TALKTYPE_MONSTER_SAY)
           player:getPosition():sendMagicEffect(CONST_ME_STUN)
           player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "You gained "..amount.." experience points.")
       end
       -----------------------------------------------------------------------------------
       -- Outfit Type Reward --
       -----------------------------------------------------------------------------------
       if rewardType == "outfit" then
           local outfitName = questChests[questChest].items[i].name
           local maleOutfit = questChests[questChest].items[i].maleId
           local femaleOutfit = questChests[questChest].items[i].femaleId
           if player:getSex() == 0 then
               player:addOutfit(femaleOutfit)
           else
               player:addOutfit(maleOutfit)
           end
           player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "You gained the "..outfitName.." outfit.")
       end
       -----------------------------------------------------------------------------------
       -- Addon Type Reward --
       -----------------------------------------------------------------------------------
       if rewardType == "addon" then
           local outfitName = questChests[questChest].items[i].outfit
           local addon = questChests[questChest].items[i].addonNumber
           local maleAddon = questChests[questChest].items[i].maleId
           local femaleAddon = questChests[questChest].items[i].femaleId
           if player:getSex() == 0 then
               player:addOutfitAddon(femaleAddon, addon)
           else
               player:addOutfitAddon(maleAddon, addon)
           end
           if addon == 1 then
               player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "You gained the first "..outfitName.." outfit addon.")
           elseif addon == 2 then
               player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "You gained the second "..outfitName.." outfit addon.")
           elseif addon == 3 then
               player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "You gained the third "..outfitName.." outfit addon.")
           end
       end
       -----------------------------------------------------------------------------------
       -- Mount Type Reward --
       -----------------------------------------------------------------------------------
       if rewardType == "mount" then
           local mountName = questChests[questChest].items[i].mountName
           local mountId = questChests[questChest].items[i].mountId
           player:addMount(mountId)
           player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "You have unlocked the "..mountName.." mount.")
       end

           
 
 
   -----------------------------------------------------------------------------------
   -- Add in any cooldowns/storages --
   -----------------------------------------------------------------------------------
   player:setStorageValue(questChest, 1)
   player:setStorageValue(storageOne, 1)
   return true
end
end

for i = 2000, 2100 do
    advanceChest:uid(i)
end

advanceChest:register()

Thanks in advance!

I know this is super late reply but..
In the code below rarity roll is implemented aswel as items in bag and also key's.

LUA:
    local containerID = ChestUid.containerID
    local bag = nil
    local text = nil
    local textTwo = ""
    local addItem = 0

    -----------------------------------------------------------------------------------
    for index, details in pairs(ChestUid.items) do
        local itemCheck = ItemType(details.item)
        local rollText = ""
        -----------------------------------------------------------------------------------
        -- Item Type Reward --
        -----------------------------------------------------------------------------------
        if details.type == "item" then

            -- Add items inside a container if container == 1
            if details.container == 1 then
                if not bag then
                    bag = player:addItem(containerID, 1)
                end

                addItem = bag:addItem(details.item,details.count)
            else
                addItem = player:addItem(details.item, details.count)
            end

            -- Add key with Action ID if Key and actionId is defined in table "Key = true/false, actionID = "
            if details.key == true then
                addItem:setActionId(details.actionID)
            end

            if addItem ~= nil and not itemCheck:isStackable() then
                if details.item then
                    local randomRoll = math.random(0,100)
                    if randomRoll <= INSERT CHANCE then
                        randomRoll = "rare"
                    elseif randomRoll <= INSERT CHANCE then
                        randomRoll = "epic"
                    elseif randomRoll <= INSERT CHANCE then
                        randomRoll = "legendary"
                    else
                        randomRoll = ""
                    end
                    rollRarity(addItem,randomRoll)
                    rollText = ""..addItem:getArticle().." "
                end

            end

            if details.count > 1 then
                text = ""..details.count.." "
                textTwo = "s"
            else
                text = ""
                textTwo = ""
            end

            player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "You found "..text..""..rollText..""..getItemName(details.item)..""..textTwo..".")
 
After a long time adjusting a lot of things I got it working 100% with critical system, mana leech and life leech on TFS 1.1 on nostalrius base server 7.4.
 

Attachments

  • rarity_system.PNG
    rarity_system.PNG
    182.6 KB · Views: 21 · VirusTotal
Back
Top