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

Solved Optimize elseif script.

OTcreator

Active Member
Joined
Feb 14, 2022
Messages
425
Solutions
1
Reaction score
44
Hello.
Who can optimize this script?
I can't add this on CODE becouse have to much characters.
Script in attachment.
 

Attachments

Hello.
Who can optimize this script?
I can't add this on CODE becouse have to much characters.
Script in attachment.


The shortest way is to call the storages by an array of them from 50001 to 50050 (or ur expected range) that is one of the first things you can shorten, for the rest you are already using calls to different items as well as different storages, to the being a toggle there isn't much you can do to shorten it unless it is to use different toggle for different addons with shorter scripts. What I do not understand is why you have so many Ends at the end if it is not necessary. You could also make a global call to the names of the addons to show the message so you use 1 single message for all of them where you would only change the name of the item in question, the same for the effect and for the storage you can use it globally, just change the variable.

It's the best you could do to shorten it. And I would advise you to add an exhaust to use the lever of at least 2 seconds so you can not Lagging your server if that is the problem you have when using the script.
 
How did you even managed to add there something without formatting that properly :)
Just an idea (need some adjustments):
Lua:
local config = {
    pricePos = Position({ x=1918, y=1232, z=5 }),
    addonName = { "first", "second" }
}

local outfits = {
    [50001] = {
        items = {
            { id = 5890, count = 100 }
        },
        outfit = { 128, 136 },
        addon = 1
    }
}

local removePrice = function (tile, items)
    for _, item in ipairs(items) do
        local count = item.count or 1
        local item = tile:getItemById(item.id, count)
        if not item then
            return false
        end

        item:remove(count)
    end

    return true
end

local checkPrice = function(tile, items)
    for _, item in ipairs(items) do
        local count = item.count or 1
        if not tile:getItemById(item.id, count) then
            return false
        end
    end

    return true
end

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if not player:isPremium() then
        player:sendTextMessage(MESSAGE_INFO_DESCR, "Sorry, only premium players may use addon lever.")
        return true
    end

    local sex = player:getSex()
    local pricePos = config.pricePos
    local priceTile = Tile(pricePos)

    for sId, o in pairs(outfits) do
        local hasOutfit = player:getStorageValue(sId) > 0
        if not hasOutfit and checkPrice(priceTile, o.items) and removePrice(priceTile, o.items) then
            local lookType = o.outfit[sex + 1]
            local outfit = Outfit(lookType)
            outfit.lookAddons = outfit.addon or 1
            local addonName = config.addonName[outfit.lookAddons] or ""
            pricePos:sendMagicEffect(CONST_ME_HITBYFIRE)
            player:setStorageValue(sId, 1)
            player:addOutfitAddon(lookType, outfit.lookAddons)
            player:sendTextMessage(MESSAGE_INFO_DESCR, ("You have unlocked %s %s addon!"):format(addonName, outfit.name))
            return true
        end
    end

    player:say("You don't have needed items or you already have unlocked this addon!", TALKTYPE_ORANGE_1, false, player, pricePos)
    return true
end


// Edit:
As I used TFS 1.x API you need to adjust the code to work on TFS 0.x as you didn't specified which exactly I can't write a code that would work for TFS 0.2-0.4

For 0.x check:
Lua:
local config = {
    pricePos = { x=1918, y=1232, z=5 },
    addonName = { "first", "second" }
}

local outfits = {
    [50001] = {
        items = {
            { id = 2160, count = 100 }
        },
        name = "Citizen",
        outfit = { 128, 136 },
        addon = 1
    }
}

local removePrice = function (pos, items)
    for _, item in ipairs(items) do
        local count = item.count or 1
        local item = getTileItemById(pos, item.id)
        if not item then
            return false
        end

        doRemoveItem(item.uid, count)
    end

    return true
end

local checkPrice = function(pos, items)
    for _, item in ipairs(items) do
        local count = item.count or 1
        local item = getTileItemById(pos, item.id)
        if not item or item.type < count then
            return false
        end
    end

    return true
