• 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!
  • If you're using Gesior 2012 or MyAAC, please review this thread for information about a serious security vulnerability and a fix.

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

Leo32

Getting back into it...
Joined
Sep 21, 2007
Messages
981
Solutions
14
Reaction score
505
< 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.
 

Attachments

  • rollAttributes.zip
    17.9 KB · Views: 172 · VirusTotal
Last edited:

Evil Puncker

I know nothing
TFS Developer
Joined
May 30, 2009
Messages
8,508
Solutions
260
Reaction score
4,443
cool!!! awesome!!! I can't wait to try the 10.98 version
 
OP
OP
Leo32

Leo32

Getting back into it...
Joined
Sep 21, 2007
Messages
981
Solutions
14
Reaction score
505
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

  • rollAttributes10.98.zip
    17.2 KB · Views: 99 · VirusTotal
Last edited:

zxmatzx

Advanced OT User
Joined
Dec 1, 2010
Messages
310
Solutions
27
Reaction score
159
Location
Brazil
GitHub
Mateuso8
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
OP
Leo32

Leo32

Getting back into it...
Joined
Sep 21, 2007
Messages
981
Solutions
14
Reaction score
505
Bonus Feature:
Jewel Case drops

SDg3KPN.png


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
OP
Leo32

Leo32

Getting back into it...
Joined
Sep 21, 2007
Messages
981
Solutions
14
Reaction score
505
Last edited:

guiismiti

Well-Known Member
Joined
May 19, 2014
Messages
315
Solutions
3
Reaction score
72
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
OP
Leo32

Leo32

Getting back into it...
Joined
Sep 21, 2007
Messages
981
Solutions
14
Reaction score
505
Speed was never added as an item attribute in lua.
So yes, you would add it as a custom condition here.
 

guiismiti

Well-Known Member
Joined
May 19, 2014
Messages
315
Solutions
3
Reaction score
72
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
148
Solutions
2
Reaction score
39
Hey @Leo32
I have a question: How do I merge the branch you mentioned?
I'm using the latest TFS.
 
OP
OP
Leo32

Leo32

Getting back into it...
Joined
Sep 21, 2007
Messages
981
Solutions
14
Reaction score
505
Last edited:

namco

Alienbutserious
Joined
Sep 5, 2010
Messages
148
Solutions
2
Reaction score
39
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
1,264
Solutions
46
Reaction score
454
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

Member
Joined
Aug 25, 2007
Messages
51
Solutions
1
Reaction score
6
Location
Spain
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:

risy

Member
Joined
Aug 25, 2007
Messages
51
Solutions
1
Reaction score
6
Location
Spain
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.
Lua Script Error: [CreatureScript Interface]
data/creaturescripts/scripts/attributes.lua: onHealthChange
data/creaturescripts/scripts/attributes.lua:437: attempt to index a nil value
stack traceback:
[C]: in function '__index'
data/creaturescripts/scripts/attributes.lua:437: in function 'statChange'
data/creaturescripts/scripts/attributes.lua:513: in function <data/creaturescripts/scripts/attributes.lua:510>
[C]: at 0x7ff67fef7c80
 

Itutorial

Excellent OT User
Joined
Dec 23, 2014
Messages
2,208
Solutions
65
Reaction score
829
I got the same error as above

Code:
Lua Script Error: [CreatureScript Interface]
data/creaturescripts/scripts/attributes.lua:onHealthChange
data/creaturescripts/scripts/attributes.lua:585: attempt to index a nil value
stack traceback:
        [C]: in function '__index'
        data/creaturescripts/scripts/attributes.lua:585: in function 'statChange'
        data/creaturescripts/scripts/attributes.lua:683: in function <data/creaturescripts/scripts/attributes.lua:680>
        [C]: at 0x7ff7d5a18c50
 
Top