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

AAC Znote AAC shop [talkaction] vs [globalevents]

Status
Not open for further replies.

roriscrave

Advanced OT User
Joined
Dec 7, 2011
Messages
1,188
Solutions
34
Reaction score
200
What is most viable in shop znoteAac to deliver shop items?
a talkactions !shop (manual deliver) or a globalevents (automatic deliver) that runs every 30 seconds?
can globalevents slow down the game if you have a lot of players online?
thank you!
 
Solution
The globalevent script does 1 query for each player online every 30 seconds. (so 400 players online = 400 separate queries).
And it won't work if you have a pending order that is not type 1. (single item purchases).

The talkaction shop script only queries the database when player asks for it (when they type !shop) and supports type 1,5 and 6 by default.
(Regular item shop products, Outfit and addon, Mounts).

The globalevent script can be improved alot (especially in TFS 1.0), you can pull only relevant orders that you can handle, and cross check with table players_online to ensure you only load the relevant orders for players that are currently online. And instead of looping through every player, you should do 1 query that loads...
benchmark it, Add this in your global.lua
Code:
do
       local units = {
        ['seconds'] = 1,
        ['milliseconds'] = 1000,
        ['microseconds'] = 1000000,
        ['nanoseconds'] = 1000000000
    }

    function benchmark(unit, decPlaces, n, f, ...)
        local elapsed = 0
        local multiplier = units[unit]
        for i = 1, n do
            local now = os.clock()
            f(...)
            elapsed = elapsed + (os.clock() - now)
        end
        print(string.format('Benchmark results: %d function calls | %.'.. decPlaces ..'f %s elapsed | %.'.. decPlaces ..'f %s avg execution time.', n, elapsed * multiplier, unit, (elapsed / n) * multiplier, unit))
    end
end
and if you are going to test globalevents then it will be something like this
Code:
local function _onThink(interval, lastExecution)
--The whole script
return true
end

function onThink(interval, lastExecution)
    benchmark('milliseconds', 2, 50, _onThink, interval, lastExecution)
    return true
    end
this will show you the freeze time if 50 player recieved items at the same time you can change it from here
Code:
    benchmark('milliseconds', 2, 50, _onThink, interval, lastExecution)
 
Last edited by a moderator:
It all depends on the delivery code. If you're running db queries for each player in quick succession it's going to cause lag if you have lots of players.

@Shadow_ forgot the do in the benchmark code (and has _onKill in place of where _onThink should be):
Lua:
do
    local units = {
        ['seconds'] = 1,
        ['milliseconds'] = 1000,
        ['microseconds'] = 1000000,
        ['nanoseconds'] = 1000000000
    }
 
    function benchmark(unit, decPlaces, n, f, ...)
        local elapsed = 0
        local multiplier = units[unit]
        for i = 1, n do
            local now = os.clock()
            f(...)
            elapsed = elapsed + (os.clock() - now)
        end
        print(string.format('Benchmark results:\n  - %d function calls\n  - %.'.. decPlaces ..'f %s elapsed\n  - %.'.. decPlaces ..'f %s avg execution time.', n, elapsed * multiplier, unit, (elapsed / n) * multiplier, unit))
    end
end

In this case running the benchmark N times to mimic how many players wouldn't work because you're iterating the current list of players online and more than likely handling the expensive operations there, so you should be benchmarking the code that handles each iteration of the online players rather than the entire onThink function to see its real performance.
If you'd like to mimic a variable amount of players online, create a table and copy your player userdata N times into itself and iterate that table rather than Game.getOnlinePlayers().
 
It all depends on the delivery code. If you're running db queries for each player in quick succession it's going to cause lag if you have lots of players.