end

function onUse(cid, item, fromPosition, itemEx, toPosition)
    if not isPremium(cid) then
        doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "Sorry, only premium players may use addon lever.")
        return true
    end

    local sex = getPlayerSex(cid)
    local pricePos = config.pricePos

    for sId, o in pairs(outfits) do
        local hasOutfit = getPlayerStorageValue(cid, sId) > 0
        if not hasOutfit and checkPrice(pricePos, o.items) and removePrice(pricePos, o.items) then
            local lookType = o.outfit[sex + 1]
            local addon = o.addon or 1
            local addonName = config.addonName[addon] or ""

            doSendMagicEffect(pricePos, CONST_ME_HITBYFIRE)
            setPlayerStorageValue(cid, sId, 1)
            doPlayerAddOutfit(cid, lookType, addon)
            doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "You have unlocked " .. addonName .. " " .. o.name .. " addon!")
            return true
        end
    end

    doCreatureSay(cid, "You don't have needed items or you already have unlocked this addon!", TALKTYPE_ORANGE_1, false, cid, pricePos)
    return true
end
 
Last edited:
How did you even managed to add there something without formatting that properly :)
Just an idea (need some adjustments):
Lua:
local config = {
    pricePos = Position({ x=1918, y=1232, z=5 }),
    addonName = { "first", "second" }
}

local outfits = {
    [50001] = {
        items = {
            { id = 5890, count = 100 }
        },
        outfit = { 128, 136 },
        addon = 1
    }
}

local removePrice = function (tile, items)
    for _, item in ipairs(items) do
        local count = item.count or 1
        local item = tile:getItemById(item.id, count)
        item:remove(count)
    end

    return true
end

local checkPrice = function(tile, items)
    for _, item in ipairs(items) do
        local count = item.count or 1
        if not tile:getItemById(item.id, count) then
            return false
        end
    end

    return true
end

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if not player:isPremium() then
        player:sendTextMessage(MESSAGE_INFO_DESCR, "Sorry, only premium players may use addon lever.")
        return true
    end

    local sex = player:getSex()
    local pricePos = config.pricePos
    local priceTile = Tile(pricePos)

    for sId, o in pairs(outfits) do
        local hasOutfit = player:getStorageValue(sId) > 0
        if not hasOutfit and checkPrice(priceTile, o.items) and removePrice(priceTile, o.items) then
            local lookType = o.outfit[sex]
            local outfit = Outfit(lookType)
            outfit.lookAddons = outfit.addon or 1
            local addonName = config.addonName[outfit.lookAddons] or ""
            pricePos:sendMagicEffect(CONST_ME_HITBYFIRE)
            player:setStorageValue(sId, 1)
            player:addOutfitAddon(lookType, outfit.lookAddons)
            player:sendTextMessage(MESSAGE_INFO_DESCR, ("You have unlocked %s %s addon!"):format(addonName, outfit.name))
            return true
        end
    end

    player:say("You don't have needed items or you already have unlocked this addon!", TALKTYPE_ORANGE_1, false, player, pricePos)
    return true
end


// Edit:
As I used TFS 1.x API you need to adjust the code to work on TFS 0.x as you didn't specified which exactly I can't write a code that would work for TFS 0.2-0.4

For 0.x check:
Lua:
local config = {
    pricePos = { x=1918, y=1232, z=5 },
    addonName = { "first", "second" }
}

local outfits = {
    [50001] = {
        items = {
            { id = 2160, count = 100 }
        },
        name = "Citizen",
        outfit = { 128, 136 },
        addon = 1
    }
}

local removePrice = function (pos, items)
    for _, item in ipairs(items) do
        local count = item.count or 1
        local item = getTileItemById(pos, item.id)
        doRemoveItem(item.uid, count)
    end

    return true
end

local checkPrice = function(pos, items)
    for _, item in ipairs(items) do
        local count = item.count or 1
        local item = getTileItemById(pos, item.id)
        if not item or item.type < count then
            return false
        end
    end

    return true
