JE
tfs 0.3.6

Ajudem NPC com Bug na hora de comprar Potions Runas Etc

Por je19921992, 25 de mai. de 2016 em Scripts

bug npc
trade npc bug
bug npc trade potion
bug potion
bug runas
bug runa
14
3.9k
je19921992J
25 de maio de 2016 às 15:02

Salve XTIBIA!!! Vim recorrer a este forum, ver se consigo alguma coisa:

Quando compro itens no NPC de potion, runas, mesmo com 15 bps e 5k de cap, ele para de comprar quando enche a primeira BP... Alguem poderia me ajudar?

NPCCHANDLER.LUA

Spoiler

-- Advanced NPC System (Created by Jiddo),
-- Modified by TheForgottenServer Team.

if(NpcHandler == nil) then
    -- Constant talkdelay behaviors.
    TALKDELAY_NONE = 0 -- No talkdelay. Npc will reply immedeatly.
    TALKDELAY_ONTHINK = 1 -- Talkdelay handled through the onThink callback function. (Default)
    TALKDELAY_EVENT = 2 -- Not yet implemented

    -- Currently applied talkdelay behavior. TALKDELAY_ONTHINK is default.
    NPCHANDLER_TALKDELAY = TALKDELAY_ONTHINK

    -- Constant conversation behaviors.
    CONVERSATION_DEFAULT = 0 -- Conversation through default window, like it was before 8.2 update.
    CONVERSATION_PRIVATE = 1 -- Conversation through NPCs chat window, as of 8.2 update. (Default)
        --Small Note: Private conversations also means the NPC will use multi-focus system.

    -- Currently applied conversation behavior. CONVERSATION_PRIVATE is default.
    NPCHANDLER_CONVBEHAVIOR = CONVERSATION_PRIVATE

    -- Constant indexes for defining default messages.
    MESSAGE_GREET             = 1 -- When the player greets the npc.
    MESSAGE_FAREWELL         = 2 -- When the player unGreets the npc.
    MESSAGE_BUY             = 3 -- When the npc asks the player if he wants to buy something.
    MESSAGE_ONBUY             = 4 -- When the player successfully buys something via talk.
    MESSAGE_BOUGHT            = 5 -- When the player bought something through the shop window.
    MESSAGE_SELL             = 6 -- When the npc asks the player if he wants to sell something.
    MESSAGE_ONSELL             = 7 -- When the player successfully sells something via talk.
    MESSAGE_SOLD            = 8 -- When the player sold something through the shop window.
    MESSAGE_MISSINGMONEY        = 9 -- When the player does not have enough money.
    MESSAGE_MISSINGITEM        = 10 -- When the player is trying to sell an item he does not have.
    MESSAGE_NEEDMONEY        = 11 -- Same as above, used for shop window.
    MESSAGE_NEEDITEM        = 12 -- Same as above, used for shop window.
    MESSAGE_NEEDSPACE         = 13 -- When the player don't have any space to buy an item
    MESSAGE_NEEDMORESPACE        = 14 -- When the player has some space to buy an item, but not enough space
    MESSAGE_IDLETIMEOUT        = 15 -- When the player has been idle for longer then idleTime allows.
    MESSAGE_WALKAWAY        = 16 -- When the player walks out of the talkRadius of the npc.
    MESSAGE_DECLINE            = 17 -- When the player says no to something.
    MESSAGE_SENDTRADE        = 18 -- When the npc sends the trade window to the player
    MESSAGE_NOSHOP            = 19 -- When the npc's shop is requested but he doesn't have any
    MESSAGE_ONCLOSESHOP        = 20 -- When the player closes the npc's shop window
    MESSAGE_ALREADYFOCUSED        = 21 -- When the player already has the focus of this npc.
    MESSAGE_PLACEDINQUEUE        = 22 -- When the player has been placed in the costumer queue.

    -- Constant indexes for callback functions. These are also used for module callback ids.
    CALLBACK_CREATURE_APPEAR     = 1
    CALLBACK_CREATURE_DISAPPEAR    = 2
    CALLBACK_CREATURE_SAY         = 3
    CALLBACK_ONTHINK         = 4
    CALLBACK_GREET             = 5
    CALLBACK_FAREWELL         = 6
    CALLBACK_MESSAGE_DEFAULT     = 7
    CALLBACK_PLAYER_ENDTRADE     = 8
    CALLBACK_PLAYER_CLOSECHANNEL    = 9
    CALLBACK_ONBUY            = 10
    CALLBACK_ONSELL            = 11

    -- Addidional module callback ids
    CALLBACK_MODULE_INIT        = 12
    CALLBACK_MODULE_RESET        = 13

    -- Constant strings defining the keywords to replace in the default messages.
    TAG_PLAYERNAME = '|PLAYERNAME|'
    TAG_ITEMCOUNT = '|ITEMCOUNT|'
    TAG_TOTALCOST = '|TOTALCOST|'
    TAG_ITEMNAME = '|ITEMNAME|'
    TAG_QUEUESIZE = '|QUEUESIZE|'

    NpcHandler = {
        keywordHandler = nil,
        focuses = nil,
        talkStart = nil,
        idleTime = 300,
        talkRadius = 3,
        talkDelayTime = 350, -- Seconds to delay outgoing messages.
        queue = nil,
        talkDelay = nil,
        callbackFunctions = nil,
        modules = nil,
        shopItems = nil, -- They must be here since ShopModule uses "static" functions
        messages = {
            -- These are the default replies of all npcs. They can/should be changed individually for each npc.
            [MESSAGE_GREET]     = 'Welcome, |PLAYERNAME|! I have been expecting you.',
            [MESSAGE_FAREWELL]     = 'Good bye, |PLAYERNAME|!',
            [MESSAGE_BUY]         = 'Do you want to buy |ITEMCOUNT| |ITEMNAME| for |TOTALCOST| gold coins?',
            [MESSAGE_ONBUY]     = 'It was a pleasure doing business with you.',
            [MESSAGE_BOUGHT]     = 'Bought |ITEMCOUNT|x |ITEMNAME| for |TOTALCOST| gold.',
            [MESSAGE_SELL]         = 'Do you want to sell |ITEMCOUNT| |ITEMNAME| for |TOTALCOST| gold coins?',
            [MESSAGE_ONSELL]     = 'Thank you for this |ITEMNAME|, |PLAYERNAME|.',
            [MESSAGE_SOLD]         = 'Sold |ITEMCOUNT|x |ITEMNAME| for |TOTALCOST| gold.',
            [MESSAGE_MISSINGMONEY]    = 'Sorry, you don\'t have enough money.',
            [MESSAGE_MISSINGITEM]     = 'You don\'t even have that item, |PLAYERNAME|!',
            [MESSAGE_NEEDMONEY]     = 'You do not have enough money.',
            [MESSAGE_NEEDITEM]    = 'You do not have this object.',
            [MESSAGE_NEEDSPACE]    = 'You do not have enough capacity.',
            [MESSAGE_NEEDMORESPACE]    = 'You do not have enough capacity for all items.',
            [MESSAGE_IDLETIMEOUT]     = 'Next, please!',
            [MESSAGE_WALKAWAY]     = 'How rude!',
            [MESSAGE_DECLINE]    = 'Not good enough, is it... ?',
            [MESSAGE_SENDTRADE]    = 'Here\'s my offer, |PLAYERNAME|. Don\'t you like it?',
            [MESSAGE_NOSHOP]    = 'Sorry, I\'m not offering anything.',
            [MESSAGE_ONCLOSESHOP]    = 'Thank you, come back when you want something more.',
            [MESSAGE_ALREADYFOCUSED]= '|PLAYERNAME|! I am already talking to you...',
            [MESSAGE_PLACEDINQUEUE] = '|PLAYERNAME|, please wait for your turn. There are |QUEUESIZE| customers before you.'
        }
    }

    -- Creates a new NpcHandler with an empty callbackFunction stack.
    function NpcHandler:new(keywordHandler)
        local obj = {}
        obj.messages = {}

        obj.keywordHandler = keywordHandler
        if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
            obj.focuses = {}
            obj.talkStart = {}
        else
            obj.queue = Queue:new(obj)
            obj.focuses = 0
            obj.talkStart = 0
        end

        obj.callbackFunctions = {}
        obj.modules = {}
        obj.talkDelay = {}
        obj.shopItems = {}

        setmetatable(obj.messages, self.messages)
        self.messages.__index = self.messages

        setmetatable(obj, self)
        self.__index = self
        return obj
    end

    -- Re-defines the maximum idle time allowed for a player when talking to this npc.
    function NpcHandler:setMaxIdleTime(newTime)
        self.idleTime = newTime
    end

    -- Attackes a new keyword handler to this npchandler
    function NpcHandler:setKeywordHandler(newHandler)
        self.keywordHandler = newHandler
    end

    -- Function used to change the focus of this npc.
    function NpcHandler:addFocus(newFocus)
        if(not isCreature(newFocus)) then
            return
        end

        if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
            if(self:isFocused(newFocus, true)) then
                return
            end

            table.insert(self.focuses, newFocus)
        else
            self.focuses = newFocus
        end

        self:updateFocus(true)
    end
    NpcHandler.changeFocus = NpcHandler.addFocus -- "changeFocus" looks better for CONVERSATION_DEFAULT

    -- Function used to verify if npc is focused to certain player
    function NpcHandler:isFocused(focus, creatureCheck)
        local creatureCheck = creatureCheck or false
        if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
            for k, v in pairs(self.focuses) do
                if(v == focus) then
                    if(creatureCheck or isCreature(v)) then
                        return true
                    end

                    self:unsetFocus(focus, k)
                    return false
                end
            end

            return false
        end

        if(creatureCheck or isCreature(self.focuses)) then
            return self.focuses == focus
        end

        self:changeFocus(0)
        return false
    end

    -- This function should be called on each onThink and makes sure the npc faces the player it is talking to.
    --    Should also be called whenever a new player is focused.
    function NpcHandler:updateFocus(creatureCheck)
        local creatureCheck = creatureCheck or false
        if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
            for _, focus in pairs(self.focuses) do
                if(creatureCheck or isCreature(focus)) then
                    doNpcSetCreatureFocus(focus)
                    return
                end
            end
        elseif(creatureCheck or isCreature(self.focuses)) then
            doNpcSetCreatureFocus(self.focuses)
            return
        end

        doNpcSetCreatureFocus(0)
    end

    -- Used when the npc should un-focus the player.
    function NpcHandler:releaseFocus(focus)
        if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
            if(not self:isFocused(focus)) then
                return
            end

            local pos = nil
            for k, v in pairs(self.focuses) do
                if(v == focus) then
                    pos = k
                end
            end

            if(pos ~= nil) then
                closeShopWindow(focus)
                self:unsetFocus(focus, pos)
            end
        elseif(self.focuses == focus) then
            if(isCreature(focus)) then
                closeShopWindow(focus)
            end

            self:changeFocus(0)
        end
    end

    -- Internal un-focusing function, beware using!
    function NpcHandler:unsetFocus(focus, pos)
        if(type(self.focuses) ~= "table" or pos == nil or self.focuses[pos] == nil) then
            return
        end

        table.remove(self.focuses, pos)
        self.talkStart[focus] = nil
        self:updateFocus()
    end

    -- Returns the callback function with the specified id or nil if no such callback function exists.
    function NpcHandler:getCallback(id)
        local ret = nil
        if(self.callbackFunctions ~= nil) then
            ret = self.callbackFunctions[id]
        end

        return ret
    end

    -- Changes the callback function for the given id to callback.
    function NpcHandler:setCallback(id, callback)
        if(self.callbackFunctions ~= nil) then
            self.callbackFunctions[id] = callback
        end
    end

    -- Adds a module to this npchandler and inits it.
    function NpcHandler:addModule(module)
        if(self.modules == nil or module == nil) then
            return false
        end

        module:init(self)
        if(module.parseParameters ~= nil) then
            module:parseParameters()
        end

        table.insert(self.modules, module)
        return true
    end

    -- Calls the callback function represented by id for all modules added to this npchandler with the given arguments.
    function NpcHandler:processModuleCallback(id, ...)
        local ret = true
        for _, module in pairs(self.modules) do
            local tmpRet = true
            if(id == CALLBACK_CREATURE_APPEAR and module.callbackOnCreatureAppear ~= nil) then
                tmpRet = module:callbackOnCreatureAppear(...)
            elseif(id == CALLBACK_CREATURE_DISAPPEAR and module.callbackOnCreatureDisappear ~= nil) then
                tmpRet = module:callbackOnCreatureDisappear(...)
            elseif(id == CALLBACK_CREATURE_SAY and module.callbackOnCreatureSay ~= nil) then
                tmpRet = module:callbackOnCreatureSay(...)
            elseif(id == CALLBACK_PLAYER_ENDTRADE and module.callbackOnPlayerEndTrade ~= nil) then
                tmpRet = module:callbackOnPlayerEndTrade(...)
            elseif(id == CALLBACK_PLAYER_CLOSECHANNEL and module.callbackOnPlayerCloseChannel ~= nil) then
                tmpRet = module:callbackOnPlayerCloseChannel(...)
            elseif(id == CALLBACK_ONBUY and module.callbackOnBuy ~= nil) then
                tmpRet = module:callbackOnBuy(...)
            elseif(id == CALLBACK_ONSELL and module.callbackOnSell ~= nil) then
                tmpRet = module:callbackOnSell(...)
            elseif(id == CALLBACK_ONTHINK and module.callbackOnThink ~= nil) then
                tmpRet = module:callbackOnThink(...)
            elseif(id == CALLBACK_GREET and module.callbackOnGreet ~= nil) then
                tmpRet = module:callbackOnGreet(...)
            elseif(id == CALLBACK_FAREWELL and module.callbackOnFarewell ~= nil) then
                tmpRet = module:callbackOnFarewell(...)
            elseif(id == CALLBACK_MESSAGE_DEFAULT and module.callbackOnMessageDefault ~= nil) then
                tmpRet = module:callbackOnMessageDefault(...)
            elseif(id == CALLBACK_MODULE_RESET and module.callbackOnModuleReset ~= nil) then
                tmpRet = module:callbackOnModuleReset(...)
            end

            if(not tmpRet) then
                ret = false
                break
            end
        end

        return ret
    end

    -- Returns the message represented by id.
    function NpcHandler:getMessage(id)
        local ret = nil
        if(self.messages ~= nil) then
            ret = self.messages[id]
        end

        return ret
    end

    -- Changes the default response message with the specified id to newMessage.
    function NpcHandler:setMessage(id, newMessage)
        if(self.messages ~= nil) then
            self.messages[id] = newMessage
        end
    end

    -- Translates all message tags found in msg using parseInfo
    function NpcHandler:parseMessage(msg, parseInfo)
        for search, replace in pairs(parseInfo) do
            if(replace ~= nil) then
                msg = msg:gsub(search, replace)
            end
        end

        return msg
    end

    -- Makes sure the npc un-focuses the currently focused player
    function NpcHandler:unGreet(cid)
        if(not self:isFocused(cid)) then
            return
        end

        local callback = self:getCallback(CALLBACK_FAREWELL)
        if(callback == nil or callback(cid)) then
            if(self:processModuleCallback(CALLBACK_FAREWELL)) then
                if(self.queue == nil or not self.queue:greetNext()) then
                    local msg = self:getMessage(MESSAGE_FAREWELL)
                    msg = self:parseMessage(msg, { [TAG_PLAYERNAME] = getPlayerName(cid) or -1 })

                    self:resetNpc(cid)
                    if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
                        self:say(msg, cid, 0, true)
                        msg = msg:gsub('{', ''):gsub('}', '')
                        local ghost, position = isPlayerGhost(cid), getThingPosition(getNpcId())

                        local spectators, nid = getSpectators(position, 7, 7), getNpcId()
                        for _, pid in ipairs(spectators) do
                            if(isPlayer(pid) and pid ~= cid) then
                                if(NPCHANDLER_TALKDELAY ~= TALKDELAY_NONE) then
                                    addEvent(doCreatureSay, self.talkDelayTime, nid, msg, TALKTYPE_SAY, ghost, pid, position)
                                else
                                    doCreatureSay(nid, msg, TALKTYPE_SAY, ghost, pid, position)
                                end
                            end
                        end
                    else
                        self:say(msg)
                    end

                    self:releaseFocus(cid)
                end
            end
        end
    end

    -- Greets a new player.
    function NpcHandler:greet(cid)
        local callback = self:getCallback(CALLBACK_GREET)
        if(callback == nil or callback(cid)) then
            if(self:processModuleCallback(CALLBACK_GREET, cid)) then
                local msg = self:getMessage(MESSAGE_GREET)
                msg = self:parseMessage(msg, { [TAG_PLAYERNAME] = getCreatureName(cid) })

                self:addFocus(cid)
                if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
                    self:say(msg, cid, 0, true)
                    msg = msg:gsub('{', ''):gsub('}', '')
                    local ghost, position = isPlayerGhost(cid), getThingPosition(getNpcId())

                    local spectators, nid = getSpectators(position, 7, 7), getNpcId()
                    for _, pid in ipairs(spectators) do
                        if(isPlayer(pid) and pid ~= cid) then
                            if(NPCHANDLER_TALKDELAY ~= TALKDELAY_NONE) then
                                addEvent(doCreatureSay, self.talkDelayTime, nid, msg, TALKTYPE_SAY, ghost, pid, position)
                            else
                                doCreatureSay(nid, msg, TALKTYPE_SAY, ghost, pid, position)
                            end
                        end
                    end
                else
                    self:say(msg)
                end
            end
        end
    end

    -- Handles onCreatureAppear events. If you with to handle this yourself, please use the CALLBACK_CREATURE_APPEAR callback.
    function NpcHandler:onCreatureAppear(cid)
        local callback = self:getCallback(CALLBACK_CREATURE_APPEAR)
        if(callback == nil or callback(cid)) then
            if(self:processModuleCallback(CALLBACK_CREATURE_APPEAR, cid)) then
                --
            end
        end
    end

    -- Handles onCreatureDisappear events. If you with to handle this yourself, please use the CALLBACK_CREATURE_DISAPPEAR callback.
    function NpcHandler:onCreatureDisappear(cid)
        local callback = self:getCallback(CALLBACK_CREATURE_DISAPPEAR)
        if(callback == nil or callback(cid)) then
            if(self:processModuleCallback(CALLBACK_CREATURE_DISAPPEAR, cid)) then
                if(self:isFocused(cid)) then
                    self:unGreet(cid)
                end
            end
        end
    end

    -- Handles onCreatureSay events. If you with to handle this yourself, please use the CALLBACK_CREATURE_SAY callback.
    function NpcHandler:onCreatureSay(cid, class, msg)
        local callback = self:getCallback(CALLBACK_CREATURE_SAY)
        if(callback == nil or callback(cid, class, msg)) then
            if(self:processModuleCallback(CALLBACK_CREATURE_SAY, cid, class, msg)) then
                if(not self:isInRange(cid)) then
                    return
                end

                if(self.keywordHandler ~= nil) then
                    if((self:isFocused(cid) and (class == TALKTYPE_PRIVATE_PN or NPCHANDLER_CONVBEHAVIOR == CONVERSATION_DEFAULT)) or not self:isFocused(cid)) then
                        local ret = self.keywordHandler:processMessage(cid, msg)
                        if(not ret) then
                            local callback = self:getCallback(CALLBACK_MESSAGE_DEFAULT)
                            if(callback ~= nil and callback(cid, class, msg)) then
                                if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
                                    self.talkStart[cid] = os.time()
                                else
                                    self.talkStart = os.time()
                                end
                            end
                        elseif(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
                            self.talkStart[cid] = os.time()
                        else
                            self.talkStart = os.time()
                        end
                    end
                end
            end
        end
    end

    -- Handles onPlayerEndTrade events. If you wish to handle this yourself, use the CALLBACK_PLAYER_ENDTRADE callback.
    function NpcHandler:onPlayerEndTrade(cid)
        local callback = self:getCallback(CALLBACK_PLAYER_ENDTRADE)
        if(callback == nil or callback(cid)) then
            if(self:processModuleCallback(CALLBACK_PLAYER_ENDTRADE, cid)) then
                if(self:isFocused(cid)) then
                    local parseInfo = { [TAG_PLAYERNAME] = getPlayerName(cid) }
                    local msg = self:parseMessage(self:getMessage(MESSAGE_ONCLOSESHOP), parseInfo)
                    self:say(msg, cid)
                end
            end
        end
    end

    -- Handles onPlayerCloseChannel events. If you wish to handle this yourself, use the CALLBACK_PLAYER_CLOSECHANNEL callback.
    function NpcHandler:onPlayerCloseChannel(cid)
        local callback = self:getCallback(CALLBACK_PLAYER_CLOSECHANNEL)
        if(callback == nil or callback(cid)) then
            if(self:processModuleCallback(CALLBACK_PLAYER_CLOSECHANNEL, cid)) then
                if(self:isFocused(cid)) then
                    self:unGreet(cid)
                end
            end
        end
    end

    -- Handles onBuy events. If you wish to handle this yourself, use the CALLBACK_ONBUY callback.
    function NpcHandler:onBuy(cid, itemid, subType, amount, ignoreCap, inBackpacks)
        local callback = self:getCallback(CALLBACK_ONBUY)
        if(callback == nil or callback(cid, itemid, subType, amount, ignoreCap, inBackpacks)) then
            if(self:processModuleCallback(CALLBACK_ONBUY, cid, itemid, subType, amount, ignoreCap, inBackpacks)) then
                --
            end
        end
    end

    -- Handles onSell events. If you wish to handle this yourself, use the CALLBACK_ONSELL callback.
    function NpcHandler:onSell(cid, itemid, subType, amount, ignoreCap, inBackpacks)
        local callback = self:getCallback(CALLBACK_ONSELL)
        if(callback == nil or callback(cid, itemid, subType, amount, ignoreCap, inBackpacks)) then
            if(self:processModuleCallback(CALLBACK_ONSELL, cid, itemid, subType, amount, ignoreCap, inBackpacks)) then
                --
            end
        end
    end

    -- Handles onThink events. If you wish to handle this yourself, please use the CALLBACK_ONTHINK callback.
    function NpcHandler:onThink()
        local callback = self:getCallback(CALLBACK_ONTHINK)
        if(callback == nil or callback()) then
            for i, speech in pairs(self.talkDelay) do
                if((speech.cid == nil or speech.cid == 0) and speech.time ~= nil and speech.message ~= nil) then
                    if(os.mtime() >= speech.time) then
                        selfSay(speech.message)
                        self.talkDelay = nil
                    end
                elseif(isCreature(speech.cid) and speech.start ~= nil and speech.time ~= nil and speech.message ~= nil) then
                    if(os.mtime() >= speech.time) then
                        local talkStart = (NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT and self.talkStart[speech.cid] or self.talkStart)
                        if(speech.force or (self:isFocused(speech.cid) and talkStart == speech.start)) then
                            if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
                                selfSay(speech.message, speech.cid)
                            else
                                selfSay(speech.message)
                            end
                        end

                        self.talkDelay = nil
                    end
                else
                    self.talkDelay = nil
                end
            end

            if(self:processModuleCallback(CALLBACK_ONTHINK)) then
                if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
                    for _, focus in pairs(self.focuses) do
                        if(focus ~= nil) then
                            if(not self:isInRange(focus)) then
                                self:onWalkAway(focus)
                            elseif((os.time() - self.talkStart[focus]) > self.idleTime) then
                                self:unGreet(focus)
                            else
                                self:updateFocus()
                            end
                        end
                    end
                elseif(self.focuses ~= 0) then
                    if(not self:isInRange(self.focuses)) then
                        self:onWalkAway(self.focuses)
                    elseif((os.time() - self.talkStart) > self.idleTime) then
                        self:unGreet(self.focuses)
                    else
                        self:updateFocus()
                    end
                end
            end
        end
    end

    -- Tries to greet the player with the given cid.
    function NpcHandler:onGreet(cid)
        if(self:isInRange(cid)) then
            if(NPCHANDLER_CONVBEHAVIOR == CONVERSATION_PRIVATE) then
                if(not self:isFocused(cid)) then
                    self:greet(cid)
                    return
                end
            elseif(NPCHANDLER_CONVBEHAVIOR == CONVERSATION_DEFAULT) then
                if(self.focuses == 0) then
                    self:greet(cid)
                elseif(self.focuses == cid) then
                    local msg = self:getMessage(MESSAGE_ALREADYFOCUSED)
                    local parseInfo = { [TAG_PLAYERNAME] = getCreatureName(cid) }
                    msg = self:parseMessage(msg, parseInfo)
                    self:say(msg)
                else
                    if(not self.queue:isInQueue(cid)) then
                        self.queue:push(cid)
                    end

                    local msg = self:getMessage(MESSAGE_PLACEDINQUEUE)
                    local parseInfo = { [TAG_PLAYERNAME] = getCreatureName(cid), [TAG_QUEUESIZE] = self.queue:getSize() }
                    msg = self:parseMessage(msg, parseInfo)
                    self:say(msg)
                end
            end
        end
    end

    -- Simply calls the underlying unGreet function.
    function NpcHandler:onFarewell(cid)
        self:unGreet(cid)
    end

    -- Should be called on this npc's focus if the distance to focus is greater then talkRadius.
    function NpcHandler:onWalkAway(cid)
        if(self:isFocused(cid)) then
            local callback = self:getCallback(CALLBACK_CREATURE_DISAPPEAR)
            if(callback == nil or callback(cid)) then
                if(self:processModuleCallback(CALLBACK_CREATURE_DISAPPEAR, cid)) then
                    if(self.queue == nil or not self.queue:greetNext()) then
                        local msg = self:getMessage(MESSAGE_WALKAWAY)
                        self:resetNpc(cid)
                        self:say(self:parseMessage(msg, { [TAG_PLAYERNAME] = getPlayerName(cid) or -1 }))
                        self:releaseFocus(cid)
                    end
                end
            end
        end
    end

    -- Returns true if cid is within the talkRadius of this npc.
    function NpcHandler:isInRange(cid)
        if not isPlayer(cid) then
            return false
        end

        local distance = getNpcDistanceTo(cid) or -1
        return distance ~= -1 and distance <= self.talkRadius
    end

    -- Resets the npc into it's initial state (in regard of the keyrodhandler).
    --    All modules are also receiving a reset call through their callbackOnModuleReset function.
    function NpcHandler:resetNpc(cid)
        if(self:processModuleCallback(CALLBACK_MODULE_RESET)) then
            self.keywordHandler:reset(cid)
        end
    end

    -- Makes the npc represented by this instance of NpcHandler say something.
    --    This implements the currently set type of talkdelay.
    function NpcHandler:say(message, focus, delay, force)
        local delay = delay or 0
        if(NPCHANDLER_TALKDELAY == TALKDELAY_NONE or delay <= 0) then
            if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
                selfSay(message, focus)
            else
                selfSay(message)
            end

            return
        end

        -- TODO: Add an event handling method for delayed messages
        table.insert(self.talkDelay, {
            id = getNpcId(),
            cid = focus,
            message = message,
            time = os.mtime() + (delay and delay or self.talkDelayTime),
            start = os.time(),
            force = force or false
        })
    end
end
 

Aparece uma mensagem dizendo que não tenho capacidade! Mesmo com 5k de cap e 15 bps uma dentro da outra. Para de comprar quando enche a primeira

DanihcvD
25 de maio de 2016 às 16:16

Este tópico foi movido para Tutoriais e Suporte - Tutoriais de Scripting - Suporte Scripting

je19921992J
25 de maio de 2016 às 16:39

Nossa eu amo o Xtibia, não chama atenção em publico por topico colocado em area errada =): Enfim, estou com problemao sitado la em cima...

