• 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 How to make itens break?

Icaraii

Well-Known Member
Joined
Jan 5, 2020
Messages
469
Solutions
1
Reaction score
58
Hi Guys,

I'm creating a custom server that players have a high amount of craft and to make the market work well with this system I need to make itens break with a certain amount of usages. I tried to copy ice rapier attributes from item.xml but the item I tested didn't break, do I need do to anything else?

That's how ice rapier is on my server:

Lua:
    <item id="2396" article="an" name="ice rapier">
        <attribute key="description" value="A deadly but fragile weapon." />
        <attribute key="weight" value="1500" />
        <attribute key="attack" value="42" />
        <attribute key="defense" value="1" />
        <attribute key="weaponType" value="sword" />
        <attribute key="elementIce" value="18" />
        <attribute key="charges" value="1" />
</item>

That's the item I tested on:

Lua:
    <item id="2433" article="an" name="enchanted staff">
        <attribute key="description" value="Temporary magic powers enchant this staff." />
        <attribute key="weight" value="3800" />
        <attribute key="defense" value="45" />
        <attribute key="attack" value="39" />
        <attribute key="weaponType" value="club" />
        <attribute key="charges" value="1" />
        <attribute key="showcharges" value="1" />
</item>

I even tried to add this line:

Lua:
        <attribute key="decayTo" value="0" />

but it still didn't break the item.

Also, does this way work for itens aswel?
 
Hi Guys,

I'm creating a custom server that players have a high amount of craft and to make the market work well with this system I need to make itens break with a certain amount of usages. I tried to copy ice rapier attributes from item.xml but the item I tested didn't break, do I need do to anything else?

That's how ice rapier is on my server:

Lua:
    <item id="2396" article="an" name="ice rapier">
        <attribute key="description" value="A deadly but fragile weapon." />
        <attribute key="weight" value="1500" />
        <attribute key="attack" value="42" />
        <attribute key="defense" value="1" />
        <attribute key="weaponType" value="sword" />
        <attribute key="elementIce" value="18" />
        <attribute key="charges" value="1" />
</item>

That's the item I tested on:

Lua:
    <item id="2433" article="an" name="enchanted staff">
        <attribute key="description" value="Temporary magic powers enchant this staff." />
        <attribute key="weight" value="3800" />
        <attribute key="defense" value="45" />
        <attribute key="attack" value="39" />
        <attribute key="weaponType" value="club" />
        <attribute key="charges" value="1" />
        <attribute key="showcharges" value="1" />
</item>

I even tried to add this line:

Lua:
        <attribute key="decayTo" value="0" />

but it still didn't break the item.

Also, does this way work for itens aswel?
data/weapons/weapons.xml
<melee id="2396" action="removecharge" />
 
data/scripts

Lua:
local slots = {
    CONST_SLOT_HEAD,
    CONST_SLOT_NECKLACE,
    CONST_SLOT_BACKPACK,
    CONST_SLOT_ARMOR,
    CONST_SLOT_RIGHT,
    CONST_SLOT_LEFT,
    CONST_SLOT_LEGS,
    CONST_SLOT_FEET,
    CONST_SLOT_RING,
    CONST_SLOT_AMMO
}

local function removeChargesFromAllEquippedItems(player, ignoredSlotsList)
    for i = 1, #slots do
        if not table.contains(ignoredSlotsList, slots[i]) then
            local item = player:getSlotItem(slots[i])
            if item:hasAttribute(ITEM_ATTRIBUTE_CHARGES) then
                local currentCharges = item:getAttribute(ITEM_ATTRIBUTE_CHARGES)
                if currentCharges >= 1 then
                    local newCharges = currentCharges -1
                    item:setAttribute(ITEM_ATTRIBUTE_CHARGES, newCharges)
                    if newCharges == 0 then
                        -- remove item?
                    end
                end
            end
        end
    end
end

local creatureevent = CreatureEvent("onHealthChange_removeCharges")

