• 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+ [movement] Script not working – no errors, no prints.

Svira

Banned User
Joined
Jan 27, 2008
Messages
361
Solutions
13
Reaction score
105
Hello everyone,

I have a problem with my movement script for a ring. Everything seems correct, there are no errors in the console, but the script is not working at all – even the print statements are not showing up. The ring should give health/mana bonuses depending on the player's vocation when equipped and remove them when unequipped. However, equipping or unequipping the ring does nothing.

code:
LUA:
local ringStorage = 790528

local vocationBonuses = {
    [4] = {health = 1500, mana = -500, storage = 1}, -- Knight
    [8] = {health = 1500, mana = -500, storage = 1}, -- Elite Knight
    [5] = {health = 1500, mana = -500, storage = 1}, -- Paladin
    [9] = {health = 1500, mana = -500, storage = 1}, -- Royal Paladin
    [2] = {health = -400, mana = 1300, storage = 2}, -- Druid
    [6] = {health = -400, mana = 1300, storage = 2}, -- Elder Druid
    [1] = {health = -400, mana = 1300, storage = 2}, -- Sorcerer
    [7] = {health = -400, mana = 1300, storage = 2}  -- Master Sorcerer
}

function onEquip(player, item, slot)
    local vocation = player:getVocation():getId()
    local bonus = vocationBonuses[vocation]

    if bonus then
        print("Ring equipped")
        player:setHealth(math.max(1, player:getHealth() + bonus.health))
        player:setMana(math.max(0, player:getMana() + bonus.mana))
        player:setStorageValue(ringStorage, bonus.storage)
       
        local message = (bonus.storage == 1) and
            "You feel a surge of vitality, but your magical energy diminishes." or
            "You feel a surge of magical energy, but your vitality diminishes."
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, message)
    else
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "This ring seems to have no effect on you.")
    end
    return true
end

function onDeEquip(player, item, slot)
    local storageValue = player:getStorageValue(ringStorage)
    if storageValue == 1 then
        print("Ring unequipped (Knight/Paladin)")
        player:setHealth(math.max(1, player:getHealth() - 1500))
        player:setMana(math.max(0, player:getMana() + 500))
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The surge of vitality fades, and your magical energy returns.")
    elseif storageValue == 2 then
        print("Ring unequipped (Druid/Sorcerer)")
        player:setMana(math.max(0, player:getMana() - 1300))
        player:setHealth(math.max(1, player:getHealth() + 400))
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The surge of magical energy fades, and your vitality returns.")
    end
    player:setStorageValue(ringStorage, -1) -- Reset the storage value
    return true
end
and register:
XML:
<!-- Tier EQ -->
<movement type="Equip" itemid="13825" slot="ring" script="ring_tier_1.lua">
    <vocation name="Knight" />
    <vocation name="Elite Knight" showInDescription="0" />
    <vocation name="Paladin" />
    <vocation name="Royal Paladin" showInDescription="0" />
    <vocation name="Sorcerer" />
    <vocation name="Master Sorcerer" showInDescription="0" />
    <vocation name="Druid" />
    <vocation name="Elder Druid" showInDescription="0" />
</movement>
<movement type="DeEquip" itemid="13825" slot="ring" script="ring_tier_1.lua" />

I have checked everything, and there are no errors in the console. However, the print messages are not showing, and the effects are not applied to the player.

Does anyone know what could be wrong? Is there something missing in movements.xml, or is there an issue with how onEquip and onDeEquip are handled?

Thanks in advance for your help!

#edit:
Yes, I know I can do it in items.xml but I want to check vocation...
 
Last edited:
Solution
Let me understand what you want—when equipping the ring, you gain HP/Mana, and when removing it, the HP/MP is also removed, correct? If so, you should use the condition parameter for HP/MP instead of the player:setHealth or player:setMana function. The best and simplest way is to use conditions.
LUA:
local ringStorage = 790528

