• 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!
  • 2026 staff recruitment is open! Check it out and consider applying!

Lua Weird values on onEquip / onDeEquip with setMaxHealth function

Siegh

Thronar Developer
Joined
Mar 12, 2011
Messages
1,276
Solutions
1
Reaction score
635
Location
Brazil
I'm using TFS 1.2!

It's my first time messing around with the onEquip and onDeEquip functions for movements and I'm trying to make a simple health increase on equip function.

It works perfectly, both for equiping and unequiping, BUT for some crazy reason the onEquip health increase is tripled. It increases my health by 30 when equipping, but reduces it by 10 when unequipping.

LUA:
function onEquip(player, item, slot)
    if item.itemid == 2461 then
        local maxHp = player:getMaxHealth()     
        player:getPosition():sendMagicEffect(1)
        player:setMaxHealth(maxHp+10)
    end
    return true
end

function onDeEquip(player, item, slot)
    if item.itemid == 2461 then
        local maxHp = player:getMaxHealth()     
        player:getPosition():sendMagicEffect(1)
        player:setMaxHealth(maxHp-10)
    end
    return true
end

Any clues on why is this happening?
 
I'm using TFS 1.2!

It's my first time messing around with the onEquip and onDeEquip functions for movements and I'm trying to make a simple health increase on equip function.

It works perfectly, both for equiping and unequiping, BUT for some crazy reason the onEquip health increase is tripled. It increases my health by 30 when equipping, but reduces it by 10 when unequipping.

LUA:
function onEquip(player, item, slot)
    if item.itemid == 2461 then
        local maxHp = player:getMaxHealth()    
        player:getPosition():sendMagicEffect(1)
        player:setMaxHealth(maxHp+10)
    end
    return true
end

function onDeEquip(player, item, slot)
    if item.itemid == 2461 then
        local maxHp = player:getMaxHealth()    
        player:getPosition():sendMagicEffect(1)
        player:setMaxHealth(maxHp-10)
    end
    return true
end

Any clues on why is this happening?
 
Thanks, that helped me understand the issue. While the compiling would be the best solution, I've worked around it with something way simpler. Now that I've tested it, I will properly do it with a global array in order to facilitate the addition of multiple new items :)


LUA:
function onEquip(player, item, slot)
    stg = 2461
    stgCheck = player:getStorageValue(stg)
    if item.itemid == 2461 then
        if stgCheck == -1 then
            player:setStorageValue(stg, 1)
            addEvent(setPlayerStorageValue, 20, player, stg, -1)
            player:getPosition():sendMagicEffect(1)
            player:setMaxHealth(player:getMaxHealth()+10)
        end
    end
    return true
end

function onDeEquip(player, item, slot)
    stg = 2461
    stgCheck = player:getStorageValue(stg)   
    if item.itemid == 2461 then
        if stgCheck == -1 then
            player:setStorageValue(stg, 1)
            addEvent(setPlayerStorageValue, 20, player, stg, -1)
            player:getPosition():sendMagicEffect(1)
            player:setMaxHealth(player:getMaxHealth()-10)
        end
    end
    return true
end
 
Thanks, that helped me understand the issue. While the compiling would be the best solution, I've worked around it with something way simpler. Now that I've tested it, I will properly do it with a global array in order to facilitate the addition of multiple new items :)


LUA:
function onEquip(player, item, slot)
    stg = 2461
    stgCheck = player:getStorageValue(stg)
    if item.itemid == 2461 then
        if stgCheck == -1 then
            player:setStorageValue(stg, 1)
            addEvent(setPlayerStorageValue, 20, player, stg, -1)
            player:getPosition():sendMagicEffect(1)
            player:setMaxHealth(player:getMaxHealth()+10)
        end
    end
    return true
end

function onDeEquip(player, item, slot)
    stg = 2461
    stgCheck = player:getStorageValue(stg)  
    if item.itemid == 2461 then
        if stgCheck == -1 then
            player:setStorageValue(stg, 1)
            addEvent(setPlayerStorageValue, 20, player, stg, -1)
            player:getPosition():sendMagicEffect(1)
            player:setMaxHealth(player:getMaxHealth()-10)
        end
    end
    return true
end
Please don't do it this way, it is the worst solution possible🤒
 
I'm genuinely curious, why is it the worst?