end

function onUse(cid, item, fromPosition, itemEx, toPosition)
    if not isPremium(cid) then
        doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "Sorry, only premium players may use addon lever.")
        return true
    end

    local sex = getPlayerSex(cid)
    local pricePos = config.pricePos

    for sId, o in pairs(outfits) do
        local hasOutfit = getPlayerStorageValue(cid, sId) > 0
        if not hasOutfit and checkPrice(pricePos, o.items) and removePrice(pricePos, o.items) then
            local lookType = o.outfit[sex]
            local addon = o.addon or 1
            local addonName = config.addonName[addon] or ""

            doSendMagicEffect(pricePos, CONST_ME_HITBYFIRE)
            setPlayerStorageValue(cid, sId, 1)
            doPlayerAddOutfit(cid, lookType, addon)
            doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "You have unlocked " .. addonName .. " " .. o.name .. " addon!")
            return true
        end
    end

    doCreatureSay(cid, "You don't have needed items or you already have unlocked this addon!", TALKTYPE_ORANGE_1, false, cid, pricePos)
    return true
end

TFS 1.4.2


Lua Script Error: [Action Interface]
data/actions/scripts/custom/others/addon_lever.lua:eek:nUse
data/actions/scripts/custom/others/addon_lever.lua:53: attempt to index local 'outfit' (a nil value)
stack traceback:
[C]: in function '__index'
data/actions/scripts/custom/others/addon_lever.lua:53: in function <data/actions/scripts/custom/others/addon_lever.lua:38>
 
TFS 1.4.2


Lua Script Error: [Action Interface]
data/actions/scripts/custom/others/addon_lever.lua:eek:nUse
data/actions/scripts/custom/others/addon_lever.lua:53: attempt to index local 'outfit' (a nil value)
stack traceback:
[C]: in function '__index'
data/actions/scripts/custom/others/addon_lever.lua:53: in function <data/actions/scripts/custom/others/addon_lever.lua:38>

You will always need to check if the item exists or not before using the lever as well as the correct looktype.

Try:
Lua:
local config = {
    pricePos = Position({ x=1918, y=1232, z=5 }),
    addonName = { "first", "second" }
}

local outfits = {
    [50001] = {
        items = {
            { id = 5890, count = 100 }
        },
        outfit = { 128, 136 },
        addon = 1
    }
}

local removePrice = function(tile, items)
    for _, item in ipairs(items) do
        local count = item.count or 1
        local item = tile:getItemById(item.id, count)
        if item then
            item:remove(count)
        else
            return false
        end
    end
    return true
end

local checkPrice = function(tile, items)
    for _, item in ipairs(items) do
        local count = item.count or 1
        if not tile:getItemById(item.id, count) then
            return false
        end
    end
    return true
end

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if not player:isPremium() then
        player:sendTextMessage(MESSAGE_INFO_DESCR, "Sorry, only premium players may use addon lever.")
        return true
    end

    local sex = player:getSex()
    local pricePos = config.pricePos
    local priceTile = Tile(pricePos)

    for sId, o in pairs(outfits) do
        local hasOutfit = player:getStorageValue(sId) > 0
        if not hasOutfit and checkPrice(priceTile, o.items) and removePrice(priceTile, o.items) then
            local lookType = o.outfit[sex]
            if lookType then
                local outfit = Outfit(lookType)
                outfit.lookAddons = outfit.addon or 1
                local addonName = config.addonName[outfit.lookAddons] or ""
                pricePos:sendMagicEffect(CONST_ME_HITBYFIRE)
                player:setStorageValue(sId, 1)
                player:addOutfitAddon(lookType, outfit.lookAddons)
                player:sendTextMessage(MESSAGE_INFO_DESCR, ("You have unlocked %s %s addon!"):format(addonName, outfit.name))
                return true
            end
        end
    end

    player:say("You don't have needed items or you already have unlocked this addon!", TALKTYPE_ORANGE_1, false, player, pricePos)
    return true