local vocationBonuses = {
    [4] = {health = 1500, mana = -500, storage = 1}, -- Knight
    [8] = {health = 1500, mana = -500, storage = 1}, -- Elite Knight
    [5] = {health = 1500, mana = -500, storage = 1}, -- Paladin
    [9] = {health = 1500, mana = -500, storage = 1}, -- Royal Paladin
    [2] = {health = -400, mana = 1300, storage = 2}, -- Druid
    [6] = {health = -400, mana = 1300, storage = 2}, -- Elder...
in movements maybe add
LUA:
function="onDeEquipItem"
and
LUA:
function="onEquipItem"

maybe some related to that?

and maybe some:

If the player has less than 1500 HP, they will die immediately after removing the ring.
LUA:
player:setHealth(math.max(1, player:getHealth() - 1500))
to
LUA:
local currentHealth = player:getHealth()
player:setHealth(math.max(1, currentHealth > 1500 and (currentHealth - 1500) or 1))

LUA:
local storageValue = player:getStorageValue(ringStorage)
player:setStorageValue(ringStorage, -1)

LUA:
if player:getStorageValue(ringStorage) > 0 then
    player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You are already affected by the ring's power.")
    return false
end
? 🤔
 
in movements maybe add
LUA:
function="onDeEquipItem"
and
LUA:
function="onEquipItem"

maybe some related to that?

and maybe some:

If the player has less than 1500 HP, they will die immediately after removing the ring.
LUA:
player:setHealth(math.max(1, player:getHealth() - 1500))
to
LUA:
local currentHealth = player:getHealth()
player:setHealth(math.max(1, currentHealth > 1500 and (currentHealth - 1500) or 1))

LUA:
local storageValue = player:getStorageValue(ringStorage)
player:setStorageValue(ringStorage, -1)

LUA:
if player:getStorageValue(ringStorage) > 0 then
    player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You are already affected by the ring's power.")
    return false
end
? 🤔
Hi,

I made the changes as suggested, but there are still no errors, and the code is not working as expected. The print statements are not even showing up, which means it’s not executing the onEquip or onDeEquip functions at all.

Could you help me identify the issue? Maybe I missed something, or there's an issue with how the events are triggered.

Thanks in advance!


LUA:
local ringStorage = 790528

local vocationBonuses = {
    [4] = {health = 1500, mana = -500, storage = 1}, -- Knight
    [8] = {health = 1500, mana = -500, storage = 1}, -- Elite Knight
    [5] = {health = 1500, mana = -500, storage = 1}, -- Paladin
    [9] = {health = 1500, mana = -500, storage = 1}, -- Royal Paladin
    [2] = {health = -400, mana = 1300, storage = 2}, -- Druid
    [6] = {health = -400, mana = 1300, storage = 2}, -- Elder Druid
    [1] = {health = -400, mana = 1300, storage = 2}, -- Sorcerer
    [7] = {health = -400, mana = 1300, storage = 2}  -- Master Sorcerer
}

function onEquip(player, item, slot)
    local vocation = player:getVocation():getId()
    local bonus = vocationBonuses[vocation]

    if bonus then
        if player:getStorageValue(ringStorage) > 0 then
            player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You are already affected by the ring's power.")
            return false
        end

        print("Ring equipped")
        player:setHealth(math.max(1, player:getHealth() + bonus.health))
        player:setMana(math.max(0, player:getMana() + bonus.mana))
        player:setStorageValue(ringStorage, bonus.storage)
      
        local message = (bonus.storage == 1) and
            "You feel a surge of vitality, but your magical energy diminishes." or
            "You feel a surge of magical energy, but your vitality diminishes."
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, message)
    else
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "This ring seems to have no effect on you.")
    end
    return true
end

function onDeEquip(player, item, slot)
    local storageValue = player:getStorageValue(ringStorage)
    if storageValue == 1 then
        print("Ring unequipped (Knight/Paladin)")
        local currentHealth = player:getHealth()
        player:setHealth(math.max(1, currentHealth > 1500 and (currentHealth - 1500) or 1))
        player:setMana(math.max(0, player:getMana() + 500))
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The surge of vitality fades, and your magical energy returns.")
    elseif storageValue == 2 then
        print("Ring unequipped (Druid/Sorcerer)")
        player:setMana(math.max(0, player:getMana() - 1300))
        player:setHealth(math.max(1, player:getHealth() + 400))
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The surge of magical energy fades, and your vitality returns.")
    end
    player:setStorageValue(ringStorage, -1) -- Reset the storage value
    return true
end

XML:
<!-- Tier EQ -->
    <movement type="Equip" itemid="13825" slot="ring"  function="onEquipItem" script="ring_tier_1.lua">
        <vocation name="Knight" />
        <vocation name="Elite Knight" showInDescription="0" />
        <vocation name="Paladin" />
        <vocation name="Royal Paladin" showInDescription="0" />
        <vocation name="Sorcerer" />
        <vocation name="Master Sorcerer" showInDescription="0" />
        <vocation name="Druid" />
        <vocation name="Elder Druid" showInDescription="0" />
    </movement>
    <movement type="DeEquip" itemid="13825" slot="ring"  function="onDeEquipItem" script="ring_tier_1.lua" />
 
Is it correct to use the "event" function instead of "type". It should be like this:

XML:
<!-- Tier EQ -->
<movevent event="Equip" itemid="13825" slot="ring" script="ring_tier_1.lua">
    <vocation name="Knight" />
    <vocation name="Elite Knight" showInDescription="0" />
    <vocation name="Paladin" />
    <vocation name="Royal Paladin" showInDescription="0" />
    <vocation name="Sorcerer" />
    <vocation name="Master Sorcerer" showInDescription="0" />
    <vocation name="Druid" />
    <vocation name="Elder Druid" showInDescription="0" />
</movevent>
<movevent event="DeEquip" itemid="13825" slot="ring" script="ring_tier_1.lua" />

The script, I just improved a few details here.
LUA:
local ringStorage = 790528

local vocationBonuses = {
    [4] = {health = 1500, mana = -500, storage = 1}, -- Knight
    [8] = {health = 1500, mana = -500, storage = 1}, -- Elite Knight
    [5] = {health = 1500, mana = -500, storage = 1}, -- Paladin
    [9] = {health = 1500, mana = -500, storage = 1}, -- Royal Paladin
    [2] = {health = -400, mana = 1300, storage = 2}, -- Druid
    [6] = {health = -400, mana = 1300, storage = 2}, -- Elder Druid
    [1] = {health = -400, mana = 1300, storage = 2}, -- Sorcerer
    [7] = {health = -400, mana = 1300, storage = 2}  -- Master Sorcerer
}

function onEquip(player, item, slot)
    print("onEquip called") -- Adding debug message
    local vocation = player:getVocation():getId()
    print("Player vocation: " .. vocation) -- Adding debug message
    local bonus = vocationBonuses[vocation]

    if bonus then
        if player:getStorageValue(ringStorage) > 0 then
            player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You are already affected by the ring's power.")
            return false
        end

        print("Ring equipped") -- Adding debug message
        player:setHealth(math.max(1, player:getHealth() + bonus.health))
        player:setMana(math.max(0, player:getMana() + bonus.mana))
        player:setStorageValue(ringStorage, bonus.storage)
      
        local message = (bonus.storage == 1) and
            "You feel a surge of vitality, but your magical energy diminishes." or
            "You feel a surge of magical energy, but your vitality diminishes."
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, message)
    else
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "This ring seems to have no effect on you.")
    end
    return true
end

function onDeEquip(player, item, slot)
    print("onDeEquip called") -- Adding debug message
    local storageValue = player:getStorageValue(ringStorage)
    print("Storage value: " .. storageValue) -- Adding debug message
    if storageValue == 1 then
        print("Ring unequipped (Knight/Paladin)") -- Adding debug message
        local currentHealth = player:getHealth()
        player:setHealth(math.max(1, currentHealth > 1500 and (currentHealth - 1500) or 1))
        player:setMana(math.max(0, player:getMana() + 500))
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The surge of vitality fades, and your magical energy returns.")
    elseif storageValue == 2 then
        print("Ring unequipped (Druid/Sorcerer)") -- Adding debug message
        player:setMana(math.max(0, player:getMana() - 1300))
        player:setHealth(math.max(1, player:getHealth() + 400))
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The surge of magical energy fades, and your vitality returns.")
    end
    player:setStorageValue(ringStorage, -1) -- Reset the storage value
    return true
end
 
Is it correct to use the "event" function instead of "type". It should be like this:

XML:
<!-- Tier EQ -->
<movevent event="Equip" itemid="13825" slot="ring" script="ring_tier_1.lua">
    <vocation name="Knight" />
    <vocation name="Elite Knight" showInDescription="0" />
    <vocation name="Paladin" />
    <vocation name="Royal Paladin" showInDescription="0" />
    <vocation name="Sorcerer" />
    <vocation name="Master Sorcerer" showInDescription="0" />
    <vocation name="Druid" />
    <vocation name="Elder Druid" showInDescription="0" />
</movevent>
<movevent event="DeEquip" itemid="13825" slot="ring" script="ring_tier_1.lua" />

The script, I just improved a few details here.
LUA:
local ringStorage = 790528

local vocationBonuses = {
    [4] = {health = 1500, mana = -500, storage = 1}, -- Knight
    [8] = {health = 1500, mana = -500, storage = 1}, -- Elite Knight
    [5] = {health = 1500, mana = -500, storage = 1}, -- Paladin
    [9] = {health = 1500, mana = -500, storage = 1}, -- Royal Paladin
    [2] = {health = -400, mana = 1300, storage = 2}, -- Druid
    [6] = {health = -400, mana = 1300, storage = 2}, -- Elder Druid
    [1] = {health = -400, mana = 1300, storage = 2}, -- Sorcerer
    [7] = {health = -400, mana = 1300, storage = 2}  -- Master Sorcerer
}

