• 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] Rarity Rolls & Custom Attributes Library

Leo32

Getting back into it...
Premium User
Joined
Sep 21, 2007
Messages
918
Best answers
13
Reaction score
329
< 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:



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



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



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.
 

Attachments

Last edited:

Evil Puncker

Unlucky
Premium User
Joined
May 30, 2009
Messages
6,295
Best answers
55
Reaction score
2,091
cool!!! awesome!!! I can't wait to try the 10.98 version
 
OP
Leo32

Leo32

Getting back into it...
Premium User
Joined
Sep 21, 2007
Messages
918
Best answers
13
Reaction score
329
Here are the 10.94+ files for the latest version of TFS.
It uses the native Crit and Leech system.

Here is a branch you can simply merge:
Comparison can be found here.


Alternatively, follow the instructions below if you want to install it manually:

You need these commits/changes:
1) Leech fix (If you don't have 👇 your leech amounts will be all messed up)
2) onInventoryUpdate()
3) onSpawn()

Installation:

📁
rollAttributes10.98.zip
paste into /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
 

Attachments

Last edited:

zxmatzx

Well-Known Member
Joined
Dec 1, 2010
Messages
232
Best answers
20
Reaction score
89
Amazing work Leo32! Definitly i will look deep your system! I saw your post showing the system, very happy that you released the system to community! Thanks for share and keep going!
 
OP
Leo32

Leo32

Getting back into it...
Premium User
Joined
Sep 21, 2007
Messages
918
Best answers
13
Reaction score
329
Bonus Feature:
Jewel Case drops



