• 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!

Lua Custom ring function

pasiak12

Well-Known Member
Joined
Jun 7, 2009
Messages
261
Solutions
13
Reaction score
71
I would like to replace stealth ring with new item called 'mana ring'.

I have edited items.xml

Code:
    <item id="2202" article="a" name="mana ring&#10;(1% max mana / sec)">
        <attribute key="weight" value="100" />
        <attribute key="slotType" value="ring" />
        <attribute key="transformDeEquipTo" value="2165" />
    </item>

    <item id="2165" article="a" name="mana ring">
        <attribute key="weight" value="100" />
        <attribute key="slotType" value="ring" />
        <attribute key="transformEquipTo" value="2202" />
    </item>

And now I would like to execute custom script when someone is wearing the ring.

The original part of movements.xml is:
Code:
    <!-- MANA RING -->
    <movevent event="Equip" itemid="2165" slot="ring" function="onEquipItem" />
    <movevent event="Equip" itemid="2202" slot="ring" function="onEquipItem" />
    <movevent event="DeEquip" itemid="2202" slot="ring" function="onDeEquipItem" />

I would like to put somewhere script="manaring.lua" but every combination I tried didn't work correctly.

The manaring.lua script should add 1% mana pers sec to the user.

The script hasn't been tested yet
Code:
function onEquip(creature, item, slot)

    local player = creature:getPlayer()
    local ring = player:getSlotItem(CONST_SLOT_RING)
    player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "ring on") --debug

    if item.itemid == 2202 and slot == 9 then
        creature:getPlayer():sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "condition is met") --debug
        
        --some loop ?
        mana1 = creature:getMaxMana() * 1/100 -- get 1% max mana
        creature:addMana(mana1)
        --some 'wait' method 1 sec
        
    end
end

I don't know if the script has been projected properly yet. I think some kind of 'addEvent' function with time interval would be better, can anyone also give me a tip to that?

tfs 1.2
 
Solution
are talking about this?



Doesn't work. After changing to

Code:
<movevent event="Equip" itemid="2165" slot="ring" script="manaring.lua" />

1. Gives 3x mana to the user (Im gonna read about this bug soon)
2. Still gives mana even if the player take off the ring (Definitely can't work that way)
3. The ring doesn't transform into 'sparking' ring (id 2022)


edit - - - -

This almost works (I think)

Code:
runningEvents = {}

local function addMana(cid, time)
    local player = Player(cid)
    if not player then
        return
    end
  
  
    player:addMana(math.ceil(player:getMaxMana() * (1/100)))
    runningEvents[player:getGuid()] = addEvent(addMana, time, cid, time)
  
end

function onEquip(player, item, slot)...
equip doesnt use creature argument, since nothing other than players will ever equip an item
you also don't need to check ring slot or itemid since it should execute script whenever you equip the ring into the ring slot with that itemid
Code:
local function addMana(cid, itemid, time, amount)
    --// Recreate player userdata (addEvent warns about passing userdata because it may become null when function is executed)
    local player = Player(cid)
    if not player then
        return
    end
    --// Check if player still has ring equipped
    if (player:getSlotItem(CONST_SLOT_RING).itemid == itemid) then
        player:addMana(amount)
        --//     Callback  MS   |          args          |
        addEvent(addMana, time, cid, itemid, time, amount)
    end
end

function onEquip(player, item, slot)
    player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "ring on") --debug
    addMana(player:getId(), item.itemid, 1000, player:getMaxMana() * (1/100))
    return true
end

Code:
   <movevent event="Equip" itemid="2165" slot="ring" script="manaRing.lua" />
   <movevent event="DeEquip" itemid="2202" slot="ring" function="onDeEquipItem" />

another way of doing this would be using onEquip/onDeEquip functions in the same file and have a table with cid events that are waiting to be executed
add it in onEquip
when onDeEquip executes, do stopEvent(sometable[player:getId()])
 
Last edited:
Corrected small mistake creature:getMaxMana() into player:getMaxMana() in onEquip function.