@Shadow_ forgot the do in the benchmark code (and has _onKill in place of where _onThink should be):
Lua:
do
    local units = {
        ['seconds'] = 1,
        ['milliseconds'] = 1000,
        ['microseconds'] = 1000000,
        ['nanoseconds'] = 1000000000
    }

    function benchmark(unit, decPlaces, n, f, ...)
        local elapsed = 0
        local multiplier = units[unit]
        for i = 1, n do
            local now = os.clock()
            f(...)
            elapsed = elapsed + (os.clock() - now)
        end
        print(string.format('Benchmark results:\n  - %d function calls\n  - %.'.. decPlaces ..'f %s elapsed\n  - %.'.. decPlaces ..'f %s avg execution time.', n, elapsed * multiplier, unit, (elapsed / n) * multiplier, unit))
    end
end

In this case running the benchmark N times to mimic how many players wouldn't work because you're iterating the current list of players online and more than likely handling the expensive operations there, so you should be benchmarking the code that handles each iteration of the online players rather than the entire onThink function to see its real performance.
If you'd like to mimic a variable amount of players online, create a table and copy your player userdata N times into itself and iterate that table rather than Game.getOnlinePlayers().
Thank you
 
It all depends on the delivery code. If you're running db queries for each player in quick succession it's going to cause lag if you have lots of players.

@Shadow_ forgot the do in the benchmark code (and has _onKill in place of where _onThink should be):