end
 
I just tested it, and it's working fine. I liked this Avalanca Addon. I'll put it on my server

Revscriptsys​

Lua:
local action = Action()

function action.onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if item.actionid == 18563 then
        local config = {
            pricePos = { x = 1918, y = 1232, z = 5 },
            addonName = { "first", "second" }
        }

        local outfits = {
            [50001] = {
                items = {
                    { id = 5890, count = 100 }
                },
                outfit = {
                    [PLAYERSEX_FEMALE] = 128,
                    [PLAYERSEX_MALE] = 136,   
                },
                addon = 1
            }
        }

        local removePrice = function(tile, items)
            local tileItems = tile:getItems()
            local itemFound = false

            for _, item in ipairs(items) do
                local count = item.count or 1
                itemFound = false

                for _, tileItem in ipairs(tileItems) do
                    if tileItem:getId() == item.id and count > 0 then
                        local removeCount = math.min(count, tileItem:getCount())
                        count = count - removeCount
                        tileItem:remove(removeCount)
                        itemFound = true
                    end
                end

                if not itemFound then
                    print("Item not found:", item.id)
                    return false
                end
            end

            return true
        end

        local checkPrice = function(tile, items)
            if not tile then
                return false
            end

            for _, item in ipairs(items) do
                local count = item.count or 1
                if not tile:getItemById(item.id, count) then
                    return false
                end
            end
            return true
        end

        if not player or not item then
            return false
        end

        if not player:isPremium() then
            player:sendTextMessage(MESSAGE_INFO_DESCR, "Sorry, only premium players may use addon lever.")
            return true
        end

        local sex = player:getSex()
        local pricePos = config.pricePos
        local priceTile = Tile(pricePos)

        for sId, o in pairs(outfits) do
            local hasOutfit = player:getStorageValue(sId) > 0
            if not hasOutfit and checkPrice(priceTile, o.items) then
                if removePrice(priceTile, o.items) then
                    local lookType = o.outfit[sex]
                    if lookType then
                        local outfit = Outfit(lookType)
                        outfit.lookAddons = o.addon or 1
                        local addonName = config.addonName[outfit.lookAddons] or ""
                        priceTile:getPosition():sendMagicEffect(CONST_ME_HITBYFIRE)
                        player:setStorageValue(sId, 1)
                        player:addOutfitAddon(lookType, outfit.lookAddons)
                        player:sendTextMessage(MESSAGE_INFO_DESCR, ("You have unlocked %s %s addon!"):format(addonName, outfit.name))
                        return true
                    end
                else
                    player:say("You don't have the required items!", TALKTYPE_ORANGE_1, false, player, priceTile:getPosition())
                    return true
                end
            end
        end

        player:say("You don't have needed items or you already have unlocked this addon!", TALKTYPE_ORANGE_1, false, player, priceTile:getPosition())
        return true
    end

    return false
end

action:aid(18563)
action:register()
 
@NvSo It's not a problem with check, if it's configured correctly it would work.
Problem is that arrays in lua are indexed from 1 and player sex is 0/1.
Thus it has to be changed to either work like:
Lua:
outfit = {
    [PLAYERSEX_FEMALE] = 136,
    [PLAYERSEX_MALE] = 128
}

local outfit = o.outfit[sex]
or simply:
Lua:
local outfit = o.outfit[sex + 1]

Additional check in removePrice won't hurt but as it's done just after checkPrice it's almost certain that item is still there but yea won't hurt to check.
Edit: I've applied necessary changes
 
@NvSo It's not a problem with check, if it's configured correctly it would work.
Problem is that arrays in lua are indexed from 1 and player sex is 0/1.
Thus it has to be changed to either work like:
Lua:
outfit = {
    [PLAYERSEX_FEMALE] = 136,
    [PLAYERSEX_MALE] = 128
}

local outfit = o.outfit[sex]
or simply:
Lua:
local outfit = o.outfit[sex + 1]