PoccnnP
25 de maio de 2016 às 17:42

Posta o arquivo modules.lua

je19921992J
25 de maio de 2016 às 18:26
Spoiler

-- Advanced NPC System (Created by Jiddo),
-- Modified by TheForgottenServer Team.

if(Modules == nil) then
    -- Constants used to separate buying from selling.
    SHOPMODULE_SELL_ITEM = 1
    SHOPMODULE_BUY_ITEM = 2
    SHOPMODULE_BUY_ITEM_CONTAINER = 3

    -- Constants used for shop mode. Notice: addBuyableItemContainer is working on all modes
    SHOPMODULE_MODE_TALK = 1 -- Old system used before Tibia 8.2: sell/buy item name
    SHOPMODULE_MODE_TRADE = 2 -- Trade window system introduced in Tibia 8.2
    SHOPMODULE_MODE_BOTH = 3 -- Both working at one time

    -- Used in shop mode
    SHOPMODULE_MODE = SHOPMODULE_MODE_BOTH

    -- Constants used for outfit giving mode
    OUTFITMODULE_FUNCTION_OLD = { doPlayerAddOutfit, canPlayerWearOutfit } -- lookType usage
    OUTFITMODULE_FUNCTION_NEW = { doPlayerAddOutfitId, canPlayerWearOutfitId } -- OutfitId usage

    -- Used in outfit module
    OUTFITMODULE_FUNCTION = OUTFITMODULE_FUNCTION_NEW
    if(OUTFITMODULE_FUNCTION[1] == nil or OUTFITMODULE_FUNCTION[2] == nil) then
        OUTFITMODULE_FUNCTION = OUTFITMODULE_FUNCTION_OLD
    end

    Modules = {
        parseableModules = {}
    }

    StdModule = {}

    -- These callback function must be called with parameters.npcHandler = npcHandler in the parameters table or they will not work correctly.
    -- Notice: The members of StdModule have not yet been tested. If you find any bugs, please report them to me.
    -- Usage:
        -- keywordHandler:addKeyword({'offer'}, StdModule.say, {npcHandler = npcHandler, text = 'I sell many powerful melee weapons.'})
    function StdModule.say(cid, message, keywords, parameters, node)
        local npcHandler = parameters.npcHandler
        if(npcHandler == nil) then
            print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'StdModule.say - Call without any npcHandler instance.')
            return false
        end

        local onlyFocus = (parameters.onlyFocus == nil or parameters.onlyFocus == true)
        if(not npcHandler:isFocused(cid) and onlyFocus) then
            return false
        end

        local parseInfo = {[TAG_PLAYERNAME] = getCreatureName(cid)}
        npcHandler:say(npcHandler:parseMessage(parameters.text or parameters.message, parseInfo), cid, parameters.publicize and true)
        if(parameters.reset) then
            npcHandler:resetNpc(cid)
        elseif(parameters.moveup and type(parameters.moveup) == 'number') then
            npcHandler.keywordHandler:moveUp(parameters.moveup)
        end

        return true
    end

    --Usage:
        -- local node1 = keywordHandler:addKeyword({'promot'}, StdModule.say, {npcHandler = npcHandler, text = 'I can promote you for 20000 brozne coins. Do you want me to promote you?'})
        --         node1:addChildKeyword({'yes'}, StdModule.promotePlayer, {npcHandler = npcHandler, cost = 20000, promotion = 1, level = 20}, text = 'Congratulations! You are now promoted.')
        --         node1:addChildKeyword({'no'}, StdModule.say, {npcHandler = npcHandler, text = 'Alright then, come back when you are ready.'}, reset = true)
    function StdModule.promotePlayer(cid, message, keywords, parameters, node)
        local npcHandler = parameters.npcHandler
        if(npcHandler == nil) then
            print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'StdModule.promotePlayer - Call without any npcHandler instance.')
            return false
        end

        if(not npcHandler:isFocused(cid)) then
            return false
        end

        if(isPremium(cid) or not getBooleanFromString(getConfigValue('premiumForPromotion'))) then
            if(getPlayerPromotionLevel(cid) >= parameters.promotion) then
                npcHandler:say('You are already promoted!', cid)
            elseif(getPlayerLevel(cid) < parameters.level) then
                npcHandler:say('I am sorry, but I can only promote you once you have reached level ' .. parameters.level .. '.', cid)
            elseif(not doPlayerRemoveMoney(cid, parameters.cost)) then
                npcHandler:say('You do not have enough money!', cid)
            else
                doPlayerSetPromotionLevel(cid, parameters.promotion)
                npcHandler:say(parameters.text, cid)
            end
        else
            npcHandler:say("You need a premium account in order to get promoted.", cid)
        end

        npcHandler:resetNpc(cid)
        return true
    end

    function StdModule.learnSpell(cid, message, keywords, parameters, node)
        local npcHandler = parameters.npcHandler
        if(npcHandler == nil) then
            print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'StdModule.learnSpell - Call without any npcHandler instance.')
            return false
        end

        if(not npcHandler:isFocused(cid)) then
            return false
        end

        if(isPremium(cid) or not(parameters.premium)) then
            if(getPlayerLearnedInstantSpell(cid, parameters.spellName)) then
                npcHandler:say('You already know this spell.', cid)
            elseif(getPlayerLevel(cid) < parameters.level) then
                npcHandler:say('You need to obtain a level of ' .. parameters.level .. ' or higher to be able to learn ' .. parameters.spellName .. '.', cid)
            elseif(not parameters.vocation(cid)) then
                npcHandler:say('This spell is not for your vocation', cid)
            elseif(not doPlayerRemoveMoney(cid, parameters.price)) then
                npcHandler:say('You do not have enough money, this spell costs ' .. parameters.price .. ' gold coins.', cid)
            else
                npcHandler:say('You have learned ' .. parameters.spellName .. '.', cid)
                playerLearnInstantSpell(cid, parameters.spellName)
            end
        else
            npcHandler:say('You need a premium account in order to buy ' .. parameters.spellName .. '.', cid)
        end

        npcHandler:resetNpc(cid)
        return true
    end

    function StdModule.bless(cid, message, keywords, parameters, node)
        local npcHandler = parameters.npcHandler
        if(npcHandler == nil) then
            print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'StdModule.bless - Call without any npcHandler instance.')
            return false
        end

        if(not getBooleanFromString(getConfigValue('blessings'))) then
            npcHandler:say("Sorry, but Gods moved back my permission to bless anyone.", cid)
            return false
        end

        if(not npcHandler:isFocused(cid)) then
            return false
        end

        if(isPremium(cid) or not getBooleanFromString(getConfigValue('blessingsOnlyPremium')) or not parameters.premium) then
            local price = parameters.baseCost
            if(getPlayerLevel(cid) > parameters.startLevel) then
                price = (price + ((math.min(parameters.endLevel, getPlayerLevel(cid)) - parameters.startLevel) * parameters.levelCost))
            end

            if(parameters.number > 0) then
                if(getPlayerBlessing(cid, parameters.number)) then
                    npcHandler:say("Gods have already blessed you with this blessing!", cid)
                elseif(not doPlayerRemoveMoney(cid, price)) then
                    npcHandler:say("You don't have enough money for blessing.", cid)
                else
                    npcHandler:say("You have been blessed by one of the five gods!", cid)
                    doPlayerAddBlessing(cid, parameters.number)
                end
            else
                if(getPlayerPVPBlessing(cid)) then
                    npcHandler:say("Gods have already blessed you with this blessing!", cid)
                elseif(not doPlayerRemoveMoney(cid, price)) then
                    npcHandler:say("You don't have enough money for blessing.", cid)
                else
                    local any = false
                    for i = 1, 5 do
                        if(getPlayerBlessing(cid, i)) then
                            any = true
                            break
                        end
                    end

                    if(any) then
                        npcHandler:say("You have been blessed by the god of war!", cid)
                        doPlayerSetPVPBlessing(cid)
                    else
                        npcHandler:say("You need to be blessed by at least one god to get this blessing.", cid)
                    end
                end
            end
        else
            npcHandler:say('You need a premium account in order to be blessed.', cid)
        end

        npcHandler:resetNpc(cid)
        return true
    end

    function StdModule.travel(cid, message, keywords, parameters, node)
        local npcHandler = parameters.npcHandler
        if(npcHandler == nil) then
            print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'StdModule.travel - Call without any npcHandler instance.')
            return false
        end

        if(not npcHandler:isFocused(cid)) then
            return false
        end

        local storage, pzLocked = parameters.storageValue or (EMPTY_STORAGE + 1), parameters.allowLocked or false
        if(parameters.premium and not isPremium(cid)) then
            npcHandler:say('I\'m sorry, but you need a premium account in order to travel onboard our ships.', cid)
        elseif(parameters.level ~= nil and getPlayerLevel(cid) < parameters.level) then
            npcHandler:say('You must reach level ' .. parameters.level .. ' before I can let you go there.', cid)
        elseif(parameters.storageId ~= nil and getPlayerStorageValue(cid, parameters.storageId) < storage) then
            npcHandler:say(parameters.storageInfo or 'You may not travel there yet!', cid)
        elseif(not pzLocked and isPlayerPzLocked(cid)) then
            npcHandler:say('First get rid of those blood stains! You are not going to ruin my vehicle!', cid)
        elseif(not doPlayerRemoveMoney(cid, parameters.cost)) then
            npcHandler:say('You don\'t have enough money.', cid)
        else
            npcHandler:say('Set the sails!', cid)
            npcHandler:releaseFocus(cid)

            doTeleportThing(cid, parameters.destination, false)
            doSendMagicEffect(parameters.destination, CONST_ME_TELEPORT)
        end

        npcHandler:resetNpc(cid)
        return true
    end

    FocusModule = {
        npcHandler = nil
    }

    -- Creates a new instance of FocusModule without an associated NpcHandler.
    function FocusModule:new()
        local obj = {}
        setmetatable(obj, self)
        self.__index = self
        return obj
    end

    -- Inits the module and associates handler to it.
    function FocusModule:init(handler)
        self.npcHandler = handler
        for i, word in pairs(FOCUS_GREETWORDS) do
            local obj = {}
            table.insert(obj, word)

            obj.callback = FOCUS_GREETWORDS.callback or FocusModule.messageMatcher
            handler.keywordHandler:addKeyword(obj, FocusModule.onGreet, {module = self})
        end

        for i, word in pairs(FOCUS_FAREWELLWORDS) do
            local obj = {}
            table.insert(obj, word)

            obj.callback = FOCUS_FAREWELLWORDS.callback or FocusModule.messageMatcher
            handler.keywordHandler:addKeyword(obj, FocusModule.onFarewell, {module = self})
        end
    end

    -- Greeting callback function.
    function FocusModule.onGreet(cid, message, keywords, parameters)
        parameters.module.npcHandler:onGreet(cid)
        return true
    end

    -- UnGreeting callback function.
    function FocusModule.onFarewell(cid, message, keywords, parameters)
        if(not parameters.module.npcHandler:isFocused(cid)) then
            return false
        end

        parameters.module.npcHandler:onFarewell(cid)
        parameters.module.npcHandler:resetNpc(cid)
        return true
    end

    -- Custom message matching callback function for greeting messages.
    function FocusModule.messageMatcher(keywords, message)
        local spectators = getSpectators(getCreaturePosition(getNpcId()), 7, 7)
        for i, word in pairs(keywords) do
            if(type(word) == 'string') then
                if(string.find(message, word) and not string.find(message, '[%w+]' .. word) and not string.find(message, word .. '[%w+]')) then
                    if(string.find(message, getCreatureName(getNpcId()))) then
                        return true
                    end

                    for i, uid in ipairs(spectators) do
                        if(string.find(message, getCreatureName(uid))) then
                            return false
                        end
                    end

                    return true
                end
            end
        end

        return false
    end

    KeywordModule = {
        npcHandler = nil
    }
    -- Add it to the parseable module list.
    Modules.parseableModules['module_keywords'] = KeywordModule

    function KeywordModule:new()
        local obj = {}
        setmetatable(obj, self)
        self.__index = self
        return obj
    end

    function KeywordModule:init(handler)
        self.npcHandler = handler
    end

    -- Parses all known parameters.
    function KeywordModule:parseParameters()
        local ret = NpcSystem.getParameter('keywords')
        if(ret ~= nil) then
            self:parseKeywords(ret)
        end
    end

    function KeywordModule:parseKeywords(data)
        local n = 1
        for keys in string.gmatch(data, '[^;]+') do
            local i = 1

            local keywords = {}
            for temp in string.gmatch(keys, '[^,]+') do
                table.insert(keywords, temp)
                i = i + 1
            end

            if(i ~= 1) then
                local reply = NpcSystem.getParameter('keyword_reply' .. n)
                if(reply ~= nil) then
                    self:addKeyword(keywords, reply)
                else
                    print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Parameter \'' .. 'keyword_reply' .. n .. '\' missing. Skipping...')
                end
            else
                print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'No keywords found for keyword set #' .. n .. '. Skipping...')
            end

            n = n + 1
        end
    end

    function KeywordModule:addKeyword(keywords, reply)
        self.npcHandler.keywordHandler:addKeyword(keywords, StdModule.say, {npcHandler = self.npcHandler, onlyFocus = true, text = reply, reset = true})
    end

    TravelModule = {
        npcHandler = nil,
        destinations = nil,
        yesNode = nil,
        noNode = nil,
    }
    -- Add it to the parseable module list.
    Modules.parseableModules['module_travel'] = TravelModule

    function TravelModule:new()
        local obj = {}
        setmetatable(obj, self)
        self.__index = self
        return obj
    end

    function TravelModule:init(handler)
        self.npcHandler = handler
        self.yesNode = KeywordNode:new(SHOP_YESWORD, TravelModule.onConfirm, {module = self})
        self.noNode = KeywordNode:new(SHOP_NOWORD, TravelModule.onDecline, {module = self})

        self.destinations = {}
    end

    -- Parses all known parameters.
    function TravelModule:parseParameters()
        local ret = NpcSystem.getParameter('travel_destinations')
        if(ret ~= nil) then
            self:parseDestinations(ret)
            for _, word in ipairs({'destination', 'list', 'where', 'travel'}) do
                self.npcHandler.keywordHandler:addKeyword({word}, TravelModule.listDestinations, {module = self})
            end
        end
    end

    function TravelModule:parseDestinations(data)
        for destination in string.gmatch(data, '[^;]+') do
            local i, name, pos, cost, premium, level, storage = 1, nil, {x = nil, y = nil, z = nil}, nil, false
            for tmp in string.gmatch(destination, '[^,]+') do
                if(i == 1) then
                    name = tmp
                elseif(i == 2) then
                    pos.x = tonumber(tmp)
                elseif(i == 3) then
                    pos.y = tonumber(tmp)
                elseif(i == 4) then
                    pos.z = tonumber(tmp)
                elseif(i == 5) then
                    cost = tonumber(tmp)
                elseif(i == 6) then
                    premium = getBooleanFromString(tmp)
                else
                    print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Unknown parameter found in travel destination parameter.', tmp, destination)
                end

                i = i + 1
            end

            if(name ~= nil and pos.x ~= nil and pos.y ~= nil and pos.z ~= nil and cost ~= nil) then
                self:addDestination(name, pos, cost, premium)
            else
                print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Parameter(s) missing for travel destination:', name, pos, cost, premium)
            end
        end
    end

    function TravelModule:addDestination(name, position, price, premium)
        table.insert(self.destinations, name)
        local parameters = {
            cost = price,
            destination = position,
            premium = premium,
            module = self
        }

        local keywords, bringWords = {}, {}
        table.insert(keywords, name)

        table.insert(bringWords, 'bring me to ' .. name)
        self.npcHandler.keywordHandler:addKeyword(bringWords, TravelModule.bring, parameters)

        local node = self.npcHandler.keywordHandler:addKeyword(keywords, TravelModule.travel, parameters)
        node:addChildKeywordNode(self.yesNode)
        node:addChildKeywordNode(self.noNode)
    end

    function TravelModule.travel(cid, message, keywords, parameters, node)
        local module = parameters.module
        if(not module.npcHandler:isFocused(cid)) then
            return false
        end

        module.npcHandler:say('Do you want to travel to ' .. keywords[1] .. ' for ' .. parameters.cost .. ' gold coins?', cid)
        return true
    end

    function TravelModule.onConfirm(cid, message, keywords, parameters, node)
        local module = parameters.module
        if(not module.npcHandler:isFocused(cid)) then
            return false
        end

        local parent = node:getParent():getParameters()
        if(isPremium(cid) or not parent.premium) then
            if(not isPlayerPzLocked(cid)) then
                if(doPlayerRemoveMoney(cid, parent.cost)) then
                    module.npcHandler:say('Set the sails!', cid)
                    module.npcHandler:releaseFocus(cid)

                    doTeleportThing(cid, parent.destination, true)
                    doSendMagicEffect(parent.destination, CONST_ME_TELEPORT)
                else
                    module.npcHandler:say('You don\'t have enough money.', cid)
                end
            else
                module.npcHandler:say('First get rid of those blood stains! You are not going to ruin my vehicle!', cid)
            end
        else
            module.npcHandler:say('I\'m sorry, but you need a premium account in order to travel onboard our ships.', cid)
        end

        module.npcHandler:resetNpc(cid)
        return true
    end

    -- onDecline keyword callback function. Generally called when the player sais 'no' after wanting to buy an item.
    function TravelModule.onDecline(cid, message, keywords, parameters, node)
        local module = parameters.module
        if(not module.npcHandler:isFocused(cid)) then
            return false
        end

        module.npcHandler:say(module.npcHandler:parseMessage(module.npcHandler:getMessage(MESSAGE_DECLINE), {[TAG_PLAYERNAME] = getCreatureName(cid)}), cid)
        module.npcHandler:resetNpc(cid)
        return true
    end

    function TravelModule.bring(cid, message, keywords, parameters, node)
        local module = parameters.module
        if(not module.npcHandler:isFocused(cid)) then
            return false
        end

        if((isPremium(cid) or not parameters.premium) and not isPlayerPzLocked(cid) and doPlayerRemoveMoney(cid, parameters.cost)) then
            module.npcHandler:say('Set the sails!', cid)
            module.npcHandler:releaseFocus(cid)

            doTeleportThing(cid, parameters.destination, false)
            doSendMagicEffect(parameters.destination, CONST_ME_TELEPORT)
        end

        module.npcHandler:releaseFocus(cid)
        return true
    end

    function TravelModule.listDestinations(cid, message, keywords, parameters, node)
        local module = parameters.module
        if(not module.npcHandler:isFocused(cid)) then
            return false
        end

        local msg = nil
        for _, destination in ipairs(module.destinations) do
            if(msg ~= nil) then
                msg = msg .. ", "
            else
                msg = ""
            end

            msg = msg .. "{" .. destination .. "}"
        end

        module.npcHandler:say(msg .. ".", cid)
        module.npcHandler:resetNpc(cid)
        return true
    end

    OutfitModule = {
        npcHandler = nil,
        outfits = nil,
        yesNode = nil,
        noNode = nil,
    }
    -- Add it to the parseable module list.
    Modules.parseableModules['module_outfit'] = OutfitModule

    function OutfitModule:new()
        if(OUTFITMODULE_FUNCTION[1] == nil or OUTFITMODULE_FUNCTION[2] == nil) then
            return nil
        end

        local obj = {}
        setmetatable(obj, self)
        self.__index = self
        return obj
    end

    function OutfitModule:init(handler)
        self.npcHandler = handler
        self.yesNode = KeywordNode:new(SHOP_YESWORD, OutfitModule.onConfirm, {module = self})
        self.noNode = KeywordNode:new(SHOP_NOWORD, OutfitModule.onDecline, {module = self})

        self.outfits = {}
    end

    -- Parses all known parameters.
    function OutfitModule:parseParameters()
        local ret = NpcSystem.getParameter('outfits')
        if(ret ~= nil) then
            self:parseKeywords(ret)
            for _, word in ipairs({'outfits', 'addons'}) do
                self.npcHandler.keywordHandler:addKeyword({word}, OutfitModule.listOutfits, {module = self})
            end
        end
    end

    function OutfitModule:parseKeywords(data)
        local n = 1
        for outfit in string.gmatch(data, '[^;]+') do
            local i, keywords = 1, {}
            for tmp in string.gmatch(outfit, '[^,]+') do
                table.insert(keywords, tmp)
                i = i + 1
            end

            if(i > 0) then
                local ret = NpcSystem.getParameter('outfit' .. n)
                if(ret ~= nil) then
                    self:parseList(keywords, ret)
                else
                    print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Missing \'outfit' .. n .. '\' parameter, skipping...')
                end
            else
                print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'No keywords found for outfit set #' .. n .. ', skipping...')
            end

            n = n + 1
        end
    end

    function OutfitModule:parseList(keywords, data)
        local outfit, items = nil, {}
        for list in string.gmatch(data, '[^;]+') do
            local a, b, c, d, e = nil, nil, nil, nil, 1
            for tmp in string.gmatch(list, '[^,]+') do
                if(e == 1) then
                    a = tmp
                elseif(e == 2) then
                    b = tmp
                elseif(e == 3) then
                    c = tmp
                elseif(e == 4) then
                    d = tmp
                else
                    print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Unknown parameter found in outfit list while parsing ' .. (outfit == nil and 'outfit' or 'item') .. '.', tmp, list)
                end

                e = e + 1
            end

            if(outfit == nil) then
                outfit = {tonumber(a), tonumber(b), getBooleanFromString©, d}
            elseif(a ~= nil) then
                local tmp = tonumber(a)
                if((tmp ~= nil or tostring(a) == "money") and b ~= nil and c ~= nil) then
                    a = tmp or 20000
                    tmp = tonumber(d)
                    if(tmp == nil) then
                        tmp = -1
                    end

                    items[a] = {b, tmp, c}
                else
                    print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Missing parameter(s) for outfit items.', b, c, d)
                end
            else
                print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Missing base parameter for outfit items.', a)
            end
        end

        if(type(outfit) == 'table') then
            local tmp = true
            for i = 1, 2 do
                if(outfit == nil) then
                    tmp = false
                    break
                end
            end

            if(tmp and table.maxn(items) > 0) then
                self:addOutfit(keywords, outfit, items)
            else
                print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Invalid outfit, addon or empty items pool.', data)
            end
        end
    end

    function OutfitModule:addOutfit(keywords, outfit, items)
        table.insert(self.outfits, keywords[1])
        local parameters = {
            outfit = outfit[1],
            addon = outfit[2],
            premium = outfit[3],
            gender = nil,
            items = items,
            module = self
        }

        if(outfit[4] ~= nil) then
            local tmp = string.lower(tostring(outfit[5]))
            if(tmp == 'male' or tmp == '1') then
                parameters.gender = 1
            elseif(tmp == 'female' or tmp == '0') then
                parameters.gender = 0
            end
        end

        for i, name in pairs(keywords) do
            local words = {}
            table.insert(words, name)

            local node = self.npcHandler.keywordHandler:addKeyword(words, OutfitModule.obtain, parameters)
            node:addChildKeywordNode(self.yesNode)
            node:addChildKeywordNode(self.noNode)
        end
    end

    function OutfitModule.obtain(cid, message, keywords, parameters, node)
        local module = parameters.module
        if(not module.npcHandler:isFocused(cid)) then
            return false
        end

        local i, items, size = 0, nil, table.maxn(parameters.items)
        for k, v in pairs(parameters.items) do
            if(v[1] ~= "storageset") then
                i = i + 1
                if(items ~= nil) then
                    if(i == size) then
                        items = items .. " and "
                    else
                        items = items .. ", "
                    end
                else
                    items = ""
                end

                if(tonumber(v[1]) ~= nil and tonumber(v[1]) > 1) then
                    items = items .. v[1] .. " "
                end

                items = items .. v[3]
            end
        end

        module.npcHandler:say('Do you want ' .. keywords[1] .. ' ' .. (addon == 0 and "outfit" or "addon") .. ' for ' .. items .. '?', cid)
        return true

    end

    function OutfitModule.onConfirm(cid, message, keywords, parameters, node)
        local module = parameters.module
        if(not module.npcHandler:isFocused(cid)) then
            return false
        end

        local parent = node:getParent():getParameters()
        if(isPremium(cid) or not parent.premium) then
            if(not OUTFITMODULE_FUNCTION[2](cid, parent.outfit, parent.addon)) then
                if(parent.addon == 0 or OUTFITMODULE_FUNCTION[2](cid, parent.outfit)) then
                    if(parent.gender == nil or parent.gender == getPlayerSex(cid)) then
                        local found = true
                        for k, v in pairs(parent.items) do
                            local tmp = tonumber(v[1])
                            if(tmp == nil) then
                                if(v[1] == "storagecheck") then
                                    if(getCreatureStorage(cid, k) < v[2]) then
                                        found = false
                                    end
                                elseif(v[1] == "outfitid") then
                                    if(not canPlayerWearOutfitId(cid, k, v[2])) then
                                        found = false
                                    end
                                elseif(v[1] == "outfit") then
                                    if(not canPlayerWearOutfit(cid, k, v[2])) then
                                        found = false
                                    end
                                else
                                    found = false
                                end
                            elseif(k == 20000) then
                                if(getPlayerMoney(cid) < tmp) then
                                    found = false
                                end
                            elseif(getPlayerItemCount(cid, k, v[2]) < tmp) then
                                found = false
                            end

                            if(not found) then
                                break
                            end
                        end

                        if(found) then
                            for k, v in pairs(parent.items) do
                                if(tonumber(v[1]) ~= nil) then
                                    if(k == 20000) then
                                        doPlayerRemoveMoney(cid, v[1])
                                    else
                                        doPlayerRemoveItem(cid, k, v[1], v[2])
                                    end
                                elseif(v[1] == "storageset") then
                                    doCreatureSetStorage(cid, k, v[2])
                                end
                            end

                            module.npcHandler:say('It was a pleasure to dress you.', cid)
                            OUTFITMODULE_FUNCTION[1](cid, parent.outfit, parent.addon)
                            doPlayerSetStorageValue(cid, parent.storageId, storage)
                        else
                            module.npcHandler:say('You don\'t have these items!', cid)
                        end
                    else
                        module.npcHandler:say('Sorry, this ' .. (parent.addon == 0 and 'outfit' or 'addon') .. ' is not for your gender.', cid)
                    end
                else
                    module.npcHandler:say('I will not dress you with addon of outfit you cannot wear!', cid)
                end
            else
                module.npcHandler:say('You already have this ' .. (parent.addon == 0 and 'outfit' or 'addon') .. '!', cid)
            end
        else
            module.npcHandler:say('Sorry, I dress only premium players.', cid)
        end

        module.npcHandler:resetNpc(cid)
        return true
    end

    -- onDecline keyword callback function. Generally called when the player sais 'no' after wanting to buy an item.
    function OutfitModule.onDecline(cid, message, keywords, parameters, node)
        local module = parameters.module
        if(not module.npcHandler:isFocused(cid)) then
            return false
        end

        module.npcHandler:say(module.npcHandler:parseMessage(module.npcHandler:getMessage(MESSAGE_DECLINE), {[TAG_PLAYERNAME] = getCreatureName(cid)}), cid)
        module.npcHandler:resetNpc(cid)
        return true
    end

    function OutfitModule.listOutfits(cid, message, keywords, parameters, node)
        local module = parameters.module
        if(not module.npcHandler:isFocused(cid)) then
            return false
        end

        local msg, size = nil, table.maxn(module.outfits)
        if(size > 0) then
            for i, outfit in ipairs(module.outfits) do
                if(msg ~= nil) then
                    if(i == size) then
                        msg = msg .. " and "
                    else
                        msg = msg .. ", "
                    end
                else
                    msg = "I can dress you into "
                end

                msg = msg .. "{" .. outfit .. "}"
            end
        else
            msg = "Sorry, I have nothing to offer right now."
        end

        module.npcHandler:say(msg .. ".", cid)
        module.npcHandler:resetNpc(cid)
        return true
    end

    ShopModule = {
        npcHandler = nil,
        yesNode = nil,
        noNode = nil,
        noText = '',
        maxCount = 100,
        amount = 0
    }

    -- Add it to the parseable module list.
    Modules.parseableModules['module_shop'] = ShopModule

    -- Creates a new instance of ShopModule
    function ShopModule:new()
        local obj = {}
        setmetatable(obj, self)
        self.__index = self
        return obj
    end

    -- Parses all known parameters.
    function ShopModule:parseParameters()
        local ret = NpcSystem.getParameter('shop_buyable')
        if(ret ~= nil) then
            self:parseBuyable(ret)
        end

        local ret = NpcSystem.getParameter('shop_sellable')
        if(ret ~= nil) then
            self:parseSellable(ret)
        end

        local ret = NpcSystem.getParameter('shop_buyable_containers')
        if(ret ~= nil) then
            self:parseBuyableContainers(ret)
        end
    end

    -- Parse a string contaning a set of buyable items.
    function ShopModule:parseBuyable(data)
        for item in string.gmatch(data, '[^;]+') do
            local i, name, itemid, cost, subType, realName = 1, nil, nil, nil, nil, nil
            for tmp in string.gmatch(item, '[^,]+') do
                if(i == 1) then
                    name = tmp
                elseif(i == 2) then
                    itemid = tonumber(tmp)
                elseif(i == 3) then
                    cost = tonumber(tmp)
                elseif(i == 4) then
                    subType = tonumber(tmp)
                elseif(i == 5) then
                    realName = tmp
                else
                    print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Unknown parameter found in buyable items parameter.', tmp, item)
                end

                i = i + 1
            end

            if(SHOPMODULE_MODE == SHOPMODULE_MODE_TRADE) then
                if(itemid ~= nil and cost ~= nil) then
                    if(isItemFluidContainer(itemid) and subType == nil) then
                        print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'SubType missing for parameter item:', item)
                    else
                        self:addBuyableItem(nil, itemid, cost, subType, realName)
                    end
                else
                    print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Parameter(s) missing for item:', itemid, cost)
                end
            elseif(name ~= nil and itemid ~= nil and cost ~= nil) then
                if(isItemFluidContainer(itemid) and subType == nil) then
                    print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'SubType missing for parameter item:', item)
                else
                    local names = {}
                    table.insert(names, name)
                    self:addBuyableItem(names, itemid, cost, subType, realName)
                end
            else
                print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Parameter(s) missing for item:', name, itemid, cost)
            end
        end
    end

    -- Parse a string contaning a set of sellable items.
    function ShopModule:parseSellable(data)
        for item in string.gmatch(data, '[^;]+') do
            local i, name, itemid, cost, realName = 1, nil, nil, nil, nil
            for temp in string.gmatch(item, '[^,]+') do
                if(i == 1) then
                    name = temp
                elseif(i == 2) then
                    itemid = tonumber(temp)
                elseif(i == 3) then
                    cost = tonumber(temp)
                elseif(i == 4) then
                    realName = temp
                else
                    print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Unknown parameter found in sellable items parameter.', temp, item)
                end
                i = i + 1
            end

            if(SHOPMODULE_MODE == SHOPMODULE_MODE_TRADE) then
                if(itemid ~= nil and cost ~= nil) then
                    self:addSellableItem(nil, itemid, cost, realName)
                else
                    print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Parameter(s) missing for item:', itemid, cost)
                end
            elseif(name ~= nil and itemid ~= nil and cost ~= nil) then
                local names = {}
                table.insert(names, name)
                self:addSellableItem(names, itemid, cost, realName)
            else
                print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Parameter(s) missing for item:', name, itemid, cost)
            end
        end
    end

    -- Parse a string contaning a set of buyable items.
    function ShopModule:parseBuyableContainers(data)
        for item in string.gmatch(data, '[^;]+') do
            local i, name, container, itemid, cost, subType, realName = 1, nil, nil, nil, nil, nil, nil
            for temp in string.gmatch(item, '[^,]+') do
                if(i == 1) then
                    name = temp
                elseif(i == 2) then
                    itemid = tonumber(temp)
                elseif(i == 3) then
                    itemid = tonumber(temp)
                elseif(i == 4) then
                    cost = tonumber(temp)
                elseif(i == 5) then
                    subType = tonumber(temp)
                elseif(i == 6) then
                    realName = temp
                else
                    print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Unknown parameter found in buyable items parameter.', temp, item)
                end
                i = i + 1
            end

            if(name ~= nil and container ~= nil and itemid ~= nil and cost ~= nil) then
                if(isItemFluidContainer(itemid) and subType == nil) then
                    print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'SubType missing for parameter item:', item)
                else
                    local names = {}
                    table.insert(names, name)
                    self:addBuyableItemContainer(names, container, itemid, cost, subType, realName)
                end
            else
                print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Parameter(s) missing for item:', name, container, itemid, cost)
            end
        end
    end

    -- Initializes the module and associates handler to it.
    function ShopModule:init(handler)
        self.npcHandler = handler
        self.yesNode = KeywordNode:new(SHOP_YESWORD, ShopModule.onConfirm, {module = self})
        self.noNode = KeywordNode:new(SHOP_NOWORD, ShopModule.onDecline, {module = self})

        self.noText = handler:getMessage(MESSAGE_DECLINE)
        if(SHOPMODULE_MODE ~= SHOPMODULE_MODE_TALK) then
            for i, word in pairs(SHOP_TRADEREQUEST) do
                local obj = {}
                table.insert(obj, word)

                obj.callback = SHOP_TRADEREQUEST.callback or ShopModule.messageMatcher
                handler.keywordHandler:addKeyword(obj, ShopModule.requestTrade, {module = self})
            end
        end
    end

    -- Custom message matching callback function for requesting trade messages.
    function ShopModule.messageMatcher(keywords, message)
        for i, word in pairs(keywords) do
            if(type(word) == 'string' and string.find(message, word) and not string.find(message, '[%w+]' .. word) and not string.find(message, word .. '[%w+]')) then
                return true
            end
        end

        return false
    end

    -- Resets the module-specific variables.
    function ShopModule:reset()
        self.amount = 0
    end

    -- Function used to match a number value from a string.
    function ShopModule:getCount(message)
        local ret, b, e = 1, string.find(message, PATTERN_COUNT)
        if(b ~= nil and e ~= nil) then
            ret = tonumber(string.sub(message, b, e))
        end

        return math.max(1, math.min(self.maxCount, ret))
    end

    -- Adds a new buyable item.
    --    names = A table containing one or more strings of alternative names to this item. Used only for old buy/sell system.
    --    itemid = The itemid of the buyable item
    --    cost = The price of one single item
    --    subType - The subType of each rune or fluidcontainer item. Can be left out if it is not a rune/fluidcontainer. Default value is 0 and 1 (depending on shop mode)
    --    realName - The real, full name for the item. Will be used as ITEMNAME in MESSAGE_ONBUY and MESSAGE_ONSELL if defined. Default value is nil (getItemNameById will be used)
    function ShopModule:addBuyableItem(names, itemid, cost, subType, realName)
        if(type(subType) == 'string' and realName == nil) then
            realName = subType
            subType = nil
        end

        local v = getItemInfo(itemid)
        if(SHOPMODULE_MODE ~= SHOPMODULE_MODE_TALK) then
            local item = {
                id = itemid,
                buy = cost,
                sell = -1,
                subType = tonumber(subType) or (v.charges > 0 and v.charges or 0),
                name = realName or v.name
            }

            for i, shopItem in ipairs(self.npcHandler.shopItems) do
                if(shopItem.id == item.id and (shopItem.subType == item.subType or shopItem.subType == 0)) then
                    if(item.sell ~= shopItem.sell) then
                        item.sell = shopItem.sell
                    end

                    self.npcHandler.shopItems = item
                    item = nil
                    break
                end
            end

            if(item ~= nil) then
                table.insert(self.npcHandler.shopItems, item)
            end
        end

        if(names ~= nil and SHOPMODULE_MODE ~= SHOPMODULE_MODE_TRADE) then
            local parameters = {
                itemid = itemid,
                cost = cost,
                eventType = SHOPMODULE_BUY_ITEM,
                module = self,
                realName = realName or v.name,
                subType = tonumber(subType) or (v.charges > 0 and v.charges or 1)
            }

            for i, name in pairs(names) do
                local keywords = {}
                table.insert(keywords, 'buy')
                table.insert(keywords, name)

                local node = self.npcHandler.keywordHandler:addKeyword(keywords, ShopModule.tradeItem, parameters)
                node:addChildKeywordNode(self.yesNode)
                node:addChildKeywordNode(self.noNode)
            end
        end
    end

    -- Adds a new buyable container of items.
    --    names = A table containing one or more strings of alternative names to this item.
    --    container = Backpack, bag or any other itemid of container where bought items will be stored
    --    itemid = The itemid of the buyable item
    --    cost = The price of one single item
    --    subType - The subType of each rune or fluidcontainer item. Can be left out if it is not a rune/fluidcontainer. Default value is 1.
    --    realName - The real, full name for the item. Will be used as ITEMNAME in MESSAGE_ONBUY and MESSAGE_ONSELL if defined. Default value is nil (getItemNameById will be used)
    function ShopModule:addBuyableItemContainer(names, container, itemid, cost, subType, realName)
        if(names ~= nil) then
            local v = getItemInfo(itemid)
            local parameters = {
                container = container,
                itemid = itemid,
                cost = cost,
                eventType = SHOPMODULE_BUY_ITEM_CONTAINER,
                module = self,
                realName = realName or v.name,
                subType = tonumber(subType) or (v.charges > 0 and v.charges or 1)
            }

            for i, name in pairs(names) do
                local keywords = {}
                table.insert(keywords, 'buy')
                table.insert(keywords, name)

                local node = self.npcHandler.keywordHandler:addKeyword(keywords, ShopModule.tradeItem, parameters)
                node:addChildKeywordNode(self.yesNode)
                node:addChildKeywordNode(self.noNode)
            end
        end
    end

    -- Adds a new sellable item.
    --    names = A table containing one or more strings of alternative names to this item. Used only by old buy/sell system.
    --    itemid = The itemid of the sellable item
    --    cost = The price of one single item
    --    realName - The real, full name for the item. Will be used as ITEMNAME in MESSAGE_ONBUY and MESSAGE_ONSELL if defined. Default value is nil (getItemNameById will be used)
    function ShopModule:addSellableItem(names, itemid, cost, realName)
        local v = getItemInfo(itemid)
        if(SHOPMODULE_MODE ~= SHOPMODULE_MODE_TALK) then
            local item = {
                id = itemid,
                buy = -1,
                sell = cost,
                subType = ((v.charges > 0 and v.stackable) and v.charges or 0),
                name = realName or v.name
            }

            for i, shopItem in ipairs(self.npcHandler.shopItems) do
                if(shopItem.id == item.id and shopItem.subType == item.subType) then
                    if(item.buy ~= shopItem.buy) then
                        item.buy = shopItem.buy
                    end

                    self.npcHandler.shopItems = item
                    item = nil
                    break
                end
            end

            if(item ~= nil) then
                table.insert(self.npcHandler.shopItems, item)
            end
        end

        if(names ~= nil and SHOPMODULE_MODE ~= SHOPMODULE_MODE_TRADE) then
            local parameters = {
                itemid = itemid,
                cost = cost,
                eventType = SHOPMODULE_SELL_ITEM,
                module = self,
                realName = realName or v.name
            }

            for i, name in pairs(names) do
                local keywords = {}
                table.insert(keywords, 'sell')
                table.insert(keywords, name)

                local node = self.npcHandler.keywordHandler:addKeyword(keywords, ShopModule.tradeItem, parameters)
                node:addChildKeywordNode(self.yesNode)
                node:addChildKeywordNode(self.noNode)
            end
        end
    end

    -- onModuleReset callback function. Calls ShopModule:reset()
    function ShopModule:callbackOnModuleReset()
        self:reset()
        return true
    end

    -- Callback onBuy() function. If you wish, you can change certain Npc to use your onBuy().
    function ShopModule:callbackOnBuy(cid, itemid, subType, amount, ignoreCap, inBackpacks)
        local shopItem = nil
        for _, item in ipairs(self.npcHandler.shopItems) do
            if(item.id == itemid and item.subType == subType) then
                shopItem = item
                break
            end
        end

        if(shopItem == nil) then
            print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'ShopModule.onBuy - Item not found on shopItems list')
            return false
        end

        if(shopItem.buy == -1) then
            print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'ShopModule.onBuy - Attempt to purchase an item which only sellable')
            return false
        end

        if(amount <= 0) then
            print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'ShopModule.onBuy - Attempt to purchase ' .. amount .. ' items')
            return false
        end
        local subType, count = shopItem.subType or 0, amount
        
        local backpack, backpackPrice, totalCost = 1988, 20, amount * shopItem.buy
        if(inBackpacks) then
            totalCost = totalCost + (math.max(1, math.floor(count / getContainerCapById(backpack))) * backpackPrice)
        end

        local parseInfo = {
            [TAG_PLAYERNAME] = getPlayerName(cid),
            [TAG_ITEMCOUNT] = amount,
            [TAG_TOTALCOST] = totalCost,
            [TAG_ITEMNAME] = shopItem.name
        }
        if(getPlayerMoney(cid) < totalCost) then
            local msg = self.npcHandler:getMessage(MESSAGE_NEEDMONEY)
            doPlayerSendCancel(cid, self.npcHandler:parseMessage(msg, parseInfo))
            return false
        end

        local a, b = doNpcSellItem(cid, itemid, count, subType, ignoreCap, inBackpacks, backpack)
        if(a < amount) then
            local msgId = MESSAGE_NEEDMORESPACE
            if(a == 0) then
                msgId = MESSAGE_NEEDSPACE
            end

            local msg = self.npcHandler:getMessage(msgId)
            parseInfo[TAG_ITEMCOUNT] = a

            doPlayerSendCancel(cid, self.npcHandler:parseMessage(msg, parseInfo))
            if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
                self.npcHandler.talkStart[cid] = os.time()
            else
                self.npcHandler.talkStart = os.time()
            end

            if(a > 0) then
                doPlayerRemoveMoney(cid, ((a * shopItem.buy) + (b * backpackPrice)))
                return true
            end

            return false
        end

        local msg = self.npcHandler:getMessage(MESSAGE_BOUGHT)
        doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, self.npcHandler:parseMessage(msg, parseInfo))

        doPlayerRemoveMoney(cid, totalCost)
        if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
            self.npcHandler.talkStart[cid] = os.time()
        else
            self.npcHandler.talkStart = os.time()
        end

        return true
    end

    -- Callback onSell() function. If you wish, you can change certain Npc to use your onSell().
    function ShopModule:callbackOnSell(cid, itemid, subType, amount, ignoreEquipped, dummy)
        local shopItem = nil
        for _, item in ipairs(self.npcHandler.shopItems) do
            if(item.id == itemid and item.subType == subType) then
                shopItem = item
                break
            end
        end

        if(shopItem == nil) then
            print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'ShopModule.onSell - Item not found on shopItems list')
            return false
        end

        if(shopItem.sell == -1) then
            print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'ShopModule.onSell - Attempt to sell an item which is only buyable')
            return false
        end

        local parseInfo = {
            [TAG_PLAYERNAME] = getPlayerName(cid),
            [TAG_ITEMCOUNT] = amount,
            [TAG_TOTALCOST] = amount * shopItem.sell,
            [TAG_ITEMNAME] = shopItem.name
        }

        if(subType < 1 or getItemInfo(itemid).stackable) then
            subType = -1
        end

        if(doPlayerRemoveItem(cid, itemid, amount, subType, ignoreEquipped)) then
            local msg = self.npcHandler:getMessage(MESSAGE_SOLD)
            doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, self.npcHandler:parseMessage(msg, parseInfo))

            doPlayerAddMoney(cid, amount * shopItem.sell)
            if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
                self.npcHandler.talkStart[cid] = os.time()
            else
                self.npcHandler.talkStart = os.time()
            end

            return true
        end

        local msg = self.npcHandler:getMessage(MESSAGE_NEEDITEM)
        doPlayerSendCancel(cid, self.npcHandler:parseMessage(msg, parseInfo))
        if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
            self.npcHandler.talkStart[cid] = os.time()
        else
            self.npcHandler.talkStart = os.time()
        end

        return false
    end

    -- Callback for requesting a trade window with the NPC.
    function ShopModule.requestTrade(cid, message, keywords, parameters, node)
        local module = parameters.module
        if(not module.npcHandler:isFocused(cid)) then
            return false
        end

        local shop = getShopOwner(cid)
        if(shop and shop == getNpcId()) then
            return true
        end

        if(table.maxn(module.npcHandler.shopItems) == 0) then
            local parseInfo = { [TAG_PLAYERNAME] = getPlayerName(cid) }
            local msg = module.npcHandler:parseMessage(module.npcHandler:getMessage(MESSAGE_NOSHOP), parseInfo)

            module.npcHandler:say(msg, cid)
            return true
        end

        local parseInfo = { [TAG_PLAYERNAME] = getPlayerName(cid) }
        local msg = module.npcHandler:parseMessage(module.npcHandler:getMessage(MESSAGE_SENDTRADE), parseInfo)
        addEvent(openShopWindow, 100, cid, module.npcHandler.shopItems,
            function(cid, itemid, subType, amount, ignoreCap, inBackpacks)
                module.npcHandler:onBuy(cid, itemid, subType, amount, ignoreCap, inBackpacks)
            end,
            function(cid, itemid, subType, amount, ignoreCap, inBackpacks)
                module.npcHandler:onSell(cid, itemid, subType, amount, ignoreCap, inBackpacks)
            end
        )

        module.npcHandler:say(msg, cid)
        return true
    end

    -- onConfirm keyword callback function. Sells/buys the actual item.
    function ShopModule.onConfirm(cid, message, keywords, parameters, node)
        local module = parameters.module
        if(not module.npcHandler:isFocused(cid)) then
            return false
        end

        local parentParameters = node:getParent():getParameters()
        local parseInfo = {
            [TAG_PLAYERNAME] = getPlayerName(cid),
            [TAG_ITEMCOUNT] = module.amount,
            [TAG_TOTALCOST] = parentParameters.cost * module.amount,
            [TAG_ITEMNAME] = parentParameters.realName
        }

        if(parentParameters.eventType == SHOPMODULE_SELL_ITEM) then
            local ret = doPlayerSellItem(cid, parentParameters.itemid, module.amount, parentParameters.cost * module.amount)
            if(ret) then
                local msg = module.npcHandler:getMessage(MESSAGE_ONSELL)
                msg = module.npcHandler:parseMessage(msg, parseInfo)
                module.npcHandler:say(msg, cid)
            else
                local msg = module.npcHandler:getMessage(MESSAGE_MISSINGITEM)
                msg = module.npcHandler:parseMessage(msg, parseInfo)
                module.npcHandler:say(msg, cid)
            end
        elseif(parentParameters.eventType == SHOPMODULE_BUY_ITEM) then
            local ret = doPlayerBuyItem(cid, parentParameters.itemid, module.amount, parentParameters.cost * module.amount, parentParameters.subType)
            if(ret) then
                if parentParameters.itemid == ITEM_PARCEL then
                    doPlayerBuyItem(cid, ITEM_LABEL, module.amount, 0, parentParameters.subType)
                end
                local msg = module.npcHandler:getMessage(MESSAGE_ONBUY)
                msg = module.npcHandler:parseMessage(msg, parseInfo)
                module.npcHandler:say(msg, cid)
            else
                local msg = module.npcHandler:getMessage(MESSAGE_MISSINGMONEY)
                msg = module.npcHandler:parseMessage(msg, parseInfo)
                module.npcHandler:say(msg, cid)
            end
        elseif(parentParameters.eventType == SHOPMODULE_BUY_ITEM_CONTAINER) then
            local ret = doPlayerBuyItemContainer(cid, parentParameters.container, parentParameters.itemid, module.amount, parentParameters.cost * module.amount, parentParameters.subType)
            if(ret) then
                local msg = module.npcHandler:getMessage(MESSAGE_ONBUY)
                msg = module.npcHandler:parseMessage(msg, parseInfo)
                module.npcHandler:say(msg, cid)
            else
                local msg = module.npcHandler:getMessage(MESSAGE_MISSINGMONEY)
                msg = module.npcHandler:parseMessage(msg, parseInfo)
                module.npcHandler:say(msg, cid)
            end
        end

        module.npcHandler:resetNpc(cid)
        return true
    end

    -- onDecliune keyword callback function. Generally called when the player sais 'no' after wanting to buy an item.
    function ShopModule.onDecline(cid, message, keywords, parameters, node)
        local module = parameters.module
        if(not module.npcHandler:isFocused(cid)) then
            return false
        end

        local parentParameters = node:getParent():getParameters()
        local parseInfo = {
            [TAG_PLAYERNAME] = getPlayerName(cid),
            [TAG_ITEMCOUNT] = module.amount,
            [TAG_TOTALCOST] = parentParameters.cost * module.amount,
            [TAG_ITEMNAME] = parentParameters.realName
        }

        local msg = module.npcHandler:parseMessage(module.noText, parseInfo)
        module.npcHandler:say(msg, cid)
        module.npcHandler:resetNpc(cid)
        return true
    end

    -- tradeItem callback function. Makes the npc say the message defined by MESSAGE_BUY or MESSAGE_SELL
    function ShopModule.tradeItem(cid, message, keywords, parameters, node)
        local module = parameters.module
        if(not module.npcHandler:isFocused(cid)) then
            return false
        end

        local count = module:getCount(message)
        module.amount = count
        local parseInfo = {
            [TAG_PLAYERNAME] = getPlayerName(cid),
            [TAG_ITEMCOUNT] = module.amount,
            [TAG_TOTALCOST] = parameters.cost * module.amount,
            [TAG_ITEMNAME] = parameters.realName
        }

        if(parameters.eventType == SHOPMODULE_SELL_ITEM) then
            local msg = module.npcHandler:getMessage(MESSAGE_SELL)
            msg = module.npcHandler:parseMessage(msg, parseInfo)
            module.npcHandler:say(msg, cid)
        elseif(parameters.eventType == SHOPMODULE_BUY_ITEM) then
            local msg = module.npcHandler:getMessage(MESSAGE_BUY)
            msg = module.npcHandler:parseMessage(msg, parseInfo)
            module.npcHandler:say(msg, cid)
        elseif(parameters.eventType == SHOPMODULE_BUY_ITEM_CONTAINER) then
            local msg = module.npcHandler:getMessage(MESSAGE_BUY)
            msg = module.npcHandler:parseMessage(msg, parseInfo)
            module.npcHandler:say(msg, cid)
        end

        return true
    end