function onEquip(player, item, slot)
    print("onEquip called") -- Adding debug message
    local vocation = player:getVocation():getId()
    print("Player vocation: " .. vocation) -- Adding debug message
    local bonus = vocationBonuses[vocation]

    if bonus then
        if player:getStorageValue(ringStorage) > 0 then
            player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You are already affected by the ring's power.")
            return false
        end

        print("Ring equipped") -- Adding debug message
        player:setHealth(math.max(1, player:getHealth() + bonus.health))
        player:setMana(math.max(0, player:getMana() + bonus.mana))
        player:setStorageValue(ringStorage, bonus.storage)
    
        local message = (bonus.storage == 1) and
            "You feel a surge of vitality, but your magical energy diminishes." or
            "You feel a surge of magical energy, but your vitality diminishes."
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, message)
    else
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "This ring seems to have no effect on you.")
    end
    return true
end

function onDeEquip(player, item, slot)
    print("onDeEquip called") -- Adding debug message
    local storageValue = player:getStorageValue(ringStorage)
    print("Storage value: " .. storageValue) -- Adding debug message
    if storageValue == 1 then
        print("Ring unequipped (Knight/Paladin)") -- Adding debug message
        local currentHealth = player:getHealth()
        player:setHealth(math.max(1, currentHealth > 1500 and (currentHealth - 1500) or 1))
        player:setMana(math.max(0, player:getMana() + 500))
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The surge of vitality fades, and your magical energy returns.")
    elseif storageValue == 2 then
        print("Ring unequipped (Druid/Sorcerer)") -- Adding debug message
        player:setMana(math.max(0, player:getMana() - 1300))
        player:setHealth(math.max(1, player:getHealth() + 400))
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The surge of magical energy fades, and your vitality returns.")
    end
    player:setStorageValue(ringStorage, -1) -- Reset the storage value
    return true
end
@Mateus Robeerto
everything seems to work except for the player:setHealth function, I tried addhealth but it doesn't affect maxHP, I decided to make a local function:
LUA:
local function setMaxHealth(cid, health)
return db.query("UPDATE `players` SET `healthmax` = " .. health .. " WHERE `name` = " .. db.escapeString(getCreatureName(cid)) .. ";")
end
which will change the maxhealth value in the database, however I encounter a problem - health is not added when the player is logged in and I can't use player:remove after the player having PZ Lock will be able to "kick" himself

do you have any ideas?
 
Let me understand what you want—when equipping the ring, you gain HP/Mana, and when removing it, the HP/MP is also removed, correct? If so, you should use the condition parameter for HP/MP instead of the player:setHealth or player:setMana function. The best and simplest way is to use conditions.
LUA:
local ringStorage = 790528

local vocationBonuses = {
    [4] = {health = 1500, mana = -500, storage = 1}, -- Knight
    [8] = {health = 1500, mana = -500, storage = 1}, -- Elite Knight
    [5] = {health = 1500, mana = -500, storage = 1}, -- Paladin
    [9] = {health = 1500, mana = -500, storage = 1}, -- Royal Paladin
    [2] = {health = -400, mana = 1300, storage = 2}, -- Druid
    [6] = {health = -400, mana = 1300, storage = 2}, -- Elder Druid
    [1] = {health = -400, mana = 1300, storage = 2}, -- Sorcerer
    [7] = {health = -400, mana = 1300, storage = 2}  -- Master Sorcerer
}

function onEquip(player, item, slot)
    local vocation = player:getVocation():getId()
    local bonus = vocationBonuses[vocation]

    if bonus then
        if player:getStorageValue(ringStorage) > 0 then
            player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You are already affected by the ring's power.")
            return false
        end

        -- Apply modifiers as conditions
        if bonus.health ~= 0 then
            -- Add max HP modification condition
            local condition = Condition(CONDITION_ATTRIBUTES)
            condition:setParameter(CONDITION_PARAM_TICKS, -1) -- Permanent until ring is removed
            condition:setParameter(CONDITION_PARAM_STAT_MAXHITPOINTS, bonus.health)
            player:addCondition(condition)
        end
        
        if bonus.mana ~= 0 then
            -- Add max MP modification condition
            local condition = Condition(CONDITION_ATTRIBUTES)
            condition:setParameter(CONDITION_PARAM_TICKS, -1) -- Permanent until ring is removed
            condition:setParameter(CONDITION_PARAM_STAT_MAXMANAPOINTS, bonus.mana)
            player:addCondition(condition)
        end
        
        player:setStorageValue(ringStorage, bonus.storage)
      
        local message = (bonus.storage == 1) and
            "You feel a surge of vitality, but your magical energy diminishes." or
            "You feel a surge of magical energy, but your vitality diminishes."
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, message)
    else
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "This ring seems to have no effect on you.")
    end
    return true