Additional check in removePrice won't hurt but as it's done just after checkPrice it's almost certain that item is still there but yea won't hurt to check.
Edit: I've applied necessary changes

I got the script from @NvSo and tested it. There was an error in the "title" part. So, I corrected some things and adapted it to RevScripts, I tested it and it worked.


I'm loving learning revscripts :)
 
Last edited:
@Mateus Robeerto Cool that you managed to make it work ;)
few remarks:
  • once some revscript is registered to single aid/uid you could get rid of the check in onUse as item.actionid == 18563 would always be true
  • consts such as config can be defined outside onUse also
  • removing items of same ID in chunks is nice but you could limit iterations with use of getItemById in a loop *
  • getItemById(id, subType) for stackable items it comapres count, but does that work for count > max (100 pcs)?

*Rather optional idea to prevent iteration over some trash items (if present) but it'd produce more load on C++ side so not worth probably.
But in case someone specifies the same id twice (or more than one item) in items you'd need to evaluate local tileItems = tile:getItems() in every itterations to filter out removed items.

Good job ;)
 
Last edited:
What you said seemed to make sense, so I went to check it out and realized it was true. I made some more necessary corrections and changes, tested it and it worked fine, without any errors in the console. Not sure if the script is safe or if it can be optimized.


Lua:
local ITEM_ID = 5890
local MAX_COUNT = 100

local config = {
    pricePos = { x = 734, y = 595, z = 6 },
    addonName = { "first", "second" }
}

local PLAYERSEX_FEMALE = 0
local PLAYERSEX_MALE = 1

local outfits = {
    [80001] = {
        items = {
            { id = ITEM_ID, count = MAX_COUNT }
        },
        outfit = {
            [PLAYERSEX_FEMALE] = 136,
            [PLAYERSEX_MALE] = 128,   
        },
        addon = 1
    }
}

local removePrice = function(tile, items)
    local tileItems = tile:getItems()
    local itemFound = false

    for _, item in ipairs(items) do
        local count = item.count or 1
        itemFound = false

        if count <= MAX_COUNT then
            local tileItem = tile:getItemById(item.id, count)
            if tileItem then
                tileItem:remove()
                itemFound = true
            end
        else
            local remainingCount = count
            repeat
                local tileItem = tile:getItemById(item.id)
                if tileItem then
                    local removeCount = math.min(remainingCount, tileItem:getCount())
                    tileItem:remove(removeCount)
                    remainingCount = remainingCount - removeCount
                else
                    break
                end
            until remainingCount <= 0

            if remainingCount > 0 then
                print("Item not found:", item.id)
                return false
            end

            itemFound = true
        end

        if not itemFound then
            print("Item not found:", item.id)
            return false
        end
    end

    return true
end

local checkPrice = function(tile, items)
    if not tile then
        return false
    end

    for _, item in ipairs(items) do
        local count = item.count or 1
        if not tile:getItemById(item.id, count) then
            return false
        end
    end
    return true
end

local action = Action()

function action.onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if not player or not item then
        return false
    end

    if not player:isPremium() then
        player:sendTextMessage(MESSAGE_INFO_DESCR, "Sorry, only premium players may use addon lever.")
        return true
    end

    local sex = player:getSex()
    local pricePos = config.pricePos
    local priceTile = Tile(pricePos)

    for sId, o in pairs(outfits) do
        local hasOutfit = player:getStorageValue(sId) > 0
        if not hasOutfit and checkPrice(priceTile, o.items) then
            if removePrice(priceTile, o.items) then
                local lookType = o.outfit[sex]
                if lookType then
                    local outfit = Outfit(lookType)
                    outfit.lookAddons = o.addon or 1
                    local addonName = config.addonName[outfit.lookAddons] or ""
                    priceTile:getPosition():sendMagicEffect(CONST_ME_HITBYFIRE)
                    player:setStorageValue(sId, 1)
                    player:addOutfitAddon(lookType, outfit.lookAddons)
                    player:sendTextMessage(MESSAGE_INFO_DESCR, ("You have unlocked %s %s addon!"):format(addonName, outfit.name))
                    return true
                end
            else
                player:say("You don't have the required items!", TALKTYPE_ORANGE_1, false, player, priceTile:getPosition())
                return true
            end
        end
    end

    player:say("You have already unlocked this addon!", TALKTYPE_ORANGE_1, false, player, priceTile:getPosition())
    return true