end
 

modules.lua

PoccnnP
25 de maio de 2016 às 19:57

Isso acontece com todos ps items ou algum específico? 

Isso acontece apenas com o trade system ou somente falando com o npc?

Tenta detalhar o máximo o procedimento que gera o erro.

je19921992J
26 de maio de 2016 às 00:53

bom, é assim: Tenho 5 kk de capacidade, tenho 1 bp, e tento comprar potions e/ou sd; consigo comprar até encher os espaços na bp, mesmo tendo capacidade, não consigo comprar mais por não ter espaço... Mas o que acontece eh que mesmo com 15 backpacks, ele para de comprar quando enche a primeira backpack... E aparece a mensagem falando que eu não tenho capacidade:

Veja a photo

2016-05-26.png

2016-05-26.thumb.png.f63d7e2ba1acd392a879e2fcd45659c3.png

je19921992J
27 de maio de 2016 às 18:26

up

PoccnnP
27 de maio de 2016 às 19:05

Eu ainda não entendi bem. Na imagem, ele usa duas bolsas, uma no slot de bp e outra no de munições. 

O que está acontecendo seria, você compra objetos até que a bp que está no slot de backpack fique cheia mas, a que está no slot de munição não está sendo adicionado nela.

Esse seria o problema? 

Yan LiimaY
27 de maio de 2016 às 19:52