It's working as intended with equipping, unequipping, dying and logging out.
I think it's to simplify your code so it doesn't become long or repetitive!
ex:
LUA:
local function changeAttr(player, item, isEquip)
    local value = tonumber(item:getCustomAttribute("CHANGESPEED")) or 0
    local speed = player:getSpeed()
    if value > 0 and speed > 0 then
        player:changeSpeed(isEquip and value or -value)
    end
    
    -- new functions
    
    -- others ...
end


function onEquip(player, item, slot)
    changeAttr(player, item, true)
    return true
end

function onDeEquip(player, item, slot)
    changeAttr(player, item, false)
    return true
end
 
I think it's to simplify your code so it doesn't become long or repetitive!
ex:
LUA:
local function changeAttr(player, item, isEquip)
    local value = tonumber(item:getCustomAttribute("CHANGESPEED")) or 0
    local speed = player:getSpeed()
    if value > 0 and speed > 0 then
        player:changeSpeed(isEquip and value or -value)
    end
  
    -- new functions
  
    -- others ...
end


function onEquip(player, item, slot)
    changeAttr(player, item, true)
    return true
end

function onDeEquip(player, item, slot)
    changeAttr(player, item, false)
    return true
end
Ah, it's not, there is a single array with my equipment and their custom attributes on global.lua and a single file with a equip and dequip function. The storage value is only there to prevent the client from checking the function more than once within 20ms and will be the same for any item.

I will post my final solution here when I get home.
Post automatically merged:

Function on Global.lua in case I want to check this somewhere else.

Code:
function getGearArray(player)
    gear = {
        [2464] = {hpIncrease = 20, mpIncrease = 0}, --Chain Mail
        [2458] = {hpIncrease = 8, mpIncrease = 0}, --Chain Coif
        [2648] = {hpIncrease = 8, mpIncrease = 0}, --Chain Legs   
        [2526] = {hpIncrease = 20, mpIncrease = 0}, --Wooden Shield       
    }
end

Code that checks everything on movements.

LUA:
function onEquip(player, item, slot)
    stg = 2461
    stgCheck = player:getStorageValue(stg)
    getGearArray(player)
    gear = gear[item.itemid]
    if stgCheck == -1 then   
        player:setStorageValue(stg, 1)
        addEvent(setPlayerStorageValue, 20, player, stg, -1)
        player:getPosition():sendMagicEffect(1)
        player:setMaxHealth(player:getMaxHealth()+gear.hpIncrease)
    end
    return true
end

function onDeEquip(player, item, slot)
    stg = 2461
    stgCheck = player:getStorageValue(stg)
    getGearArray(player)
    gear = gear[item.itemid]
    if stgCheck == -1 then   
        player:setStorageValue(stg, 1)
        addEvent(setPlayerStorageValue, 20, player, stg, -1)
        player:getPosition():sendMagicEffect(1)
        player:setMaxHealth(player:getMaxHealth()-gear.hpIncrease)
    end
    return true
end
 
Last edited:
Ah, it's not, there is a single array with my equipment and their custom attributes on global.lua and a single file with a equip and dequip function. The storage value is only there to prevent the client from checking the function more than once within 20ms and will be the same for any item.

I will post my final solution here when I get home.
Post automatically merged:

Function on Global.lua in case I want to check this somewhere else.

Code:
function getGearArray(player)
    gear = {
        [2464] = {hpIncrease = 20, mpIncrease = 0}, --Chain Mail
        [2458] = {hpIncrease = 8, mpIncrease = 0}, --Chain Coif
        [2648] = {hpIncrease = 8, mpIncrease = 0}, --Chain Legs  
        [2526] = {hpIncrease = 20, mpIncrease = 0}, --Wooden Shield      
    }
end

Code that checks everything on movements.

LUA:
function onEquip(player, item, slot)
    stg = 2461
    stgCheck = player:getStorageValue(stg)
    getGearArray(player)
    gear = gear[item.itemid]
    if stgCheck == -1 then  
        player:setStorageValue(stg, 1)
        addEvent(setPlayerStorageValue, 20, player, stg, -1)
        player:getPosition():sendMagicEffect(1)
        player:setMaxHealth(player:getMaxHealth()+gear.hpIncrease)
    end
    return true
end

function onDeEquip(player, item, slot)
    stg = 2461
    stgCheck = player:getStorageValue(stg)
    getGearArray(player)
    gear = gear[item.itemid]
    if stgCheck == -1 then  
        player:setStorageValue(stg, 1)
        addEvent(setPlayerStorageValue, 20, player, stg, -1)
        player:getPosition():sendMagicEffect(1)
        player:setMaxHealth(player:getMaxHealth()-gear.hpIncrease)
    end
    return true