In this solution, when I try to wear a ring, the ring doesnt go into ring slot, I receive msg "You can't dress this object here", and got 1 debug msg "ring on" (Seems like it has been executed once). The error in console shows that player:getSlotItem(CONST_SLOT_RING).itemid is null (which is true because I can't dress up ring).
 
Code:
runningEvents = {}

local function addMana(cid, time)
    --// Recreate player userdata (addEvent warns about passing userdata because it may become null when function is executed)
    local player = Player(cid)
    if not player then
        return
    end
    player:addMana(math.ceil(player:getMaxMana() * (1/100)))
    runningEvents[player:getGuid()] = addEvent(addMana, time, cid, time)
end

function onEquip(player, item, slot)
    addMana(player:getId(), 1000)
    return true
end

function onDeEquip(player, item, slot)
    runningEvents[player:getGuid()] = nil
    item:transform(ItemType(item.itemid):getTransformDeEquipId())
    return true
end

Code:
    <movevent event="Equip" itemid="2202" slot="ring" script="manaRing.lua" />
    <movevent event="DeEquip" itemid="2202" slot="ring" script="manaRing.lua" />


try this instead
i guess movement didnt execute for the base item id because it transforms itemid before execution
tested, this works
 
Last edited:
Had no effect with that, changed in the movements.xml to the

Code:
    <movevent event="Equip" itemid="2165" slot="ring" script="manaring.lua" />
    <movevent event="DeEquip" itemid="2202" slot="ring" script="manaring.lua" />

With that, the player wearing the ring is receiving the triple amount of mana. For example player that has 201 mana (1% = 2,01, ceil funcion = 3 mana) is receiving 9 mana per sec.

I put the debug msg

Code:
local function addMana(cid, time)
    --// Recreate player userdata (addEvent warns about passing userdata because it may become null when function is executed)
    local player = Player(cid)
    if not player then
        return
    end
    player:addMana(math.ceil(player:getMaxMana() * (1/100)))
    
    player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, math.ceil(player:getMaxMana() * (1/100)))
    
    runningEvents[player:getGuid()] = addEvent(addMana, time, cid, time)
end

And there 3x times '3' on the chat per second (The function is executing triple times per sec)

Also the mana is still regenerating this way if I take off the ring.

And theres no animation when ring is placed in ring slot :(
 
Had no effect with that, changed in the movements.xml to the

Code:
    <movevent event="Equip" itemid="2165" slot="ring" script="manaring.lua" />
    <movevent event="DeEquip" itemid="2202" slot="ring" script="manaring.lua" />

With that, the player wearing the ring is receiving the triple amount of mana. For example player that has 201 mana (1% = 2,01, ceil funcion = 3 mana) is receiving 9 mana per sec.

I put the debug msg

Code:
local function addMana(cid, time)
    --// Recreate player userdata (addEvent warns about passing userdata because it may become null when function is executed)
    local player = Player(cid)
    if not player then
        return
    end
    player:addMana(math.ceil(player:getMaxMana() * (1/100)))
   
    player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, math.ceil(player:getMaxMana() * (1/100)))
   
    runningEvents[player:getGuid()] = addEvent(addMana, time, cid, time)
end

And there 3x times '3' on the chat per second (The function is executing triple times per sec)

Also the mana is still regenerating this way if I take off the ring.