Já tentou mudar de distro e fazer o teste? Ouvi dizer que na tfs 0.3.6 tem muitos bugs parecido com este seu ai...

Faz assim, pegue qualquer distro que não seja 0.3.6. Pode ser a 0.4 e faça o teste. Se continuar dando isto saberemos que não é a distro, mais se não der mais este problema saberemos que é a distro.

 

Se realmente for nas sources acho que eu posso te ajudar.

je19921992J
28 de maio de 2016 às 00:41

entao, o problema que a unica distro que consigo usar eh essa 0.3.6 - passar para 0.4 eh basicamente impossivel (BUGA NPC, MONSTER E OUTROS) mesmo mudando os nomes tipo no script "xodet.lua" e no local "Xodet.lua" maiuscula... Eh erro tipo nas LIBs, mas respondendo a outra pergunta, tanto faz deixar só no slot de BP, ou colocar no Slot de flexas;

Quando enche a primeira Backpack, ele trava! Para de comprar

Yan LiimaY
28 de maio de 2016 às 00:43
22 horas atrás, je19921992 disse:

entao, o problema que a unica distro que consigo usar eh essa 0.3.6 - passar para 0.4 eh basicamente impossivel (BUGA NPC, MONSTER E OUTROS) mesmo mudando os nomes tipo no script "xodet.lua" e no local "Xodet.lua" maiuscula... Eh erro tipo nas LIBs, mas respondendo a outra pergunta, tanto faz deixar só no slot de BP, ou colocar no Slot de flexas;