function creatureevent.onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
    if creature:isPlayer() and attacker:getId() ~= creature:getId() then
        removeChargesFromAllEquippedItems(creature, {CONST_SLOT_RIGHT, CONST_SLOT_LEFT})-- ignore both hand slots? Or leave the table blank
    end
    return primaryDamage, primaryType, secondaryDamage, secondaryType
end

creatureevent:register()


local creatureevent = CreatureEvent("onManaChange_removeCharges")

function creatureevent.onManaChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
    if creature:isPlayer() and attacker:getId() ~= creature:getId() then
        removeChargesFromAllEquippedItems(creature, {CONST_SLOT_RIGHT, CONST_SLOT_LEFT}) -- ignore both hand slots? Or leave the table blank
    end
    return primaryDamage, primaryType, secondaryDamage, secondaryType
end

creatureevent:register()


local loginEvent = CreatureEvent("onLogin_register_removeCharges")
loginEvent:type("login")

function loginEvent.onLogin(player)
    player:registerEvent("onHealthChange_removeCharges")
    player:registerEvent("onManaChange_removeCharges")
    return true
end

loginEvent:register()
 
data/scripts

Lua:
local slots = {
    CONST_SLOT_HEAD,
    CONST_SLOT_NECKLACE,
    CONST_SLOT_BACKPACK,
    CONST_SLOT_ARMOR,
    CONST_SLOT_RIGHT,
    CONST_SLOT_LEFT,
    CONST_SLOT_LEGS,
    CONST_SLOT_FEET,
    CONST_SLOT_RING,
    CONST_SLOT_AMMO
}

local function removeChargesFromAllEquippedItems(player, ignoredSlotsList)
    for i = 1, #slots do
        if not table.contains(ignoredSlotsList, slots[i]) then
            local item = player:getSlotItem(slots[i])
            if item:hasAttribute(ITEM_ATTRIBUTE_CHARGES) then
                local currentCharges = item:getAttribute(ITEM_ATTRIBUTE_CHARGES)
                if currentCharges >= 1 then
                    local newCharges = currentCharges -1
                    item:setAttribute(ITEM_ATTRIBUTE_CHARGES, newCharges)
                    if newCharges == 0 then
                        -- remove item?
                    end
                end
            end
        end
    end
end

local creatureevent = CreatureEvent("onHealthChange_removeCharges")

function creatureevent.onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
    if creature:isPlayer() and attacker:getId() ~= creature:getId() then
        removeChargesFromAllEquippedItems(creature, {CONST_SLOT_RIGHT, CONST_SLOT_LEFT})-- ignore both hand slots? Or leave the table blank
    end
    return primaryDamage, primaryType, secondaryDamage, secondaryType
end

creatureevent:register()


local creatureevent = CreatureEvent("onManaChange_removeCharges")

function creatureevent.onManaChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
    if creature:isPlayer() and attacker:getId() ~= creature:getId() then
        removeChargesFromAllEquippedItems(creature, {CONST_SLOT_RIGHT, CONST_SLOT_LEFT}) -- ignore both hand slots? Or leave the table blank
    end
    return primaryDamage, primaryType, secondaryDamage, secondaryType
end

creatureevent:register()


local loginEvent = CreatureEvent("onLogin_register_removeCharges")
loginEvent:type("login")

function loginEvent.onLogin(player)
    player:registerEvent("onHealthChange_removeCharges")
    player:registerEvent("onManaChange_removeCharges")
    return true
end

loginEvent:register()
Lua Script Error: [Scripts Interface]
C:\Users\xicar\OneDrive\┴rea de Trabalho\═caro\Jogos e Lazer\Tukson Server\data\scripts\tales of tukson\chargeofitens.lua:callback
...on Server\data\scripts\tales of tukson\chargeofitens.lua:18: attempt to index local 'item' (a nil value)
stack traceback:
[C]: in function '__index'
...on Server\data\scripts\tales of tukson\chargeofitens.lua:18: in function 'removeChargesFromAllEquippedItems'
...on Server\data\scripts\tales of tukson\chargeofitens.lua:36: in function <...on Server\data\scripts\tales of tukson\chargeofitens.lua:34>