end

action:aid(18563)
action:register()
 
Hmm not sure but maybe something like that (as anyway separate item count won't be grater that max possible):
Lua:
local removePrice = function (pos, items)
    local tile = Tile(pos)
    for _, item in ipairs(items) do
        local remainingCount = item.count or 1
        repeat
            local tileItem = tile:getItemById(item.id)
            if not tileItem then
                break
            end

            local removeCount = math.min(remainingCount, tileItem:getCount())
            tileItem:remove(removeCount)
            remainingCount = remainingCount - removeCount
        until remainingCount <= 0

        if remainingCount > 0  then
            print("Item not found:", item.id)
            return false
        end
    end

    return true
end

But anyway there is still problem if you'd like to specify for example count higher than 100.

Similar approach would be needed for checkPrice but in this case it'd have to be done with use of tile:getItems() not to sumup same items.

But currently spliting items list to chunks of 100 should work fine (assuming all items are grouped to full stacks, always max or ordered correctly).
Like:
Lua:
items = {
    { id = 2160, count = 100 },
    { id = 2160, count = 100 }
}

Additionaly it could support money remove when there's money specified instead of id and then it could work with getMoney/removeMoney
 
Last edited:
I I understood everything you said. I'm still learning, as I stopped editing OT server since 2016 and came back this year. I feel like I understand TFS 0.4 more than TFS 1.x, but I'm really enjoying TFS 1.x. Thank you for the advice! 😁
 
Last edited:
Well I thought a bit about that and just realized it could be done without getItems:

Lua:
local checkPrice = function(tile, items)
    local countMap = {}
    for _, item in ipairs(items) do
        local tileCount = countMap[item.id] or tile:getItemCountById(item.id)
        local count = item.count or 1

        if tileCount < count then
            return false
        end

        countMap[item.id] = tileCount - count
    end

    return true
end
 
I made some more changes and corrections. I took your code and adapted it right here, it's working fine. I believe it can still be optimized better

The script is better now, isn't it?

Lua:
local action = Action()

function action.onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if item.actionid then
        local config = {
            pricePos = { x = 734, y = 595, z = 6 },
            addonName = { "first", "second" }
        }

        local outfits = {
            [50001] = {
                items = {
                    { id = 5890, count = 100 }
                },
                outfit = {
                    [PLAYERSEX_FEMALE] = 128,
                    [PLAYERSEX_MALE] = 136,  
                },
                addon = 1
            }
        }


        local priceTile = Tile(config.pricePos)
        if not priceTile then
            print("Error: Unable to create priceTile")
            return false
        end

        local removePrice = function(tile, items)
            local tileItems = tile:getItems()
            local itemFound = false

            for _, item in ipairs(items) do
                local count = item.count or 1
                itemFound = false

                for _, tileItem in ipairs(tileItems) do
                    if tileItem:getId() == item.id and count > 0 then
                        local removeCount = math.min(count, tileItem:getCount())
                        count = count - removeCount
                        tileItem:remove(removeCount)
                        itemFound = true
                    end
                end

                if not itemFound then
                    print("Item not found:", item.id)
                    return false
                end
            end

            return true
        end

local checkPrice = function(tile, items)
    local countMap = {}
    for _, item in ipairs(items) do
        local tileCount = countMap[item.id] or tile:getItemCountById(item.id)
        local count = item.count or 1

        if tileCount < count then
            return false
        end

        countMap[item.id] = tileCount - count
    end

    return true
end

        if not player:isPremium() then
            player:sendTextMessage(MESSAGE_INFO_DESCR, "Sorry, only premium players may use addon lever.")
            return true
        end

        local sex = player:getSex()

        for sId, o in pairs(outfits) do
            local hasOutfit = player:getStorageValue(sId) > 0
            if not hasOutfit and checkPrice(priceTile, o.items) then
                if removePrice(priceTile, o.items) then
                    local lookType = o.outfit[sex]
                    if lookType then
                        local outfit = Outfit(lookType)
                        outfit.lookAddons = o.addon or 1
                        local addonName = config.addonName[outfit.lookAddons] or ""
                        priceTile:getPosition():sendMagicEffect(CONST_ME_HITBYFIRE)
                        player:setStorageValue(sId, 1)
                        player:addOutfitAddon(lookType, outfit.lookAddons)
                        player:sendTextMessage(MESSAGE_INFO_DESCR, ("You have unlocked %s %s addon!"):format(addonName, outfit.name))
                        return true
                    end
                else
                    player:say("You don't have the required items!", TALKTYPE_ORANGE_1, false, player, priceTile:getPosition())
                    return true
                end
            end
        end

        player:say("You don't have needed items or you already have unlocked this addon!", TALKTYPE_ORANGE_1, false, player, priceTile:getPosition())
        return true
    end

    return false
end

action:aid(18563)
action:register()
 
@NvSo It's not a problem with check, if it's configured correctly it would work.
Problem is that arrays in lua are indexed from 1 and player sex is 0/1.
Thus it has to be changed to either work like:
Lua:
outfit = {
    [PLAYERSEX_FEMALE] = 136,
    [PLAYERSEX_MALE] = 128
}

local outfit = o.outfit[sex]
or simply:
Lua:
local outfit = o.outfit[sex + 1]

Additional check in removePrice won't hurt but as it's done just after checkPrice it's almost certain that item is still there but yea won't hurt to check.
Edit: I've applied necessary changes

Every day we learn something new! i need more practice :)