Quando enche a primeira Backpack, ele trava! Para de comprar

 

Então gostaria de fazer um teste com essa mesmo? você tem a source?

Editado Maio 28 por nedroesdoksdja

je19921992J
28 de maio de 2016 às 22:49

tenho as sources

gostaria sim de fazer teste nessa

 

Editado Maio 28 por je19921992

Yan LiimaY
28 de maio de 2016 às 22:55

Não creio que isso irá resolver seu problema, mais se não resolver pelomenos o do BOT irá resolver...

 

Em npc.cpp procure por isto

Spoiler

if(NpcState* npcState = getState(player, true))

                {

   npcState->amount = amount;

   npcState->subType = count;

   npcState->itemId = itemId;

   npcState->buyPrice = getListItemPrice(itemId, SHOPEVENT_BUY);

   npcState->ignoreCap = ignoreCap;

   npcState->inBackpacks = inBackpacks;


   const NpcResponse* response = getResponse(player, npcState, EVENT_PLAYER_SHOPBUY);

   executeResponse(player, npcState, response);

  }

E substitui por isso:

Spoiler

if(NpcState* npcState = getState(player, true))

{

if(amount <= 0){

amount = 1;

}

   npcState->amount = amount;

   npcState->subType = count;

   npcState->itemId = itemId;

   npcState->buyPrice = getListItemPrice(itemId, SHOPEVENT_BUY);

   npcState->ignoreCap = ignoreCap;

   npcState->inBackpacks = inBackpacks;


   const NpcResponse* response = getResponse(player, npcState, EVENT_PLAYER_SHOPBUY);

   executeResponse(player, npcState, response);

  }

Se por acaso o seu já estiver com o segundo, troque pelo primeiro

 

Se isso não resolver se quiser testar estarei deixando uma LIB dos NPC's.

 

NPC-LIB.rar

NPC-LIB.rar

Editado Maio 28 por nedroesdoksdja