And theres no animation when ring is placed in ring slot :(
i edited the code because i figured out soon after that stopEvent wasn't working for some reason
i retested it and it should work
just add player:getPosition():sendMagicEffect(CONST_ME_MAGIC_BLUE) in the onEquip function and it should be all good
 
i edited the code because i figured out soon after that stopEvent wasn't working for some reason
i retested it and it should work
just add player:getPosition():sendMagicEffect(CONST_ME_MAGIC_BLUE) in the onEquip function and it should be all good

Where's edited code? Still same result. 3x amount of mana per sec for endless time (still giving mana when ring is taken off)

When I mention about no animation effect, I mean that the ring doesn't transform into 2202 item (the ring with moving sparks).
 
Where's edited code? Still same result. 3x amount of mana per sec for endless time (still giving mana when ring is taken off)

When I mention about no animation effect, I mean that the ring doesn't transform into 2202 item (the ring with moving sparks).
i edited the code in the last post i gave the code in
did you edit the base ring back to function in the xml instead of script?
 
There is a TFS bug that makes onEquip trigger multiple times:
https://github.com/otland/forgottenserver/issues/278

So you may want to add some storagevalue checker to confirm proper onEquip/dequip action.

onequip:
if storage value xxxx = 0, set it to 1 and run code.

ondeequip
if storage value xxxx = 1, set it to 0 and run code.
 
i edited the code in the last post i gave the code in
did you edit the base ring back to function in the xml instead of script?

are talking about this?

Code:
runningEvents = {}

local function addMana(cid, time)
    --// Recreate player userdata (addEvent warns about passing userdata because it may become null when function is executed)
    local player = Player(cid)
    if not player then
        return
    end
    player:addMana(math.ceil(player:getMaxMana() * (1/100)))
    runningEvents[player:getGuid()] = addEvent(addMana, time, cid, time)
end

function onEquip(player, item, slot)
    addMana(player:getId(), 1000)
    return true
end

function onDeEquip(player, item, slot)
    runningEvents[player:getGuid()] = nil
    item:transform(ItemType(item.itemid):getTransformDeEquipId())
    return true
end

Code:
    <movevent event="Equip" itemid="2202" slot="ring" script="manaRing.lua" />
    <movevent event="DeEquip" itemid="2202" slot="ring" script="manaRing.lua" />


try this instead
i guess movement didnt execute for the base item id because it transforms itemid before execution
tested, this works

Doesn't work. After changing to

Code:
<movevent event="Equip" itemid="2165" slot="ring" script="manaring.lua" />

1. Gives 3x mana to the user (Im gonna read about this bug soon)
2. Still gives mana even if the player take off the ring (Definitely can't work that way)
3. The ring doesn't transform into 'sparking' ring (id 2022)


edit - - - -

This almost works (I think)

Code:
runningEvents = {}

local function addMana(cid, time)
    local player = Player(cid)
    if not player then
        return
    end
    
    
    player:addMana(math.ceil(player:getMaxMana() * (1/100)))
    runningEvents[player:getGuid()] = addEvent(addMana, time, cid, time)
    
end

function onEquip(player, item, slot)
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "ring on")
    item:transform(ItemType(item.itemid):getTransformEquipId())
    addMana(player:getId(), 1000)
    return true
end

function onDeEquip(player, item, slot)
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "ring off")

    runningEvents[player:getGuid()] = nil
    item:transform(ItemType(item.itemid):getTransformDeEquipId())
    return true
end

but the

Code:
 runningEvents[player:getGuid()] = nil

Doesn't break the event, so the player is still gaining the mana even the ring is taken off.

Also accidentally the mana amount on gain is correct (3 mana per sec for 201 max mana)
 
Last edited:
are talking about this?



Doesn't work. After changing to

Code:
<movevent event="Equip" itemid="2165" slot="ring" script="manaring.lua" />

1. Gives 3x mana to the user (Im gonna read about this bug soon)
2. Still gives mana even if the player take off the ring (Definitely can't work that way)
3. The ring doesn't transform into 'sparking' ring (id 2022)


edit - - - -

This almost works (I think)

Code:
runningEvents = {}

local function addMana(cid, time)
    local player = Player(cid)
    if not player then
        return
    end
  
  
    player:addMana(math.ceil(player:getMaxMana() * (1/100)))
    runningEvents[player:getGuid()] = addEvent(addMana, time, cid, time)
  
end

function onEquip(player, item, slot)
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "ring on")
    item:transform(ItemType(item.itemid):getTransformEquipId())
    addMana(player:getId(), 1000)
    return true
end