In this case running the benchmark N times to mimic how many players wouldn't work because you're iterating the current list of players online and more than likely handling the expensive operations there, so you should be benchmarking the code that handles each iteration of the online players rather than the entire onThink function to see its real performance.
If you'd like to mimic a variable amount of players online, create a table and copy your player userdata N times into itself and iterate that table rather than Game.getOnlinePlayers().
I was thinking of using this system made by @Printer GlobalEvent - Automatic Znote AAC Shop [TFS 1.0] (https://otland.net/threads/automatic-znote-aac-shop-tfs-1-0.224483/)
but it works the way you said it, using Game.getPlayers () all the time...
 
iam using it, its perfect.
how many player have online in your server?
I think if you have a lot of players online you can harm a performace, because all the time (every 30s) it checks all players online (i think it).
 
The globalevent script does 1 query for each player online every 30 seconds. (so 400 players online = 400 separate queries).
And it won't work if you have a pending order that is not type 1. (single item purchases).

The talkaction shop script only queries the database when player asks for it (when they type !shop) and supports type 1,5 and 6 by default.
(Regular item shop products, Outfit and addon, Mounts).

The globalevent script can be improved alot (especially in TFS 1.0), you can pull only relevant orders that you can handle, and cross check with table players_online to ensure you only load the relevant orders for players that are currently online. And instead of looping through every player, you should do 1 query that loads every relevant row and loop through that instead.

I can take a look at it this weekend and make a globalevent shop script (done the right way). But it will be for TFS 1.x, hopefully someone bothers to send PR for 0.2/3/4 compatibility.
 
Solution
The globalevent script does 1 query for each player online every 30 seconds. (so 400 players online = 400 separate queries).
And it won't work if you have a pending order that is not type 1. (single item purchases).

The talkaction shop script only queries the database when player asks for it (when they type !shop) and supports type 1,5 and 6 by default.
(Regular item shop products, Outfit and addon, Mounts).

The globalevent script can be improved alot (especially in TFS 1.0), you can pull only relevant orders that you can handle, and cross check with table players_online to ensure you only load the relevant orders for players that are currently online. And instead of looping through every player, you should do 1 query that loads every relevant row and loop through that instead.

I can take a look at it this weekend and make a globalevent shop script (done the right way). But it will be for TFS 1.x, hopefully someone bothers to send PR for 0.2/3/4 compatibility.
wow, this will be great if you can do!
you doing for 1.x, then someone with experience makes for 0.2 / 3/4 i believe.
thank you very much!
 
wow, this will be great if you can do!
you doing for 1.x, then someone with experience makes for 0.2 / 3/4 i believe.
thank you very much!

Done:

data/globalevents/globalevents.xml
XML:
<globalevent name="Znote Shop" interval="30000" script="znoteshop.lua"/>

data/globalevents/scripts/znoteshop.lua
Lua:
function onThink(interval, lastExecution)
    local orderQuery = db.storeQuery([[
        SELECT 
            MIN(`po`.`player_id`) AS `player_id`,
            `shop`.`id`, 
            `shop`.`type`, 
            `shop`.`itemid`, 
            `shop`.`count`
        FROM `players_online` AS `po`
        INNER JOIN `players` AS `p`
            ON `po`.`player_id` = `p`.`id`
        INNER JOIN `znote_shop_orders` AS `shop`
            ON `p`.`account_id` = `shop`.`account_id`
        WHERE `shop`.`type` IN(1,5,6)
        GROUP BY `shop`.`id`
    ]])
    -- Detect if we got any results
    if orderQuery ~= false then
        local type_desc = {
            "itemids",
            "pending premium (skip)",
            "pending gender change (skip)",
            "pending character name change (skip)",
            "Outfit and addons",
            "Mounts"
        }
        repeat 
            local player_id = result.getDataInt(orderQuery, 'player_id')
            local orderId = result.getDataInt(orderQuery, 'id')
            local orderType = result.getDataInt(orderQuery, 'type')
            local orderItemId = result.getDataInt(orderQuery, 'itemid')
            local orderCount = result.getDataInt(orderQuery, 'count')
            local served = false

            local player = Player(player_id)
            if player ~= nil then
                print("Processing shop order for: [".. player:getName() .."] type "..orderType..": ".. type_desc[orderType])
                local tile = Tile(player:getPosition())
                if tile ~= nil and tile:hasFlag(TILESTATE_PROTECTIONZONE) then
                    -- ORDER TYPE 1 (Regular item shop products)
                    if orderType == 1 then
                        served = true
                        local itemType = ItemType(orderItemId)
                        -- Get wheight
                        if player:getFreeCapacity() >= itemType:getWeight(orderCount) then
                            local backpack = player:getSlotItem(CONST_SLOT_BACKPACK)
                            -- variable = (condition) and (return if true) or (return if false)
                            local needslots = itemType:isStackable() and math.floor(orderCount / 100) + 1 or orderCount
                            if backpack ~= nil and backpack:getEmptySlots(false) >= needslots then
                                db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
                                player:addItem(orderItemId, orderCount)
                                player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. "!")
                                print("Process complete. [".. player:getName() .."] has recieved " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
                            else -- not enough slots 
                                player:sendTextMessage(MESSAGE_STATUS_WARNING, "Your main backpack is full. You need to free up "..needslots.." available slots to get " .. orderCount .. " " .. ItemType(orderItemId):getName() .. "!")
                                print("Process canceled. [".. player:getName() .."] need more space in his backpack to get " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
                            end
                        else -- not enough cap 
                            player:sendTextMessage(MESSAGE_STATUS_WARNING, "You need more CAP to carry this order!")
                            print("Process canceled. [".. player:getName() .."] need more cap to carry " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
                        end
                    end

                    -- ORDER TYPE 5 (Outfit and addon)
                    if orderType == 5 then
                        served = true
                        -- Make sure player don't already have this outfit and addon
                        if not player:hasOutfit(orderItemId, orderCount) then
                            db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
                            player:addOutfit(orderItemId)
                            player:addOutfitAddon(orderItemId, orderCount)
                            player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received a new outfit!")
                            print("Process complete. [".. player:getName() .."] has recieved outfit: ["..orderItemId.."] with addon: ["..orderCount.."]")
                        else -- Already has outfit 
                            player:sendTextMessage(MESSAGE_STATUS_WARNING, "You already have this outfit and addon!")
                            print("Process canceled. [".. player:getName() .."] already have outfit: ["..orderItemId.."] with addon: ["..orderCount.."].")
                        end
                    end

                    -- ORDER TYPE 6 (Mounts)
                    if orderType == 6 then
                        served = true
                        -- Make sure player don't already have this outfit and addon
                        if not player:hasMount(orderItemId) then
                            db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
                            player:addMount(orderItemId)
                            player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received a new mount!")
                            print("Process complete. [".. player:getName() .."] has recieved mount: ["..orderItemId.."]")
                        else -- Already has mount 
                            player:sendTextMessage(MESSAGE_STATUS_WARNING, "You already have this mount!")
                            print("Process canceled. [".. player:getName() .."] already have mount: ["..orderItemId.."].")
                        end
                    end

                    if not served then -- If this order hasn't been processed yet (missing type handling?)
                        print("Znote shop: Type ["..orderType.."] not properly processed. Missing Lua code?")
                    end
                else -- Not in protection zone 
                    player:sendTextMessage(MESSAGE_INFO_DESCR, 'You have a pending shop order, please enter protection zone.')
                    print("Skipped one shop order. Reason: Player: [".. player:getName() .."] is not inside protection zone.")
                end
            else -- player not logged in 
                print("Skipped one shop order. Reason: Player with id [".. player_id .."] is not online.")
            end

        until not result.next(orderQuery)
        result.free(orderQuery)
    end
    return true
end
 
Last edited:
Done:

data/globalevents/globalevents.xml
XML:
<globalevent name="Znote Shop" interval="30000" script="znoteshop.lua"/>

data/globalevents/scripts/znoteshop.lua
Lua:
function onThink(interval, lastExecution)
    local orderQuery = db.storeQuery([[
        SELECT
            MIN(`po`.`player_id`) AS `player_id`,
            `shop`.`id`,
            `shop`.`type`,
            `shop`.`itemid`,
            `shop`.`count`
        FROM `players_online` AS `po`
        INNER JOIN `players` AS `p`
            ON `po`.`player_id` = `p`.`id`
        INNER JOIN `znote_shop_orders` AS `shop`
            ON `p`.`account_id` = `shop`.`account_id`
        WHERE `shop`.`type` IN(1,5,6)
        GROUP BY `shop`.`id`
    ]])
    -- Detect if we got any results
    if orderQuery ~= false then
        local type_desc = {
            "itemids",
            "pending premium (skip)",
            "pending gender change (skip)",
            "pending character name change (skip)",
            "Outfit and addons",
            "Mounts"
        }
        repeat
            local player_id = result.getDataInt(orderQuery, 'player_id')
            local orderId = result.getDataInt(orderQuery, 'id')
            local orderType = result.getDataInt(orderQuery, 'type')
            local orderItemId = result.getDataInt(orderQuery, 'itemid')
            local orderCount = result.getDataInt(orderQuery, 'count')
            local served = false

            local player = Player(player_id)
            if player ~= nil then
                print("Processing shop order for: [".. player:getName() .."] type "..orderType..": ".. type_desc[orderType])
                local tile = Tile(player:getPosition())
                if tile ~= nil and tile:hasFlag(TILESTATE_PROTECTIONZONE) then
                    -- ORDER TYPE 1 (Regular item shop products)
                    if orderType == 1 then
                        served = true
                        -- Get wheight
                        if player:getFreeCapacity() >= ItemType(orderItemId):getWeight(orderCount) then
                            db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
                            player:addItem(orderItemId, orderCount)
                            player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received " .. orderCount .. " x " .. ItemType(orderItemId):getName() .. "!")
                            print("Process complete. [".. player:getName() .."] has recieved " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
                        else
                            player:sendTextMessage(MESSAGE_STATUS_WARNING, "You need more CAP to carry this order!")
                            print("Process canceled. [".. player:getName() .."] need more cap to carry " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
                        end
                    end

                    -- ORDER TYPE 5 (Outfit and addon)
                    if orderType == 5 then
                        served = true
                        -- Make sure player don't already have this outfit and addon
                        if not player:hasOutfit(orderItemId, orderCount) then
                            db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
                            player:addOutfit(orderItemId)
                            player:addOutfitAddon(orderItemId, orderCount)
                            player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received a new outfit!")
                            print("Process complete. [".. player:getName() .."] has recieved outfit: ["..orderItemId.."] with addon: ["..orderCount.."]")
                        else
                            player:sendTextMessage(MESSAGE_STATUS_WARNING, "You already have this outfit and addon!")
                            print("Process canceled. [".. player:getName() .."] already have outfit: ["..orderItemId.."] with addon: ["..orderCount.."].")
                        end
                    end

                    -- ORDER TYPE 6 (Mounts)
                    if orderType == 6 then
                        served = true
                        -- Make sure player don't already have this outfit and addon
                        if not player:hasMount(orderItemId) then
                            db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
                            player:addMount(orderItemId)
                            player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received a new mount!")
                            print("Process complete. [".. player:getName() .."] has recieved mount: ["..orderItemId.."]")
                        else
                            player:sendTextMessage(MESSAGE_STATUS_WARNING, "You already have this mount!")
                            print("Process canceled. [".. player:getName() .."] already have mount: ["..orderItemId.."].")
                        end
                    end

                    -- If this order hasn't been processed yet (missing type handling?)
                    if not served then
                        print("Znote shop: Type ["..orderType.."] not properly processed. Missing Lua code?")
                    end
                else
                    player:sendTextMessage(MESSAGE_INFO_DESCR, 'You have a pending shop order, please enter protection zone.')
                    print("Skipped one shop order. Reason: Player: [".. player:getName() .."] is not inside protection zone.")
                end
            else
                print("Skipped one shop order. Reason: Player with id [".. player_id .."] is not online.")
            end

        until not result.next(orderQuery)
        result.free(orderQuery)
    end
    return true
end
wow bro, thx a lot!!!!!!!!!!!!
u are a god!!
 
Done:

data/globalevents/globalevents.xml]
Hi znote, im trying to add if player dont have space in bag, it send a msg (default script, item drop on the floor).
so i added it:
Lua:
local item_add = player:addItem(orderItemId, orderCount, false)
                            print(item_add)
                            if item_add then
                                db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
                                player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received " .. orderCount .. " x " .. ItemType(orderItemId):getName() .. "!")
                                print("Process complete. [".. player:getName() .."] has recieved " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
                            else
                                player:sendTextMessage(MESSAGE_STATUS_WARNING, "You dont have backpack space to receive this order!")
                                print("Process canceled. [".. player:getName() .."] need more space in bag " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
                            end

apparently worked well with items, when an item is purchased from the shop and the player has no space, returns the message:
Code:
You dont have backpack space to receive this order!
and this part print(item_add) -> print "nil".

but if the item is a gold, the player receives msg:
Code:
Congratulations! You have received 5 x gold bar!
but he dont received anything, because he dont have space in a bag.
and this print:
print(item_add) return ->table: 0x128432f8 not nil.
do u know how can i solve?
a code:
Lua:
function onThink(interval, lastExecution)
    local orderQuery = db.storeQuery([[
        SELECT
            MIN(`po`.`player_id`) AS `player_id`,
            `shop`.`id`,
            `shop`.`type`,
            `shop`.`itemid`,
            `shop`.`count`
        FROM `players_online` AS `po`
        INNER JOIN `players` AS `p`
            ON `po`.`player_id` = `p`.`id`
        INNER JOIN `znote_shop_orders` AS `shop`
            ON `p`.`account_id` = `shop`.`account_id`
        WHERE `shop`.`type` IN(1,5,6)
        GROUP BY `shop`.`id`
    ]])
    -- Detect if we got any results
    if orderQuery ~= false then
        local type_desc = {
            "itemids",
            "pending premium (skip)",
            "pending gender change (skip)",
            "pending character name change (skip)",
            "Outfit and addons",
            "Mounts"
        }
        repeat
            local player_id = result.getDataInt(orderQuery, 'player_id')
            local orderId = result.getDataInt(orderQuery, 'id')
            local orderType = result.getDataInt(orderQuery, 'type')
            local orderItemId = result.getDataInt(orderQuery, 'itemid')
            local orderCount = result.getDataInt(orderQuery, 'count')
            local served = false

            local player = Player(player_id)
            if player ~= nil then
                print("Processing shop order for: [".. player:getName() .."] type "..orderType..": ".. type_desc[orderType])
                local tile = Tile(player:getPosition())
                if tile ~= nil and tile:hasFlag(TILESTATE_PROTECTIONZONE) then
                    -- ORDER TYPE 1 (Regular item shop products)
                    if orderType == 1 then
                        served = true
                        -- Get wheight
                        if player:getFreeCapacity() >= ItemType(orderItemId):getWeight(orderCount) then
                            local item_add = player:addItem(orderItemId, orderCount, false)
                            print(item_add)
                            if item_add then
                                db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
                                player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received " .. orderCount .. " x " .. ItemType(orderItemId):getName() .. "!")
                                print("Process complete. [".. player:getName() .."] has recieved " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
                            else
                                player:sendTextMessage(MESSAGE_STATUS_WARNING, "You dont have backpack space to receive this order!")
                                print("Process canceled. [".. player:getName() .."] need more space in bag " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
                            end
                        else
                            player:sendTextMessage(MESSAGE_STATUS_WARNING, "You need more CAP to carry this order!")
                            print("Process canceled. [".. player:getName() .."] need more cap to carry " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
                        end
                    end

                    -- ORDER TYPE 5 (Outfit and addon)
                    if orderType == 5 then
                        served = true
                        -- Make sure player don't already have this outfit and addon
                        if not player:hasOutfit(orderItemId, orderCount) then
                            db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
                            player:addOutfit(orderItemId)
                            player:addOutfitAddon(orderItemId, orderCount)
                            player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received a new outfit!")
                            print("Process complete. [".. player:getName() .."] has recieved outfit: ["..orderItemId.."] with addon: ["..orderCount.."]")
                        else
                            player:sendTextMessage(MESSAGE_STATUS_WARNING, "You already have this outfit and addon!")
                            print("Process canceled. [".. player:getName() .."] already have outfit: ["..orderItemId.."] with addon: ["..orderCount.."].")
                        end
                    end

                    -- ORDER TYPE 6 (Mounts)
                    if orderType == 6 then
                        served = true
                        -- Make sure player don't already have this outfit and addon
                        if not player:hasMount(orderItemId) then
                            db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
                            player:addMount(orderItemId)
                            player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received a new mount!")
                            print("Process complete. [".. player:getName() .."] has recieved mount: ["..orderItemId.."]")
                        else
                            player:sendTextMessage(MESSAGE_STATUS_WARNING, "You already have this mount!")
                            print("Process canceled. [".. player:getName() .."] already have mount: ["..orderItemId.."].")
                        end
                    end

                    -- If this order hasn't been processed yet (missing type handling?)
                    if not served then
                        print("Znote shop: Type ["..orderType.."] not properly processed. Missing Lua code?")
                    end
                else
                    player:sendTextMessage(MESSAGE_INFO_DESCR, 'You have a pending shop order, please enter protection zone.')
                    print("Skipped one shop order. Reason: Player: [".. player:getName() .."] is not inside protection zone.")
                end
            else
                print("Skipped one shop order. Reason: Player with id [".. player_id .."] is not online.")
            end

        until not result.next(orderQuery)
        result.free(orderQuery)
    end
    return true
end
 
Check this, added some extra code to verify player has enough available slots:
Lua:
function onThink(interval, lastExecution)
    local orderQuery = db.storeQuery([[
        SELECT 
            MIN(`po`.`player_id`) AS `player_id`,
            `shop`.`id`, 
            `shop`.`type`, 
            `shop`.`itemid`, 
            `shop`.`count`
        FROM `players_online` AS `po`
        INNER JOIN `players` AS `p`
            ON `po`.`player_id` = `p`.`id`
        INNER JOIN `znote_shop_orders` AS `shop`
            ON `p`.`account_id` = `shop`.`account_id`
        WHERE `shop`.`type` IN(1,5,6)
        GROUP BY `shop`.`id`
    ]])
    -- Detect if we got any results
    if orderQuery ~= false then
        local type_desc = {
            "itemids",
            "pending premium (skip)",
            "pending gender change (skip)",
            "pending character name change (skip)",
            "Outfit and addons",
            "Mounts"
        }
        repeat 
            local player_id = result.getDataInt(orderQuery, 'player_id')
            local orderId = result.getDataInt(orderQuery, 'id')
            local orderType = result.getDataInt(orderQuery, 'type')
            local orderItemId = result.getDataInt(orderQuery, 'itemid')
            local orderCount = result.getDataInt(orderQuery, 'count')
            local served = false

            local player = Player(player_id)
            if player ~= nil then
                print("Processing shop order for: [".. player:getName() .."] type "..orderType..": ".. type_desc[orderType])
                local tile = Tile(player:getPosition())
                if tile ~= nil and tile:hasFlag(TILESTATE_PROTECTIONZONE) then
                    -- ORDER TYPE 1 (Regular item shop products)
                    if orderType == 1 then
                        served = true
                        local itemType = ItemType(orderItemId)
                        -- Get wheight
                        if player:getFreeCapacity() >= itemType:getWeight(orderCount) then
                            local backpack = player:getSlotItem(CONST_SLOT_BACKPACK)
                            -- variable = (condition) and (return if true) or (return if false)
                            local needslots = itemType:isStackable() and math.floor(orderCount / 100) + 1 or orderCount
                            if backpack ~= nil and backpack:getEmptySlots(false) >= needslots then
                                db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
                                player:addItem(orderItemId, orderCount)
                                player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. "!")
                                print("Process complete. [".. player:getName() .."] has recieved " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
                            else -- not enough slots 
                                player:sendTextMessage(MESSAGE_STATUS_WARNING, "Your main backpack is full. You need to free up "..needslots.." available slots to get " .. orderCount .. " " .. ItemType(orderItemId):getName() .. "!")
                                print("Process canceled. [".. player:getName() .."] need more space in his backpack to get " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
                            end
                        else -- not enough cap 
                            player:sendTextMessage(MESSAGE_STATUS_WARNING, "You need more CAP to carry this order!")
                            print("Process canceled. [".. player:getName() .."] need more cap to carry " .. orderCount .. "x " .. ItemType(orderItemId):getName() .. ".")
                        end
                    end

                    -- ORDER TYPE 5 (Outfit and addon)
                    if orderType == 5 then
                        served = true
                        -- Make sure player don't already have this outfit and addon
                        if not player:hasOutfit(orderItemId, orderCount) then
                            db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
                            player:addOutfit(orderItemId)
                            player:addOutfitAddon(orderItemId, orderCount)
                            player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received a new outfit!")
                            print("Process complete. [".. player:getName() .."] has recieved outfit: ["..orderItemId.."] with addon: ["..orderCount.."]")
                        else -- Already has outfit 
                            player:sendTextMessage(MESSAGE_STATUS_WARNING, "You already have this outfit and addon!")
                            print("Process canceled. [".. player:getName() .."] already have outfit: ["..orderItemId.."] with addon: ["..orderCount.."].")
                        end
                    end

                    -- ORDER TYPE 6 (Mounts)
                    if orderType == 6 then
                        served = true
                        -- Make sure player don't already have this outfit and addon
                        if not player:hasMount(orderItemId) then
                            db.query("DELETE FROM `znote_shop_orders` WHERE `id` = " .. orderId .. ";")
                            player:addMount(orderItemId)
                            player:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations! You have received a new mount!")
                            print("Process complete. [".. player:getName() .."] has recieved mount: ["..orderItemId.."]")
                        else -- Already has mount 
                            player:sendTextMessage(MESSAGE_STATUS_WARNING, "You already have this mount!")
                            print("Process canceled. [".. player:getName() .."] already have mount: ["..orderItemId.."].")
                        end
                    end

                    if not served then -- If this order hasn't been processed yet (missing type handling?)
                        print("Znote shop: Type ["..orderType.."] not properly processed. Missing Lua code?")
                    end
                else -- Not in protection zone 
                    player:sendTextMessage(MESSAGE_INFO_DESCR, 'You have a pending shop order, please enter protection zone.')
                    print("Skipped one shop order. Reason: Player: [".. player:getName() .."] is not inside protection zone.")
                end
            else -- player not logged in 
                print("Skipped one shop order. Reason: Player with id [".. player_id .."] is not online.")
            end

        until not result.next(orderQuery)
        result.free(orderQuery)
    end
    return true
end
 
Status
Not open for further replies.
Back
Top