events/scripts/monster.lua
after:
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:
Lua:
-- Custom special item drops
local jewelCorpse = {
    [5995] = { -- Demon
        2493, -- Demon Helmet
        2494, -- Demon Armor
        2495, -- Demon Legs
        2400, -- Magic Sword
        2431, -- SCA
        2421, -- Thunder Hammer
        16112,-- Spellbook of Arcana
        8852, -- The Devileye
        8905,  -- Rainbow Shield
        2131  -- Star Amulet
    },
    [5999] = { -- Behemoth
        2503,  -- Dwarven Armor
        2504,  -- Dwarven Legs
        2502   -- Dwarven Helmet
    },
    [6332] = { -- Hellhound
        15406, -- Ornate Chest
        15414, -- Ornate Mace
        15412, -- Ornate Legs
        15644, -- Ornate Crossbow
        15407, -- Depth Lorica
        8905,  -- Rainbow Shield
        22424, -- Master Umbral Spellbook
        12644, -- Shield of Corruption
        12649, -- Blade of Corruption
        7390,  -- Justice Seeker
        7435   -- Impaler
    },
    [8955] = { -- Grim Reaper
        9778,  -- Yalahari Mask
        9776,  -- Yalahari Armor
        7429,  -- Blessed Sceptre
        14327, -- Bronze Ring
        12645  -- Elite Draken Helmet
    },
    [5984] = { -- Dragon Lord
        11118, -- Dragon Scale Boots
        2506,  -- Dragon Scale Helmet
        8886,  -- Molten Plate
    },
    [19963] = {-- Lost Basher
        2503,  -- Dwarven Armor
        2504,  -- Dwarven Legs
        2502,  -- Dwarven Helmet
    },
    [19998] = {-- Lost Thrower
        2503,  -- Dwarven Armor
        2504,  -- Dwarven Legs
        2502,  -- Dwarven Helmet
    },
    [17408] = {-- Enslaved Dwarf
        2503,  -- Dwarven Armor
        2504,  -- Dwarven Legs
        2502,  -- Dwarven Helmet
    },
    [17416] = {-- Lost Berserker
        2503,  -- Dwarven Armor
        2504,  -- Dwarven Legs
        2502,  -- Dwarven Helmet
    },
    [6320] = { -- Destroyer
        2503,  -- Dwarven Armor
        2504,  -- Dwarven Legs
        2502,  -- Dwarven Helmet
        7455,  -- Mythril Axe
        7390,  -- Justice Seeker
        8888   -- MAA
    },
    [6324] = { -- Hellfire Fighter
        18409, -- Wand of Everblazing
        8925,  -- Solar Axe
        7417,  -- Runed Sword
        8927,  -- Dark Trinity Mace
        8905,  -- Rainbow Shield
        12647, -- Snakegod's Wristguard
        8881   -- Fireborn
    },
    [6336] = { -- Juggernaut
        2522,  -- Great Shield
        21693, -- Horn
        8882,  -- Earthborn
        8930,  -- Emerald Sword
        8929,  -- Stomper
        8932,  -- The Calamity
        7405,  -- Havoc
        2415   -- Great Axe
    },
    [10524] = { -- Medusa
        8869,   -- Greenwood Coat
        2537,   -- Amazon Shield
        5803    -- Arbalest
    },
    [8951] = { -- Bog Raider
        21706, -- Goo Shell
        23528  -- Glooth Cape
    },
    [6532] = { -- Defiler
        21706  -- Goo Shell
    },
    [6061] = { -- Serpent Spawn
        12642, -- Royal Draken Mail
        12643, -- Royal Scale Robe
        8851   -- Royal Crossbow
    },
    [6012] = { -- Elf Scout
        2505   -- Elven Mail
    },
    [6011] = { -- Elf Arcanist
        2505   -- Elven Mail
    },
    [6028] = { -- Lich
        7429,  -- Blessed Sceptre
        7730   -- Blue Legs

    },
    [15354] = { -- Kollos
        8883,   -- Windborn
        16111,  -- Thorn Spitter
        15413   -- Ornate Shield
    },
    [15296] = { -- Spidris
        11374,  -- Beetle Necklace
        16111   -- Thorn Spitter
    },
    [20455] = { -- Necromancer
        6433,   -- Necromancer Shield
        7429    -- Blessed Sceptre
    },
    [9923] = { -- Hellspawn
        12607, -- Elite Draken Mail
        7390,  -- Justice Seeker
        21693, -- Horn
        7433   -- Ravenwing
    },
    [6328] = { -- Dark Torturer
        12607, -- Elite Draken Mail
        12644, -- Shield of Corruption
        12649, -- Blade of Corruption
        8924,  -- Hellforged Axe
        8927,  -- Dark Trinity Mace
        21693, -- Horn
        7453,  -- Executioner
        6391,  -- Nightmare Shield
        2415   -- Great Axe
    },
    [6048] = { -- Hydra
        2424,  -- Silver Mace
        14327, -- Bronze Ring
        11305, -- Drakinata
        7411,  -- Ornamented Axe
        7384,  -- Mystic Blade
        2508   -- Native Armor
    },
    [20527] = { -- Warlock
        2542,   -- Tempest Shield
        7410,   -- Queen's Sceptre
        2662    -- Magician Hat
    },
    [20415] = { -- Hero
        8885,   -- Divine Plate
        11302,  -- Zaoan Helmet
        7384,   -- Mystic Blade
        2424,   -- Silver Mace
        14327,  -- Bronze Ring
        2508    -- Native Armor
    }
}
if jewelCorpse[corpse:getId()] then
    if math.random(1,50) == 1 then -- 1/50 = 2%
        local jewelCase = corpse:addItem(6104, 1)
        if jewelCase then
            local jewelItem = jewelCase:addItem(jewelCorpse[corpse:getId()][math.random(1,#jewelCorpse[corpse:getId()])], 1)
            if rollCheck(jewelItem) then
                rollRarity(jewelItem, true) -- Force roll a rarity
            end
        end
    end
end


Item Name Fixes:
Items with 'the' prefixes: 'the devileye', 'the ironworker' etc

Because the rarity makes use of the article field they will roll as 'You see legendary the devileye' instead of 'You see a legendary devileye'.
Fix them by changing the to the article like so:

change:
XML:
<item id="8852" name="the devileye">
    <attribute key="weight" value="5500" />
    <attribute key="slotType" value="two-handed" />
    <attribute key="weaponType" value="distance" />
    <attribute key="ammoType" value="bolt" />
    <attribute key="range" value="6" />
    <attribute key="hitChance" value="-20" />
    <attribute key="attack" value="20" />
</item>
to:
XML:
<item id="8852" article="the" name="devileye">
    <attribute key="weight" value="5500" />
    <attribute key="slotType" value="two-handed" />
    <attribute key="weaponType" value="distance" />
    <attribute key="ammoType" value="bolt" />
    <attribute key="range" value="6" />
    <attribute key="hitChance" value="-20" />
    <attribute key="attack" value="20" />
</item>


Item Attributes:
The attribute name is configured in the main stats table, but if you want to edit how attributes appear on items like spacing etc:

lib/core/attributes.lua
Lua:
-- It item has a description, retain it instead of over-writing it
if it_id:getDescription() == "" then
    it_u:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, table.concat(stat_desc, "\n"))
else
    it_u:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, table.concat(stat_desc, "\n")  .. "\n" .. it_id:getDescription()) -- This is how I like it - before flavour text, no double spacing
end
 
Last edited:
OP
Leo32

Leo32

Getting back into it...
Premium User
Joined
Sep 21, 2007
Messages
918
Best answers
13
Reaction score
329

guiismiti

Active Member
Joined
May 19, 2014
Messages
291
Best answers
1
Reaction score
45
One question - if I want to include speed in the attributes, do I have to use CONDITION_PARAM_SPEED?
Is there no ITEM_ATTRIBUTE I can use?
I checked enums.h and the only speed related definition is CONDITION_PARAM_SPEED.
 
OP
Leo32

Leo32

Getting back into it...
Premium User
Joined
Sep 21, 2007
Messages
918
Best answers
13
Reaction score
329
Speed was never added as an item attribute in lua.
So yes, you would add it as a custom condition here.
 

guiismiti

Active Member
Joined
May 19, 2014
Messages
291
Best answers
1
Reaction score
45
Sorry to bother again - I added:
Code:
[18] = {"%[" .. stats[40].attribute.name .. ": ", CONDITION_PARAM_SPEED},
to the attributes array and
Code:
[40] = { -- Speed
    attribute = {
        name = 'Speed',
        rare = {3, 5},
        epic = {6, 10},
        legendary = {11, 20},
    },
    value = "Static"
}
to the stats matrix.

My item is rolling +speed, but I don't know how to deal with the conditions - can you help me?
I feel like I have to add a conditional to test if k == 18 and use specific conditions just for the speed:
Lua:
if player:getCondition(CONDITION_ATTRIBUTES, CONDITIONID_COMBAT, offset) == nil then
    local condition = Condition(CONDITION_ATTRIBUTES)
    condition:setParameter(CONDITION_PARAM_SUBID, offset)
    condition:setParameter(CONDITION_PARAM_TICKS, -1)
    condition:setParameter(attributes[k][2], skillBonus)
    player:addCondition(condition)
else
    player:removeCondition(CONDITION_ATTRIBUTES, CONDITIONID_COMBAT, offset)
end
How should these be? I know I have to use CONDITION_HASTE somewhere, but that's all.

Thanks in advance!
 

namco

Alienbutserious
Joined
Sep 5, 2010
Messages
139
Best answers
2
Reaction score
35
Hey @Leo32
I have a question: How do I merge the branch you mentioned?
I'm using the latest TFS.
 
OP
Leo32

Leo32

Getting back into it...
Premium User
Joined
Sep 21, 2007
Messages
918
Best answers
13
Reaction score
329
Once you clone the repo:
Git:
git checkout rarity-custom-attributes
git merge master
Guide:

If you are getting stuck or git is too complicated for you, manually make these changes:
Here is the latest version of the scripts, it should be error free and always work if you keep your TFS sources up-to-date.
(click on Files changed)
 
Last edited:

namco

Alienbutserious
Joined
Sep 5, 2010
Messages
139
Best answers
2
Reaction score
35
Once you clone the repo:
Git:
git checkout rarity-custom-attributes
git merge master
Guide:

If you are getting stuck or git is too complicated for you, manually make these changes:

(click on Files changed)
Ty
I'll do it manually cause git is too complicated for me xD
 

Lessaire

Omniscient Hypervisor
Premium User
Joined
Dec 29, 2009
Messages
821
Best answers
15
Reaction score
118
Location
Oregon
Actually, instead of master, you should check out a new branch, and use it as your "living quarters"
Pulling changes from upstream master into local master will never have merge conflicts this way. Then you pull changes from master into your living quarters.

And when you manually merge patches from elsewhere you can commit them. If you ever need to move the server from one spot to another, you can clone your git over ssh, or at least git bundle your living quarters. this way your sources and their history are preserved.

If you ever want to actually learn git and not just web repos like github, this book is what got me to dive in hard.

Also if you already manually made changes and want to do what suggest, no worries. git stash; then git checkout -b livingcopy; then git stash apply;
 

risy

New Member
Joined
Aug 25, 2007
Messages
6
Best answers
0
Reaction score
0
Hi guys, I have a problem and I need your help, I am using the malucoo distro with client 12 and the rarity system of the objects is deactivating the functions of the imbuements, some way to solve this? Thanks a lot.

Edit: only fail the vampirism, the other attributes work fine.
 
Last edited:
Top