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

Remove Player Condition Attributes

Allan Silva

Member
Joined
May 30, 2018
Messages
39
Solutions
1
Reaction score
7
Canary - Version 3.1.1
OTCv8 - 11.00
System Attributes:
[TFS 1.X] Rarity Rolls & Custom Attributes Library (https://otland.net/threads/tfs-1-x-rarity-rolls-custom-attributes-library.268888/)

Hi everyone!
I'm adding the rarity script to server. The script is working on canary server, creatures are dropping rare items, with their appropriate attributes, however with some bug. When I add or remove item from the inventory character, they sometimes add attributes and sometimes they don't, same problem occurs when removing them (while I'm equipping and unequipping item).

Example of bug:

item used in example.
1701641704441.png


what's happening with attributes when equip/dequip item.


Note: When I repeat (equip/dequip) for 5 times the attributes are reset. If I relog character, the attributes are also reset (if item is not equipped)
I reviewed entire implementation of rarity system to ensure that there were no errors during migration to server. I did some tests on part where script adds attributes to character.

Spoiler of some part of script "lib/core/attributes.lua"
attributes.lua

Lua:
function rollCondition(player, item, slot)
    local attributes = {
         [1] = {"%[" .. stats[25].attribute.name .. ": ", CONDITION_PARAM_SKILL_SWORD}, -- "[Sword Skill: "
         [2] = {"%[" .. stats[26].attribute.name .. ": ", CONDITION_PARAM_SKILL_AXE},
         [3] = {"%[" .. stats[27].attribute.name .. ": ", CONDITION_PARAM_SKILL_CLUB},
         [4] = {"%[" .. stats[28].attribute.name .. ": ", CONDITION_PARAM_SKILL_MELEE},
         [5] = {"%[" .. stats[29].attribute.name .. ": ", CONDITION_PARAM_SKILL_DISTANCE},
         [6] = {"%[" .. stats[30].attribute.name .. ": ", CONDITION_PARAM_SKILL_SHIELD},
         [7] = {"%[" .. stats[31].attribute.name .. ": ", CONDITION_PARAM_STAT_MAGICPOINTS},
         [8] = {"%[" .. stats[32].attribute.name .. ": ", CONDITION_PARAM_STAT_MAXHITPOINTS},
         [9] = {"%[" .. stats[33].attribute.name .. ": ", CONDITION_PARAM_STAT_MAXMANAPOINTS},
        [10] = {"%[" .. stats[34].attribute.name .. ": ", CONDITION_PARAM_STAT_MAXHITPOINTSPERCENT, percent = true, absolute = true},
        [11] = {"%[" .. stats[35].attribute.name .. ": ", CONDITION_PARAM_STAT_MAXMANAPOINTSPERCENT, percent = true, absolute = true},
        [12] = {"%[" .. stats[11].attribute.name .. ": ", CONDITION_PARAM_SKILL_CRITICAL_HIT_DAMAGE, percent = true, absolute = true},
        [13] = {"%[" .. stats[10].attribute.name .. ": ", CONDITION_PARAM_SKILL_CRITICAL_HIT_CHANCE, percent = true},
        [14] = {"%[" .. stats[36].attribute.name .. ": ", CONDITION_PARAM_SKILL_LIFE_LEECH_CHANCE, percent = true},
        [15] = {"%[" .. stats[37].attribute.name .. ": ", CONDITION_PARAM_SKILL_LIFE_LEECH_AMOUNT, percent = true},
        [16] = {"%[" .. stats[38].attribute.name .. ": ", CONDITION_PARAM_SKILL_MANA_LEECH_CHANCE, percent = true},
        [17] = {"%[" .. stats[39].attribute.name .. ": ", CONDITION_PARAM_SKILL_MANA_LEECH_AMOUNT, percent = true},
    }
    local itemDesc = item:getAttribute(ITEM_ATTRIBUTE_DESCRIPTION)
    for k = 1,#attributes do
        local skillBonus = 0 -- reset
        local attributeSearchValue = "%+(%d+)%]" -- "+10]"
        if attributes[k].percent ~= nil then
            attributeSearchValue = "%+(%d+)%%%]" -- "+10%]"
            if attributes[k].absolute ~= nil then
                skillBonus = 100 -- These conditions require absolutes (108%, 145% etc.)
            end
        end
        local attributeString = attributes[k][1] .. attributeSearchValue -- "%[Attack: %+(%d+)%]"
        if string.match(itemDesc, attributeString) ~= nil then -- "[Attack: +10]"
            local offset = (10 * k) + slot -- ((CONST_SLOT_LAST) * k) + slot
            local skillBonus = skillBonus + tonumber(string.match(itemDesc, attributeString)) -- Raw (%d+) value
            
            -- (!) Comment this code out if you want to use CHANCE/AMOUNT rolls (they will need to be rolled together)
            -- Leech amount is not used, set to 100%
            -- Crit amount is not used, set to 100%
            if k == 13 or k == 15 or k == 17 then
                local j = k - 1
                if player:getCondition(CONDITION_ATTRIBUTES, CONDITIONID_COMBAT, (10 * j) + slot) == nil then
                    local condition = Condition(CONDITION_ATTRIBUTES)
                    condition:setParameter(CONDITION_PARAM_SUBID, (10* j) + slot)
                    condition:setParameter(CONDITION_PARAM_TICKS, -1)
                    condition:setParameter(attributes[j][2], 100) -- 100%
                    print("before add - Condition 1 exists:", player:getCondition(CONDITION_ATTRIBUTES, CONDITIONID_COMBAT, (10 * j) + slot))
                    player:addCondition(condition)
                    print("After add - Condition 1 exists:", player:getCondition(CONDITION_ATTRIBUTES, CONDITIONID_COMBAT, (10 * j) + slot))
                else
                    print("before removal - Condition 1 exists:", player:getCondition(CONDITION_ATTRIBUTES, CONDITIONID_COMBAT, (10 * j) + slot))
                    player:removeCondition(CONDITION_ATTRIBUTES, CONDITIONID_COMBAT, (10 * j) + slot)
                    print("After removal - Condition 1 exists:", player:getCondition(CONDITION_ATTRIBUTES, CONDITIONID_COMBAT, (10 * j) + slot))
                end
            end
            
            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)
                print("before add - Condition 2 exists:", player:getCondition(CONDITION_ATTRIBUTES, CONDITIONID_COMBAT, offset))
                player:addCondition(condition)
                print("After add - Condition 2 exists:", player:getCondition(CONDITION_ATTRIBUTES, CONDITIONID_COMBAT, offset))
            else
                print("before removal - Condition 2 exists:", player:getCondition(CONDITION_ATTRIBUTES, CONDITIONID_COMBAT, offset))
                player:removeCondition(CONDITION_ATTRIBUTES, CONDITIONID_COMBAT, offset)
                print("After removal - Condition 2 exists:", player:getCondition(CONDITION_ATTRIBUTES, CONDITIONID_COMBAT, offset))
            end
        end
    end
end


function itemAttributes(player, item, slot, equip)
    -- Check if item is rolled
    if item:getArticle() ~= "" then
        if item:getArticle():find("rare") or item:getArticle():find("epic") or item:getArticle():find("legendary") then
            local appropriateSlot = false
            local slotType = ItemType(item.itemid):getSlotPosition()
            -- What slots do we want to check? this ignores CONST_SLOT_AMMO and CONST_SLOT_BACKPACK
            local raritySlots = {
                [CONST_SLOT_LEFT] = {validPositions = {[1] = SLOTP_LEFT,[2] = SLOTP_RIGHT,[3] = SLOTP_TWO_HAND}},
                [CONST_SLOT_RIGHT] = {validPositions = {[1] = SLOTP_LEFT,[2] = SLOTP_RIGHT,[3] = SLOTP_TWO_HAND}},
                [CONST_SLOT_HEAD] = {validPositions = {[1] = SLOTP_HEAD}},
                [CONST_SLOT_NECKLACE] = {validPositions = {[1] = SLOTP_NECKLACE}},
                [CONST_SLOT_ARMOR] = {validPositions = {[1] = SLOTP_ARMOR}},
                [CONST_SLOT_LEGS] = {validPositions = {[1] = SLOTP_LEGS}},
                [CONST_SLOT_FEET] = {validPositions = {[1] = SLOTP_FEET}},
                [CONST_SLOT_RING] = {validPositions = {[1] = SLOTP_RING}}
            }
            -- If slot is one that we check
            if raritySlots[slot] ~= nil then
                -- Validate that item is being equipped to the right slot
                if slot == CONST_SLOT_LEFT or slot == CONST_SLOT_RIGHT then
                    local weapon = ItemType(item.itemid):getWeaponType()
                    if weapon ~= WEAPON_NONE then
                        if weapon ~= WEAPON_AMMO then
                            appropriateSlot = true
                        end
                    end
                else
                    for i = 1,#raritySlots[slot].validPositions do
                        if bit.band(slotType, raritySlots[slot].validPositions[i]) ~= 0 then
                            appropriateSlot = true
                            break
                        end
                    end
                end
                if appropriateSlot then -- Item is in the wrong slotType
                    -- Checks have all passed, run apply/remove attribute
                    rollCondition(player, item, slot)
                end
            end
        end
    end
end

Abobe are two functions that I believe do this part of add and remove attributes in character. In the function rollCondition I put prints to try to understand what was happening and I would like your opinion. Below, the print when I only equip item once.

when I only equip item once.
1701643329510.png

Note: why the script executed twice? Why at same time that the attribute is added, is it also removed (last value is returned null), since it was only equipped once?

Could anyone help and teach me how to solve this problem? Any suggestion is valid, I will be testing your opinions. Thanks!
 
Solution
Try posting your topic on Discord (Canary) here. Almost no one uses Canary because it's quite different from TFS and can be difficult to handle. So, post your questions on Discord. In just a few hours, someone may resolve your request.

Thank for help, I joined the discord group.

@Mateus Robeerto - otland isn't tfsland, there are people here that can and will offer support for canary!

@Allan Silva - could you please run a little test with canary to see if the onEquip & on onDeEquip fire twice each time typically? As in, remove this custom system, and see if it still happens.
The reason I am asking is because there was (or perhaps still is) a bug with...
Try posting your topic on Discord (Canary) here. Almost no one uses Canary because it's quite different from TFS and can be difficult to handle. So, post your questions on Discord. In just a few hours, someone may resolve your request.

 
@Mateus Robeerto - otland isn't tfsland, there are people here that can and will offer support for canary!

@Allan Silva - could you please run a little test with canary to see if the onEquip & on onDeEquip fire twice each time typically? As in, remove this custom system, and see if it still happens.
The reason I am asking is because there was (or perhaps still is) a bug with TFS (which canary was originally forked from) that caused this.

People found a few workarounds like setting and checking storages onEquip/onDeEquip to prevent the second fire from working. This might be an option for you. (You could also check if the slot item exists and only fire the rest of the function if it does or does not etc.)
 
You can't blame anyone here for not being familiar with canary. It's horrifically unorganised and the quality of scripts is improving, but currently overall dreadful. xD
 
Try posting your topic on Discord (Canary) here. Almost no one uses Canary because it's quite different from TFS and can be difficult to handle. So, post your questions on Discord. In just a few hours, someone may resolve your request.

Thank for help, I joined the discord group.

@Mateus Robeerto - otland isn't tfsland, there are people here that can and will offer support for canary!

@Allan Silva - could you please run a little test with canary to see if the onEquip & on onDeEquip fire twice each time typically? As in, remove this custom system, and see if it still happens.
The reason I am asking is because there was (or perhaps still is) a bug with TFS (which canary was originally forked from) that caused this.

People found a few workarounds like setting and checking storages onEquip/onDeEquip to prevent the second fire from working. This might be an option for you. (You could also check if the slot item exists and only fire the rest of the function if it does or does not etc.)
Thanks for trying to help. I used information about equip/deequip to understant canary code. I agree with you, site is called otland and not tfsland. It's really sad that there are people who don't want to answer questions because it's a different server than TFS, since some problems can be easily fixed, regardless of whether it's TFS or not. I solved problem, below is the update.

You can't blame anyone here for not being familiar with canary. It's horrifically unorganised and the quality of scripts is improving, but currently overall dreadful. xD
This is your opinion. I believe that all servers have their problems during their development, and I see programmers working faithfully on the canary project in order to solve these problems. No one is obliged to answer questions about canary codes, but this community have great programmers that resolve small questions without much effort.


SOLUTION:

It is not necessary to add the following script lines in src/player.cpp
C++:
g_events->eventPlayerOnInventoryUpdate(this, thing->getItem(), static_cast<slots_t>(index), true);

g_events->eventPlayerOnInventoryUpdate(this, thing->getItem(), static_cast<slots_t>(index), false);

The reason is that they are already written in moviment.cpp (on canary code). However, even when item is equipped, the same action occurs twice and the reason for this Michael Orsino said in your comment.
 
Solution
Back
Top