and its sure, as the original was, now it is at least times better XD
 
I made some more changes and corrections. I took your code and adapted it right here, it's working fine. I believe it can still be optimized better

The script is better now, isn't it?

Lua:
local action = Action()

function action.onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if item.actionid then
        local config = {
            pricePos = { x = 734, y = 595, z = 6 },
            addonName = { "first", "second" }
        }

        local outfits = {
            [50001] = {
                items = {
                    { id = 5890, count = 100 }
                },
                outfit = {
                    [PLAYERSEX_FEMALE] = 128,
                    [PLAYERSEX_MALE] = 136, 
                },
                addon = 1
            }
        }


        local priceTile = Tile(config.pricePos)
        if not priceTile then
            print("Error: Unable to create priceTile")
            return false
        end

        local removePrice = function(tile, items)
            local tileItems = tile:getItems()
            local itemFound = false

            for _, item in ipairs(items) do
                local count = item.count or 1
                itemFound = false

                for _, tileItem in ipairs(tileItems) do
                    if tileItem:getId() == item.id and count > 0 then
                        local removeCount = math.min(count, tileItem:getCount())
                        count = count - removeCount
                        tileItem:remove(removeCount)
                        itemFound = true
                    end
                end

                if not itemFound then
                    print("Item not found:", item.id)
                    return false
                end
            end

            return true
        end

local checkPrice = function(tile, items)
    local countMap = {}
    for _, item in ipairs(items) do
        local tileCount = countMap[item.id] or tile:getItemCountById(item.id)
        local count = item.count or 1

        if tileCount < count then
            return false
        end

        countMap[item.id] = tileCount - count
    end

    return true