It's not working, sorry for the delay on the reply, I'm traveling for work this last days.
 
Lua Script Error: [Scripts Interface]
C:\Users\xicar\OneDrive\┴rea de Trabalho\═caro\Jogos e Lazer\Tukson Server\data\scripts\tales of tukson\chargeofitens.lua:callback
...on Server\data\scripts\tales of tukson\chargeofitens.lua:18: attempt to index local 'item' (a nil value)
stack traceback:
[C]: in function '__index'
...on Server\data\scripts\tales of tukson\chargeofitens.lua:18: in function 'removeChargesFromAllEquippedItems'
...on Server\data\scripts\tales of tukson\chargeofitens.lua:36: in function <...on Server\data\scripts\tales of tukson\chargeofitens.lua:34>


It's not working, sorry for the delay on the reply, I'm traveling for work this last days.

change
Lua:
if item:hasAttribute(ITEM_ATTRIBUTE_CHARGES) then
to
Lua:
if item and item:hasAttribute(ITEM_ATTRIBUTE_CHARGES) then
 
Thanks, its working now.

I also realise that I needed to add

For the script to remove the item when there's no charge.

Wasn't sure if you wanted them to remain at 0 charges, and then 'recharge' them like soft boots or remove them, that's why I added the green text xD

item:remove() is better, so that you aren't using the compat functions.
Here's updated code.
Lua:
local function removeChargesFromAllEquippedItems(player, ignoredSlotsList)
    for i = 1, #slots do
        if not table.contains(ignoredSlotsList, slots[i]) then
            local item = player:getSlotItem(slots[i])
            if item and item:hasAttribute(ITEM_ATTRIBUTE_CHARGES) then
                local currentCharges = item:getAttribute(ITEM_ATTRIBUTE_CHARGES)
                if currentCharges >= 1 then
                    local newCharges = currentCharges -1
                    item:setAttribute(ITEM_ATTRIBUTE_CHARGES, newCharges)
                else
                    item:remove()
                end
            end
        end
    end
end
 
local function removeChargesFromAllEquippedItems(player, ignoredSlotsList) for i = 1, #slots do if not table.contains(ignoredSlotsList, slots) then local item = player:getSlotItem(slots) if item and item:hasAttribute(ITEM_ATTRIBUTE_CHARGES) then local currentCharges = item:getAttribute(ITEM_ATTRIBUTE_CHARGES) if currentCharges >= 1 then local newCharges = currentCharges -1 item:setAttribute(ITEM_ATTRIBUTE_CHARGES, newCharges) else item:remove() end end end end end
I think it will be better if the item get destoyed and the player need to do a new one, just like itens from tibiame.
 
I'm with a little problem, can somebody help me?

I'm using the script above on this topic but I don't know if the problem is realted to it.

It doesn't matter how much charges I put on the item, it breaks as if it has only 1 charge.

On items.xml
<item id="26829" article="a" name="Soft Leather Helmet">
<attribute key="description" value="This is a light weight item, it increases your speed by 10 points. Increases your mana by 5 points" />
<attribute key="weight" value="2500" />
<attribute key="armor" value="1" />
<attribute key="slotType" value="head" />
<attribute key="maxmanapoints" value="+5"/>
<attribute key="speed" value="20" />
<attribute key="charges" value="100" />
<attribute key="showcharges" value="1" />
<attribute key="showattributes" value="1" />
</item>

In game:
You see a Soft Leather Helmet (Arm:1, speed +10)
Item Level: 0 that has 1 charge left.
It can only be wielded properly by players of level 0 or higher.
It weighs 25.00 oz.
This is a light weight item, it increases your speed by 10 points. Increases your mana by 5 points
Light Set Tier 1 [1/5]
[ Soft Leather Helmet, Soft Leather Armor, Soft Leather Legs, Soft Leather Boots, Soft Leather Spellbook]
Physical Protection +1%
Item ID: 26829
Position: 1071, 1050, 7

The same happens to weapons:

On items.xml
<item id="26676" article="a" name="Butcher Knife">
<attribute key="weight" value="700" />
<attribute key="attack" value="6" />
<attribute key="weaponType" value="sword" />
<attribute key="showattributes" value="1" />
<attribute key="charges" value="9000" />
</item>

In game
You see a Butcher Knife (Atk:6).
Item Level: 0
It can only be wielded properly by players of level 0 or higher.
It weighs 7.00 oz.
Item ID: 26676
Position: 1071, 1050, 7
Also the charge count doesn't even appear when the player looks at weapons.

Does anyone have any idea what this could be?
 
yes, how are you creating your items?


missing
<attribute key="showcharges" value="1" />

on all items that you want to display charges

I didn't know about the "<attribute key="showcharges" value="1" />", thanks a lot about this.

I'm creating the itens from a craft script I have and also I created with /i from GM and both ways the itens break with 1 hit.

My server is a custom server, focus on gettering materials from mining, harvest, skinning and itens from bosses to create the weapons and sets, so I would like for the itens to have charges so players need to keep on gettering materials and killing bosses. This script was the way I think it would be possible to achiev my goal and @Xikini was kind enought to help me out with this script, but I don't know if you guys have an different idea of how I can achiev this.
 
fixed /i

similar approach must be done in your craft script addItem part
Nice, the /i now adds the item with charges, perfect.

However, I have no idea how to add the same fix to the craft script.

data/lib/smith:
Lua:
local recipes = {
[1] = {name = "Backpack",
            options = {
            [1] = {name = "Leather Backpack", learned = false, learnStorage = 0, storage = {40000}, level = {1}, tries = 1, count = 1, id = 26516,
                needed = {
                    [1] = {name = "Soft Leather", id = 27851, count = 5}
                }
            }
        }
    },
}

local modalId = 1005
local Type = {}
local Option = {}

local training = {
    [40000] = "Basic Smithing",
    [40001] = "Advanced Smithing",
    [40002] = "Legendary Smithing",
    [40003] = "Ammunition Smithing",
    [40004] = "Amulet Smithing",
    [40005] = "Axe Smithing",
    [40006] = "Bow Smithing",
    [40007] = "Claw Smithing",
    [40008] = "Club Smithing",
    [40009] = "Crossbow Smithing",
    [40010] = "Dagger Smithing",
    [40011] = "Gun Smithing",
    [40012] = "Heavy Armor Smithing",
    [40013] = "Heavy Boots Smithing",
    [40014] = "Heavy Helmet Smithing",
    [40015] = "Heavy Legs Smithing",
    [40016] = "Light Armor Smithing",
    [40017] = "Light Boots Smithing",
    [40018] = "Light Helmet Smithing",
    [40019] = "Light Legs Smithing",
    [40020] = "Medium Armor Smithing",
    [40021] = "Medium Boots Smithing",
    [40022] = "Medium Helmet Smithing",
    [40023] = "Medium Legs Smithing",
    [40024] = "Ring Smithing",
    [40025] = "Shield Smithing",
    [40026] = "Spellbook Smithing",
    [40027] = "Staff Smithing",
    [40028] = "Sword Smithing",
}
-- Checks if player has the items required for a recipe - used for bringing the craft option back up after each craft if they have enough to do it again - enables quick, easy crafting
function Player:hasReq(recipe)
    for i = 1, #recipe.needed do
        if self:getItemCount(recipe.needed[i].id) < recipe.needed[i].count then
            return false
        end
    end
    return true
end

function Player:sendSortedWindow(type)
    local window = ModalWindow(1011, recipes[type].name, "Expand the item you want to produce to view the requirements.\nYou are trained in the following specialties:\n")
    local choices = 0
    local temp = 0
    for i = 40000, 40028 do
        if self:getCSkill(training[i]) >= 10 then
            temp = temp + 1
            window:setMessage(window:getMessage() .. training[i] .. " (" .. self:getCSkill(training[i]) .. ")\n")
        end
    end
    if temp == 0 then
        window:setMessage(window:getMessage() .. "No specialty training.\n")
    end
    for i = 1, #recipes[type].options do
        if (recipes[type].options[i].learned and self:getStorageValue(recipes[type].options[i].learnStorage) >= 1) or not recipes[type].options[i].learned then
            if recipes[type].options[i].count > 1 then
                window:addChoice(i, recipes[type].options[i].count .. " " .. recipes[type].options[i].name)
            else
                window:addChoice(i, recipes[type].options[i].name)
            end
        end
    end
    window:addButton(1, "Expand")
    window:setDefaultEnterButton(1)
    window:addButton(2, "Back")
    window:setDefaultEscapeButton(2)
    window:sendToPlayer(self)
    return true