function onDeEquip(player, item, slot)
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "ring off")

    runningEvents[player:getGuid()] = nil
    item:transform(ItemType(item.itemid):getTransformDeEquipId())
    return true
end

but the

Code:
 runningEvents[player:getGuid()] = nil

Doesn't break the event, so the player is still gaining the mana even the ring is taken off.

Also accidentally the mana amount on gain is correct (3 mana per sec for 201 max mana)
this should be your movements.xml
Code:
    <movevent event="Equip" itemid="2165" slot="ring" function="onEquipItem" />
    <movevent event="Equip" itemid="2202" slot="ring" script="manaRing.lua" />
    <movevent event="DeEquip" itemid="2202" slot="ring" script="manaRing.lua" />
and like znote said, there is a bug with movements i guess (i never knew it still existed in 1.x o.o)
use this:
Code:
runningEvents = {}

local function addMana(cid, time)
    --// Recreate player userdata (addEvent warns about passing userdata because it may become null when function is executed)
    local player = Player(cid)
    if not player then
        return
    end
    player:addMana(math.ceil(player:getMaxMana() * (1/100)))
    runningEvents[player:getGuid()] = addEvent(addMana, time, cid, time)
end

function onEquip(player, item, slot)
    if player:getStorageValue(97593) == -1 then
        addMana(player:getId(), 1000)
        player:setStorageValue(97593, 1)
    end
    return true
end

function onDeEquip(player, item, slot)
    if player:getStorageValue(97593) == 1 then
        stopEvent(runningEvents[player:getGuid()])
        runningEvents[player:getGuid()] = nil
        item:transform(ItemType(item.itemid):getTransformDeEquipId())
        player:setStorageValue(97593, -1)
    end
    return true
end
also add this in a logout script
Code:
function onLogout(player)
    local ring = player:getSlotItem(CONST_SLOT_RING)
    if ring and (ring.itemid == 2202) then
        player:setStorageValue(97593, -1)
        stopEvent(runningEvents[player:getGuid()])
    end
    return true
end
 
Last edited:
Solution
It still doesn't break the mana gain when ring is taken off :(

I think the
Code:
runningEvents[player:getGuid()] = nil
doesn't work
 
It still doesn't break the mana gain when ring is taken off :(

I think the
Code:
runningEvents[player:getGuid()] = nil
doesn't work
wtf im retarded
idk where my stopEvent line went but here:
Code:
function onDeEquip(player, item, slot)
    if player:getStorageValue(97593) == 1 then
        stopEvent(runningEvents[player:getGuid()])
        runningEvents[player:getGuid()] = nil
        item:transform(ItemType(item.itemid):getTransformDeEquipId())
        player:setStorageValue(97593, -1)
    end
    return true
end
 
wtf im retarded
idk where my stopEvent line went but here:
Code:
function onDeEquip(player, item, slot)
    if player:getStorageValue(97593) == 1 then
        stopEvent(runningEvents[player:getGuid()])
        runningEvents[player:getGuid()] = nil
        item:transform(ItemType(item.itemid):getTransformDeEquipId())
        player:setStorageValue(97593, -1)
    end
    return true
end

Yeah it's perfect now
 
I need small improvment. When a player is wearing the ring, and login into the game, he doesnt regenerate the mana. The player have to take off the ring and dress it again to start regenerating. Is it possible to implement some 'check' when player login, if he has the ring in the equipement he should start regenerates the mana.
 
I need small improvment. When a player is wearing the ring, and login into the game, he doesnt regenerate the mana. The player have to take off the ring and dress it again to start regenerating. Is it possible to implement some 'check' when player login, if he has the ring in the equipement he should start regenerates the mana.
weird, onEquip executes when player logs in but onDeEquip doesn't execute when player logs out, so the player keeps storage value 1
Code:
function onLogout(player)
    local ring = player:getSlotItem(CONST_SLOT_RING)
    if ring and (ring.itemid == 2202) then
        player:setStorageValue(97593, -1)
        stopEvent(runningEvents[player:getGuid()])
    end
    return true
end
 
Back
Top