end

        if not player:isPremium() then
            player:sendTextMessage(MESSAGE_INFO_DESCR, "Sorry, only premium players may use addon lever.")
            return true
        end

        local sex = player:getSex()

        for sId, o in pairs(outfits) do
            local hasOutfit = player:getStorageValue(sId) > 0
            if not hasOutfit and checkPrice(priceTile, o.items) then
                if removePrice(priceTile, o.items) then
                    local lookType = o.outfit[sex]
                    if lookType then
                        local outfit = Outfit(lookType)
                        outfit.lookAddons = o.addon or 1
                        local addonName = config.addonName[outfit.lookAddons] or ""
                        priceTile:getPosition():sendMagicEffect(CONST_ME_HITBYFIRE)
                        player:setStorageValue(sId, 1)
                        player:addOutfitAddon(lookType, outfit.lookAddons)
                        player:sendTextMessage(MESSAGE_INFO_DESCR, ("You have unlocked %s %s addon!"):format(addonName, outfit.name))
                        return true
                    end
                else
                    player:say("You don't have the required items!", TALKTYPE_ORANGE_1, false, player, priceTile:getPosition())
                    return true
                end
            end
        end

        player:say("You don't have needed items or you already have unlocked this addon!", TALKTYPE_ORANGE_1, false, player, priceTile:getPosition())
        return true
    end

    return false
end

action:aid(18563)
action:register()

After a long time, I'm back on topic.
Everything works as expected but...
If we change the gender of the character, the addon disappears because it is given only for the looktype of the player for the current gender.
Can you advise to change this ?
 
After a long time, I'm back on topic.
Everything works as expected but...
If we change the gender of the character, the addon disappears because it is given only for the looktype of the player for the current gender.
Can you advise to change this ?
The config is setup for you to place both genders, not just the one
 
The config is setup for you to place both genders, not just the one
Yes, but the script currently unlocks the addon only for a given lookType (sex). That is, if you are a male you will receive an addon only for MALE.
If I change the gender to FEMALE this addon is invisible.
If I change it to MALE again it shows as unlocked.
I would like the script to unlock the addon immediately for both genders.
 
Sorry thought character' sex is final, At least I hope that there are only two choices ;)
Check for typos (not tested)
Lua:
local addOutfit = function(player, lookTypes, addon)
    for _, sex in ipairs({ PLAYERSEX_FEMALE, PLAYERSEX_MALE }) do
        local lookType = lookTypes[sex + 1]
        player:addOutfitAddon(lookType, addon)
    end
end

for sId, o in pairs(outfits) do
    local hasOutfit = player:getStorageValue(sId) > 0
    if not hasOutfit and checkPrice(priceTile, o.items) and removePrice(priceTile, o.items) then
        addOutfit(player, o.outfit, o.addon or 1)
        player:setStorageValue(sId, 1)
        pricePos:sendMagicEffect(CONST_ME_HITBYFIRE)

        local lookType = o.outfit[sex + 1]
        local outfit = Outfit(lookType)
        local addonName = config.addonName[o.addon] or ""
        player:sendTextMessage(MESSAGE_INFO_DESCR, ("You have unlocked %s %s addon!"):format(addonName, outfit.name))
        return true
    end
end
 
Sorry thought character' sex is final, At least I hope that there are only two choices ;)
Check for typos (not tested)
Lua:
local addOutfit = function(player, lookTypes, addon)
    for _, sex in ipairs({ PLAYERSEX_FEMALE, PLAYERSEX_MALE }) do
        local lookType = lookTypes[sex + 1]
        player:addOutfitAddon(lookType, addon)
    end
end

for sId, o in pairs(outfits) do
    local hasOutfit = player:getStorageValue(sId) > 0
    if not hasOutfit and checkPrice(priceTile, o.items) and removePrice(priceTile, o.items) then
        addOutfit(player, o.outfit, o.addon or 1)
        player:setStorageValue(sId, 1)
        pricePos:sendMagicEffect(CONST_ME_HITBYFIRE)

        local lookType = o.outfit[sex + 1]
        local outfit = Outfit(lookType)
        local addonName = config.addonName[o.addon] or ""
        player:sendTextMessage(MESSAGE_INFO_DESCR, ("You have unlocked %s %s addon!"):format(addonName, outfit.name))
        return true
    end
end
Not working...
 
Back
Top