end

function Player:sendEquipmentWindow()
    local window = ModalWindow(modalId, "Smithing", "Expand the type of item you want to craft to view the available items.\nYou are trained in the following specialties:\n")
    local choices = 0
    local temp = 0
    for i = 40000, 40028 do
        if self:getCSkill(training[i]) >= 10 then
            temp = temp + 1
            window:setMessage(window:getMessage() .. training[i] .. " (" .. self:getCSkill(training[i]) .. ")\n")
        end
    end
    if temp == 0 then
        window:setMessage(window:getMessage() .. "No specialty training.\n")
    end
    
    for i = 1, #recipes do
        local t = false
        for j = 1, #recipes[i].options do
            if (recipes[i].options[j].learned and self:getStorageValue(recipes[i].options[j].learnStorage) >= 1) or not recipes[i].options[j].learned then
                t = true
                break
            end
        end
        if t then
            window:addChoice(i, recipes[i].name)
        end
    end
    
    window:addButton(1, "Expand")
    window:setDefaultEnterButton(1)

    window:addButton(2, "Exit")
    window:setDefaultEscapeButton(2)
    window:sendToPlayer(self)
    return true
end

function Player:sendERecipeWindow(type, option)
    local window = ModalWindow(modalId + 1, recipes[type].options[option].name, "To produce this item, you need:\n")
    for i = 1, #recipes[type].options[option].needed do
        window:setMessage(window:getMessage() .. recipes[type].options[option].needed[i].count .. " " .. recipes[type].options[option].needed[i].name .. " (" .. self:getItemCount(recipes[type].options[option].needed[i].id) .. ")\n")
    end
    if recipes[type].options[option].storage then
        for i = 1, #recipes[type].options[option].storage do
            local lev = self:getCSkill(training[recipes[type].options[option].storage[i]])
            window:setMessage(window:getMessage() .. training[recipes[type].options[option].storage[i]] .. " " .. recipes[type].options[option].level[i] .. " (" .. lev .. ")\n")
        end
    end
    for i = 1, #recipes[type].options[option].needed do
        if self:getItemCount(recipes[type].options[option].needed[i].id) < recipes[type].options[option].needed[i].count then
            return window:addButton(2, "Back"), window:setDefaultEscapeButton(2), window:setDefaultEnterButton(2), window:sendToPlayer(self)
        end
    end
    for i = 1, #recipes[type].options[option].storage do
        if self:getCSkill(training[recipes[type].options[option].storage[i]]) < recipes[type].options[option].level[i] then
            return window:addButton(2, "Back"), window:setDefaultEscapeButton(2), window:setDefaultEnterButton(2), window:sendToPlayer(self)
        end
    end
    window:addButton(1, "Make It!")
    window:setDefaultEnterButton(1)
    window:addButton(2, "Back")
    window:setDefaultEscapeButton(2)
    window:sendToPlayer(self)
    return true
end

function Player:sortedWindowChoice(windowId, buttonId, choiceId)
    local p = self:getGuid()
    if windowId == 1011 then
        if buttonId == 1 then
            Option[p] = choiceId
            self:sendERecipeWindow(Type[p], Option[p])
            return true
        elseif buttonId == 2 then
            self:sendEquipmentWindow()
            return true
        end
        return false
    end
    return false
end

function Player:equipmentWindowChoice(windowId, buttonId, choiceId)
    local p = self:getGuid()
    if windowId == modalId then
        if buttonId == 1 then
            Type[p] = choiceId
            self:sendSortedWindow(Type[p])
            return true
        else
            Type[p] = nil
            Option[p] = nil
            return false
        end
    end
    return false