end

function onDeEquip(player, item, slot)
    local storageValue = player:getStorageValue(ringStorage)
    
    if storageValue > 0 then
        player:removeCondition(CONDITION_ATTRIBUTES)
        
        if storageValue == 1 then
            player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The surge of vitality fades, and your magical energy returns.")
        elseif storageValue == 2 then
            player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The surge of magical energy fades, and your vitality returns.")
        end
    end
    
    player:setStorageValue(ringStorage, -1)  -- Reset storage value
    
    return true
end
 
Solution
Exactly, when the ring is equipped, it will grant HP or MP, but it will also remove them once the ring is removed, depending on the configuration. I have already tried using your code, but I also have a "Diablo items" system that adds bonuses. If the player wants to equip the ring, it works fine, but the player gets the message: "You are already affected by the ring's power," and the ring is placed in the backpack. That's why I thought of adding an extra function (because modifying the Diablo system itself would break already existing items). I have no idea how to solve this, and it’s important to me for my small community, and I wanted to add it in the next update :D


#edit:
I tried that too but the values went crazy
LUA:
local ringStorage = 790528

local vocationBonuses = {
    [4] = {health = 1500, mana = -500}, -- Knight
    [8] = {health = 1500, mana = -500}, -- Elite Knight
    [5] = {health = 1500, mana = -500}, -- Paladin
    [9] = {health = 1500, mana = -500}, -- Royal Paladin
    [2] = {health = -400, mana = 1300}, -- Druid
    [6] = {health = -400, mana = 1300}, -- Elder Druid
    [1] = {health = -400, mana = 1300}, -- Sorcerer
    [7] = {health = -400, mana = 1300}  -- Master Sorcerer
}

function onEquip(player, item, slot)
    local vocation = player:getVocation():getId()
    local bonus = vocationBonuses[vocation]

    if bonus then
        print("Applying bonus for vocation: " .. vocation)
        
        -- Get current condition values
        local currentHealthBonus = player:getStorageValue(ringStorage .. "_health") or 0
        local currentManaBonus = player:getStorageValue(ringStorage .. "_mana") or 0
        
        -- Create condition
        local condition = Condition(CONDITION_ATTRIBUTES)
        condition:setParameter(CONDITION_PARAM_TICKS, -1)
        condition:setParameter(CONDITION_PARAM_STAT_MAXHITPOINTS, currentHealthBonus + bonus.health)
        condition:setParameter(CONDITION_PARAM_STAT_MAXMANAPOINTS, currentManaBonus + bonus.mana)
        
        -- Apply condition
        player:addCondition(condition)
        
        -- Update storage values
        player:setStorageValue(ringStorage .. "_health", currentHealthBonus + bonus.health)
        player:setStorageValue(ringStorage .. "_mana", currentManaBonus + bonus.mana)
      
        local message = (bonus.health > 0) and
            "You feel a surge of vitality, but your magical energy diminishes." or
            "You feel a surge of magical energy, but your vitality diminishes."
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, message)
    else
        print("No bonus found for vocation: " .. vocation)
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "This ring seems to have no effect on you.")
    end
    return true
end

function onDeEquip(player, item, slot)
    local vocation = player:getVocation():getId()
    local bonus = vocationBonuses[vocation]

    if bonus then
        print("Removing bonus for vocation: " .. vocation)
        
        
        local currentHealthBonus = player:getStorageValue(ringStorage .. "_health") or 0
        local currentManaBonus = player:getStorageValue(ringStorage .. "_mana") or 0
        
      
        local condition = Condition(CONDITION_ATTRIBUTES)
        condition:setParameter(CONDITION_PARAM_TICKS, -1)
        condition:setParameter(CONDITION_PARAM_STAT_MAXHITPOINTS, currentHealthBonus - bonus.health)
        condition:setParameter(CONDITION_PARAM_STAT_MAXMANAPOINTS, currentManaBonus - bonus.mana)
        
      
        player:addCondition(condition)
        
        
        player:setStorageValue(ringStorage .. "_health", currentHealthBonus - bonus.health)
        player:setStorageValue(ringStorage .. "_mana", currentManaBonus - bonus.mana)
      
        local message = (bonus.health > 0) and
            "The surge of vitality fades, and your magical energy returns." or
            "The surge of magical energy fades, and your vitality returns."
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, message)
    end
    return true
end
 
Last edited:
Back
Top