Ir para conteúdo
  • 0

Ajudem NPC com Bug na hora de comprar Potions Runas Etc


je19921992

Pergunta

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

Link para o comentário
Compartilhar em outros sites

13 respostass a esta questão

Posts Recomendados

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

Link para o comentário
Compartilhar em outros sites

  • 0

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.

Link para o comentário
Compartilhar em outros sites

  • 0

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

Link para o comentário
Compartilhar em outros sites

  • 0

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? 

Link para o comentário
Compartilhar em outros sites

  • 0
  • Diretor

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.

Link para o comentário
Compartilhar em outros sites

  • 0

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

Link para o comentário
Compartilhar em outros sites

  • 0
  • Diretor
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 por nedroesdoksdja
Link para o comentário
Compartilhar em outros sites

  • 0
  • Diretor

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 por nedroesdoksdja
Link para o comentário
Compartilhar em outros sites

×
×
  • Criar Novo...