end

function Player:eRecipeWindowChoice(windowId, buttonId, choiceId)
    local p = self:getGuid()
    if windowId == modalId + 1 then
        if buttonId == 1 then
            local rand = math.random(1,100000)
            local half = false
            local chance = (cSkills[training[recipes[Type[p]].options[Option[p]].storage[1]]].bonus * self:getCSkill(training[recipes[Type[p]].options[Option[p]].storage[1]])) * 100
            if rand < chance * 1000 then
                half = true
            end
            for i = 1, #recipes[Type[p]].options[Option[p]].needed do
                if half then
                    self:removeItem(recipes[Type[p]].options[Option[p]].needed[i].id, math.ceil(recipes[Type[p]].options[Option[p]].needed[i].count / 2))
                else
                    self:removeItem(recipes[Type[p]].options[Option[p]].needed[i].id, recipes[Type[p]].options[Option[p]].needed[i].count)
                end
            end
            self:addItem(recipes[Type[p]].options[Option[p]].id, recipes[Type[p]].options[Option[p]].count)
            if half then
                self:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have crafted " .. recipes[Type[p]].options[Option[p]].count .. " " .. recipes[Type[p]].options[Option[p]].name .. " at half the usual cost!")
            else
                self:sendTextMessage(MESSAGE_INFO_DESCR, "You have crafted " .. recipes[Type[p]].options[Option[p]].count .. " " .. recipes[Type[p]].options[Option[p]].name .. "!")
            end
            for i = 1, #recipes[Type[p]].options[Option[p]].storage do
                self:addCSkillTries(training[recipes[Type[p]].options[Option[p]].storage[i]], recipes[Type[p]].options[Option[p]].tries)
            end
            if recipes[Type[p]].options[Option[p]].set then
                if self:getStorageValue(sets[recipes[Type[p]].options[Option[p]].set].pieces[recipes[Type[p]].options[Option[p]].piece].storage) ~= 1 then
                    self:setStorageValue(sets[recipes[Type[p]].options[Option[p]].set].pieces[recipes[Type[p]].options[Option[p]].piece].storage, 1)
                end
                local tempStore = true
                for i = 1, #sets[recipes[Type[p]].options[Option[p]].set].pieces do
                    if self:getStorageValue(sets[recipes[Type[p]].options[Option[p]].set].pieces[recipes[Type[p]].options[Option[p]].piece].storage) ~= 1 then
                        tempStore = false
                    end
                end
                if tempStore then
                    self:addAchievement(sets[recipes[Type[p]].options[Option[p]].set].achievement)
                end
            end
            return self:hasReq(recipes[Type[p]].options[Option[p]]) and self:sendERecipeWindow(Type[p], Option[p]) or self:sendSortedWindow(Type[p])
        elseif buttonId == 2 then
            self:sendSortedWindow(Type[p])
        end
        return false
    end
    
    return false
end


Can you help out?
 
Lua:
self:addItem(recipes[Type[p]].options[Option[p]].id, recipes[Type[p]].options[Option[p]].count)
Lua:
local item = self:addItem(recipes[Type[p]].options[Option[p]].id, recipes[Type[p]].options[Option[p]].count)
if item:hasAttribute(ITEM_ATTRIBUTE_CHARGES) then
    item:setAttribute(ITEM_ATTRIBUTE_CHARGES, ItemType(recipes[Type[p]].options[Option[p]].id):getCharges())
end
 
Lua:
self:addItem(recipes[Type[p]].options[Option[p]].id, recipes[Type[p]].options[Option[p]].count)
Lua:
local item = self:addItem(recipes[Type[p]].options[Option[p]].id, recipes[Type[p]].options[Option[p]].count)
if item:hasAttribute(ITEM_ATTRIBUTE_CHARGES) then
    item:setAttribute(ITEM_ATTRIBUTE_CHARGES, ItemType(recipes[Type[p]].options[Option[p]].id):getCharges())
end
Thank you, it's all working fine.
 
Back
Top