end
Meh, addEvent on userdata -> ka-boom.
 
I will post my final solution here when I get home.
The issue with using setMaxHealth directly is that it modifies the value raw and cumulatively — if onEquip fires more than once (e.g. duplicate registration in movements.xml), it stacks uncontrollably, which is exactly why you're seeing +30 on equip and -10 on deequip. Using CONDITION_ATTRIBUTES is the right approach here, as the bonus is applied and removed in a controlled, safe way by the engine itself — no raw math, no stacking issues. Just make sure to assign a fixed subId to the condition and remove it by the same subId, otherwise it may conflict with other attribute conditions already active on the player (spells, other equipment, etc.).
 
Meh, addEvent on userdata -> ka-boom.

You mean it could crash? As long as I keep the timer even smaller the probability of an issue is close to none.
The issue with using setMaxHealth directly is that it modifies the value raw and cumulatively — if onEquip fires more than once (e.g. duplicate registration in movements.xml), it stacks uncontrollably, which is exactly why you're seeing +30 on equip and -10 on deequip. Using CONDITION_ATTRIBUTES is the right approach here, as the bonus is applied and removed in a controlled, safe way by the engine itself — no raw math, no stacking issues. Just make sure to assign a fixed subId to the condition and remove it by the same subId, otherwise it may conflict with other attribute conditions already active on the player (spells, other equipment, etc.).
I understand, but I usually have a hard time with the removeCondition not working properly. Can you give me an example of how to correctly use it?
 
The issue with using setMaxHealth directly is that it modifies the value raw and cumulatively — if onEquip fires more than once (e.g. duplicate registration in movements.xml), it stacks uncontrollably, which is exactly why you're seeing +30 on equip and -10 on deequip. Using CONDITION_ATTRIBUTES is the right approach here, as the bonus is applied and removed in a controlled, safe way by the engine itself — no raw math, no stacking issues. Just make sure to assign a fixed subId to the condition and remove it by the same subId, otherwise it may conflict with other attribute conditions already active on the player (spells, other equipment, etc.).
im interested in this. I'm using tfs 1.4.2 and where do I look for this? Items present in vanilla tibia already have attributes in the items.xml for example, boots of haste here has <attribute key="speed" value="40" />
 
What I'm currently having an issue with is, by using a script on an equipment's movement, like this...

XML:
    <movevent event="Equip" itemid="2497" slot="head" function="onEquipItem" script="gear/equip_armor.lua"/>
    <movevent event="DeEquip" itemid="2497" slot="head" function="onDeEquipItem" script="gear/equip_armor.lua"/>

The normal attributes set on items.xml, like elemental resistances or magic level increase, are not working anymore. Is there a way to either have both working, or to make the .lua script also have them work? I don't think I have a function to work with elemental resistances on my tfs 1.2.
 
This is the code I'm currently using, using conditions definitely was the right approach for what I wanted. Using the item.itemid as the SUBID number also simplifies a lot the logic behind making each equipment have its unique condition to be removed later.

My only issue right now is that I can't load attributes such as Elemental Resistance, Skill Levels, Speed or regeneration at the same item that I have a hp or mp increase since I'm using a script on it. While I can simulate most of these with conditions, elemental resistances is something that I can't.

Any clue on how I could use a script such as this one and still being able to have the items.xml attributes working?

LUA:
function onEquip(player, item, slot)
    getGearArray(player)
    if gear[item.itemid] then
        local gear = gear[item.itemid]
        player:getPosition():sendMagicEffect(1)
        local condition = Condition(CONDITION_ATTRIBUTES, CONDITIONID_COMBAT)
        condition:setParameter(CONDITION_PARAM_STAT_MAXHITPOINTS, gear.hpIncrease)
        condition:setParameter(CONDITION_PARAM_STAT_MAXMANAPOINTS, gear.mpIncrease)
        condition:setParameter(CONDITION_PARAM_SUBID, item.itemid)
        condition:setParameter(CONDITION_PARAM_TICKS, -1)
        player:addCondition(condition)      
    end
    return true
end
function onDeEquip(player, item, slot)
    getGearArray(player)
    if gear[item.itemid] then
        local gear = gear[item.itemid]
        player:getPosition():sendMagicEffect(1)
        player:removeCondition(CONDITION_ATTRIBUTES, CONDITIONID_COMBAT, item.itemid, 1)
    end
    return true
end
 
Back
Top