Guest User

modules lua for crying damson 8.6

a guest
Mar 11th, 2017
148
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 45.67 KB | None | 0 0
  1. -- Advanced NPC System (Created by Jiddo),
  2. -- Modified by TheForgottenServer Team.
  3.  
  4. if(Modules == nil) then
  5.     -- Constants used to separate buying from selling.
  6.     SHOPMODULE_SELL_ITEM = 1
  7.     SHOPMODULE_BUY_ITEM = 2
  8.     SHOPMODULE_BUY_ITEM_CONTAINER = 3
  9.  
  10.     -- Constants used for shop mode. Notice: addBuyableItemContainer is working on all modes
  11.     SHOPMODULE_MODE_TALK = 1 -- Old system used before Tibia 8.2: sell/buy item name
  12.     SHOPMODULE_MODE_TRADE = 2 -- Trade window system introduced in Tibia 8.2
  13.     SHOPMODULE_MODE_BOTH = 3 -- Both working at one time
  14.  
  15.     -- Used in shop mode
  16.     SHOPMODULE_MODE = SHOPMODULE_MODE_BOTH
  17.  
  18.     -- Constants used for outfit giving mode
  19.     OUTFITMODULE_FUNCTION_OLD = { doPlayerAddOutfit, canPlayerWearOutfit } -- lookType usage
  20.     OUTFITMODULE_FUNCTION_NEW = { doPlayerAddOutfitId, canPlayerWearOutfitId } -- OutfitId usage
  21.  
  22.     -- Used in outfit module
  23.     OUTFITMODULE_FUNCTION = OUTFITMODULE_FUNCTION_NEW
  24.     if(OUTFITMODULE_FUNCTION[1] == nil or OUTFITMODULE_FUNCTION[2] == nil) then
  25.         OUTFITMODULE_FUNCTION = OUTFITMODULE_FUNCTION_OLD
  26.     end
  27.  
  28.     Modules = {
  29.         parseableModules = {}
  30.     }
  31.  
  32.     StdModule = {}
  33.  
  34.     -- These callback function must be called with parameters.npcHandler = npcHandler in the parameters table or they will not work correctly.
  35.     -- Notice: The members of StdModule have not yet been tested. If you find any bugs, please report them to me.
  36.     -- Usage:
  37.         -- keywordHandler:addKeyword({'offer'}, StdModule.say, {npcHandler = npcHandler, text = 'I sell many powerful melee weapons.'})
  38.     function StdModule.say(cid, message, keywords, parameters, node)
  39.         local npcHandler = parameters.npcHandler
  40.         if(npcHandler == nil) then
  41.             print('StdModule.say called without any npcHandler instance.')
  42.             return false
  43.         end
  44.  
  45.         local onlyFocus = (parameters.onlyFocus == nil or parameters.onlyFocus == true)
  46.         if(not npcHandler:isFocused(cid) and onlyFocus) then
  47.             return false
  48.         end
  49.  
  50.         local parseInfo = {[TAG_PLAYERNAME] = getCreatureName(cid)}
  51.         npcHandler:say(npcHandler:parseMessage(parameters.text or parameters.message, parseInfo), cid, parameters.publicize and true)
  52.         if(parameters.reset == true) then
  53.             npcHandler:resetNpc()
  54.         elseif(parameters.moveup ~= nil and type(parameters.moveup) == 'number') then
  55.             npcHandler.keywordHandler:moveUp(parameters.moveup)
  56.         end
  57.  
  58.         return true
  59.     end
  60.  
  61.     --Usage:
  62.         -- 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?'})
  63.         --      node1:addChildKeyword({'yes'}, StdModule.promotePlayer, {npcHandler = npcHandler, cost = 20000, promotion = 1, level = 20}, text = 'Congratulations! You are now promoted.')
  64.         --      node1:addChildKeyword({'no'}, StdModule.say, {npcHandler = npcHandler, text = 'Alright then, come back when you are ready.'}, reset = true)
  65.     function StdModule.promotePlayer(cid, message, keywords, parameters, node)
  66.         local npcHandler = parameters.npcHandler
  67.         if(npcHandler == nil) then
  68.             print('StdModule.promotePlayer called without any npcHandler instance.')
  69.             return false
  70.         end
  71.  
  72.         if(not npcHandler:isFocused(cid)) then
  73.             return false
  74.         end
  75.  
  76.         if(isPlayerPremiumCallback(cid) or not getBooleanFromString(getConfigValue('premiumForPromotion')) or not(parameters.premium)) then
  77.             if(getPlayerPromotionLevel(cid) >= parameters.promotion) then
  78.                 npcHandler:say('You are already promoted!', cid)
  79.             elseif(getPlayerLevel(cid) < parameters.level) then
  80.                 npcHandler:say('I am sorry, but I can only promote you once you have reached level ' .. parameters.level .. '.', cid)
  81.             elseif(not doPlayerRemoveMoney(cid, parameters.cost)) then
  82.                 npcHandler:say('You do not have enough money!', cid)
  83.             else
  84.                 setPlayerPromotionLevel(cid, parameters.promotion)
  85.                 npcHandler:say(parameters.text, cid)
  86.             end
  87.         else
  88.             npcHandler:say("You need a premium account in order to get promoted.", cid)
  89.         end
  90.  
  91.         npcHandler:resetNpc()
  92.         return true
  93.     end
  94.  
  95.     function StdModule.learnSpell(cid, message, keywords, parameters, node)
  96.         local npcHandler = parameters.npcHandler
  97.         if(npcHandler == nil) then
  98.             print('StdModule.learnSpell called without any npcHandler instance.')
  99.             return false
  100.         end
  101.  
  102.         if(not npcHandler:isFocused(cid)) then
  103.             return false
  104.         end
  105.  
  106.         if(isPlayerPremiumCallback(cid) or not(parameters.premium)) then
  107.             if(getPlayerLearnedInstantSpell(cid, parameters.spellName)) then
  108.                 npcHandler:say('You already know this spell.', cid)
  109.             elseif(getPlayerLevel(cid) < parameters.level) then
  110.                 npcHandler:say('You need to obtain a level of ' .. parameters.level .. ' or higher to be able to learn ' .. parameters.spellName .. '.', cid)
  111.             elseif(not parameters.vocation(cid)) then
  112.                 npcHandler:say('This spell is not for your vocation', cid)
  113.             elseif(not doPlayerRemoveMoney(cid, parameters.price)) then
  114.                 npcHandler:say('You do not have enough money, this spell costs ' .. parameters.price .. ' gold coins.', cid)
  115.             else
  116.                 npcHandler:say('You have learned ' .. parameters.spellName .. '.', cid)
  117.                 playerLearnInstantSpell(cid, parameters.spellName)
  118.             end
  119.         else
  120.             npcHandler:say('You need a premium account in order to buy ' .. parameters.spellName .. '.', cid)
  121.         end
  122.  
  123.         npcHandler:resetNpc()
  124.         return true
  125.     end
  126.  
  127.     function StdModule.bless(cid, message, keywords, parameters, node)
  128.         local npcHandler = parameters.npcHandler
  129.         if(npcHandler == nil) then
  130.             print('StdModule.bless called without any npcHandler instance.')
  131.             return false
  132.         end
  133.  
  134.         if(not getBooleanFromString(getConfigValue('blessings'))) then
  135.             npcHandler:say("Sorry, but Gods moved back my permission to bless anyone.", cid)
  136.             return false
  137.         end
  138.  
  139.         if(not npcHandler:isFocused(cid)) then
  140.             return false
  141.         end
  142.  
  143.         if(isPlayerPremiumCallback(cid) or not getBooleanFromString(getConfigValue('blessingsOnlyPremium')) or not parameters.premium) then
  144.             local price = parameters.baseCost
  145.             if(getPlayerLevel(cid) > parameters.startLevel) then
  146.                 price = (price + ((math.min(parameters.endLevel, getPlayerLevel(cid)) - parameters.startLevel) * parameters.levelCost))
  147.             end
  148.  
  149.             if(getPlayerBlessing(cid, parameters.number)) then
  150.                 npcHandler:say("Gods have already blessed you with this blessing!", cid)
  151.             elseif(not doPlayerRemoveMoney(cid, price)) then
  152.                 npcHandler:say("You don't have enough money for blessing.", cid)
  153.             else
  154.                 npcHandler:say("You have been blessed by one of the five gods!", cid)
  155.                 doPlayerAddBlessing(cid, parameters.number)
  156.             end
  157.         else
  158.             npcHandler:say('You need a premium account in order to be blessed.', cid)
  159.         end
  160.  
  161.         npcHandler:resetNpc()
  162.         return true
  163.     end
  164.  
  165.     function StdModule.travel(cid, message, keywords, parameters, node)
  166.         local npcHandler = parameters.npcHandler
  167.         if(npcHandler == nil) then
  168.             print('StdModule.travel called without any npcHandler instance.')
  169.             return false
  170.         end
  171.  
  172.         if(not npcHandler:isFocused(cid)) then
  173.             return false
  174.         end
  175.  
  176.         local storage, pzLocked = parameters.storageValue or (EMPTY_STORAGE + 1), parameters.allowLocked or false
  177.         if(parameters.premium and not isPlayerPremiumCallback(cid)) then
  178.             npcHandler:say('I can only allow premium players to travel with me.', cid)
  179.         elseif(parameters.level ~= nil and getPlayerLevel(cid) < parameters.level) then
  180.             npcHandler:say('You must reach level ' .. parameters.level .. ' before I can let you go there.', cid)
  181.         elseif(parameters.storageId ~= nil and getPlayerStorageValue(cid, parameters.storageId) < storage) then
  182.             npcHandler:say(parameters.storageInfo or 'You may not travel there!', cid)
  183.         elseif(not pzLocked and isPlayerPzLocked(cid)) then
  184.             npcHandler:say('Get out of there with this blood!', cid)
  185.         elseif(not doPlayerRemoveMoney(cid, parameters.cost)) then
  186.             npcHandler:say('You do not have enough money.', cid)
  187.         else
  188.             npcHandler:say('It was a pleasure doing business with you.', cid)
  189.             npcHandler:releaseFocus(cid)
  190.  
  191.             doTeleportThing(cid, parameters.destination, false)
  192.             doSendMagicEffect(parameters.destination, CONST_ME_TELEPORT)
  193.         end
  194.  
  195.         npcHandler:resetNpc()
  196.         return true
  197.     end
  198.  
  199.     FocusModule = {
  200.         npcHandler = nil
  201.     }
  202.  
  203.     -- Creates a new instance of FocusModule without an associated NpcHandler.
  204.     function FocusModule:new()
  205.         local obj = {}
  206.         setmetatable(obj, self)
  207.         self.__index = self
  208.         return obj
  209.     end
  210.  
  211.     -- Inits the module and associates handler to it.
  212.     function FocusModule:init(handler)
  213.         self.npcHandler = handler
  214.         for i, word in pairs(FOCUS_GREETWORDS) do
  215.             local obj = {}
  216.             table.insert(obj, word)
  217.             obj.callback = FOCUS_GREETWORDS.callback or FocusModule.messageMatcher
  218.             handler.keywordHandler:addKeyword(obj, FocusModule.onGreet, {module = self})
  219.         end
  220.  
  221.         for i, word in pairs(FOCUS_FAREWELLWORDS) do
  222.             local obj = {}
  223.             table.insert(obj, word)
  224.             obj.callback = FOCUS_FAREWELLWORDS.callback or FocusModule.messageMatcher
  225.             handler.keywordHandler:addKeyword(obj, FocusModule.onFarewell, {module = self})
  226.         end
  227.     end
  228.  
  229.     -- Greeting callback function.
  230.     function FocusModule.onGreet(cid, message, keywords, parameters)
  231.         parameters.module.npcHandler:onGreet(cid)
  232.         return true
  233.     end
  234.  
  235.     -- UnGreeting callback function.
  236.     function FocusModule.onFarewell(cid, message, keywords, parameters)
  237.         if(not parameters.module.npcHandler:isFocused(cid)) then
  238.             return false
  239.         end
  240.  
  241.         parameters.module.npcHandler:onFarewell(cid)
  242.         return true
  243.     end
  244.  
  245.     -- Custom message matching callback function for greeting messages.
  246.     function FocusModule.messageMatcher(keywords, message)
  247.         local spectators = getSpectators(getCreaturePosition(getNpcId()), 7, 7)
  248.         for i, word in pairs(keywords) do
  249.             if(type(word) == 'string') then
  250.                 if(string.find(message, word) and not string.find(message, '[%w+]' .. word) and not string.find(message, word .. '[%w+]')) then
  251.                     if(string.find(message, getCreatureName(getNpcId()))) then
  252.                         return true
  253.                     end
  254.  
  255.                     for i, uid in ipairs(spectators) do
  256.                         if(string.find(message, getCreatureName(uid))) then
  257.                             return false
  258.                         end
  259.                     end
  260.  
  261.                     return true
  262.                 end
  263.             end
  264.         end
  265.  
  266.         return false
  267.     end
  268.  
  269.     KeywordModule = {
  270.         npcHandler = nil
  271.     }
  272.     -- Add it to the parseable module list.
  273.     Modules.parseableModules['module_keywords'] = KeywordModule
  274.  
  275.     function KeywordModule:new()
  276.         local obj = {}
  277.         setmetatable(obj, self)
  278.         self.__index = self
  279.         return obj
  280.     end
  281.  
  282.     function KeywordModule:init(handler)
  283.         self.npcHandler = handler
  284.     end
  285.  
  286.     -- Parses all known parameters.
  287.     function KeywordModule:parseParameters()
  288.         local ret = NpcSystem.getParameter('keywords')
  289.         if(ret ~= nil) then
  290.             self:parseKeywords(ret)
  291.         end
  292.     end
  293.  
  294.     function KeywordModule:parseKeywords(data)
  295.         local n = 1
  296.         for keys in string.gmatch(data, '[^;]+') do
  297.             local i = 1
  298.  
  299.             local keywords = {}
  300.             for temp in string.gmatch(keys, '[^,]+') do
  301.                 table.insert(keywords, temp)
  302.                 i = i + 1
  303.             end
  304.  
  305.             if(i ~= 1) then
  306.                 local reply = NpcSystem.getParameter('keyword_reply' .. n)
  307.                 if(reply ~= nil) then
  308.                     self:addKeyword(keywords, reply)
  309.                 else
  310.                     print('[Warning] NpcSystem:', 'Parameter \'' .. 'keyword_reply' .. n .. '\' missing. Skipping...')
  311.                 end
  312.             else
  313.                 print('[Warning] NpcSystem:', 'No keywords found for keyword set #' .. n .. '. Skipping...')
  314.             end
  315.  
  316.             n = n + 1
  317.         end
  318.     end
  319.  
  320.     function KeywordModule:addKeyword(keywords, reply)
  321.         self.npcHandler.keywordHandler:addKeyword(keywords, StdModule.say, {npcHandler = self.npcHandler, onlyFocus = true, text = reply, reset = true})
  322.     end
  323.  
  324.     TravelModule = {
  325.         npcHandler = nil,
  326.         destinations = nil,
  327.         yesNode = nil,
  328.         noNode = nil,
  329.     }
  330.     -- Add it to the parseable module list.
  331.     Modules.parseableModules['module_travel'] = TravelModule
  332.  
  333.     function TravelModule:new()
  334.         local obj = {}
  335.         setmetatable(obj, self)
  336.         self.__index = self
  337.         return obj
  338.     end
  339.  
  340.     function TravelModule:init(handler)
  341.         self.npcHandler = handler
  342.         self.yesNode = KeywordNode:new(SHOP_YESWORD, TravelModule.onConfirm, {module = self})
  343.         self.noNode = KeywordNode:new(SHOP_NOWORD, TravelModule.onDecline, {module = self})
  344.  
  345.         self.destinations = {}
  346.     end
  347.  
  348.     -- Parses all known parameters.
  349.     function TravelModule:parseParameters()
  350.         local ret = NpcSystem.getParameter('travel_destinations')
  351.         if(ret ~= nil) then
  352.             self:parseDestinations(ret)
  353.             for _, word in ipairs({'destination', 'list', 'where', 'travel'}) do
  354.                 self.npcHandler.keywordHandler:addKeyword({word}, TravelModule.listDestinations, {module = self})
  355.             end
  356.         end
  357.     end
  358.  
  359.     function TravelModule:parseDestinations(data)
  360.         for destination in string.gmatch(data, '[^;]+') do
  361.             local i, name, pos, cost, premium, level, storage = 1, nil, {x = nil, y = nil, z = nil}, nil, false
  362.             for tmp in string.gmatch(destination, '[^,]+') do
  363.                 if(i == 1) then
  364.                     name = tmp
  365.                 elseif(i == 2) then
  366.                     pos.x = tonumber(tmp)
  367.                 elseif(i == 3) then
  368.                     pos.y = tonumber(tmp)
  369.                 elseif(i == 4) then
  370.                     pos.z = tonumber(tmp)
  371.                 elseif(i == 5) then
  372.                     cost = tonumber(tmp)
  373.                 elseif(i == 6) then
  374.                     premium = getBooleanFromString(tmp)
  375.                 else
  376.                     print('[Warning] NpcSystem:', 'Unknown parameter found in travel destination parameter.', tmp, destination)
  377.                 end
  378.  
  379.                 i = i + 1
  380.             end
  381.  
  382.             if(name ~= nil and pos.x ~= nil and pos.y ~= nil and pos.z ~= nil and cost ~= nil) then
  383.                 self:addDestination(name, pos, cost, premium)
  384.             else
  385.                 print('[Warning] NpcSystem:', 'Parameter(s) missing for travel destination:', name, pos, cost, premium)
  386.             end
  387.         end
  388.     end
  389.  
  390.     function TravelModule:addDestination(name, position, price, premium)
  391.         table.insert(self.destinations, name)
  392.         local parameters = {
  393.             cost = price,
  394.             destination = position,
  395.             premium = premium,
  396.             module = self
  397.         }
  398.  
  399.         local keywords, bringwords = {}, {}
  400.         table.insert(keywords, name)
  401.  
  402.         table.insert(bringwords, 'bring me to ' .. name)
  403.         self.npcHandler.keywordHandler:addKeyword(bringwords, TravelModule.bring, parameters)
  404.  
  405.         local node = self.npcHandler.keywordHandler:addKeyword(keywords, TravelModule.travel, parameters)
  406.         node:addChildKeywordNode(self.yesNode)
  407.         node:addChildKeywordNode(self.noNode)
  408.     end
  409.  
  410.     function TravelModule.travel(cid, message, keywords, parameters, node)
  411.         local module = parameters.module
  412.         if(not module.npcHandler:isFocused(cid)) then
  413.             return false
  414.         end
  415.  
  416.         module.npcHandler:say('Do you want to travel to ' .. keywords[1] .. ' for ' .. parameters.cost .. ' gold coins?', cid)
  417.         return true
  418.     end
  419.  
  420.     function TravelModule.onConfirm(cid, message, keywords, parameters, node)
  421.         local module = parameters.module
  422.         if(not module.npcHandler:isFocused(cid)) then
  423.             return false
  424.         end
  425.  
  426.         local parent = node:getParent():getParameters()
  427.         if(isPlayerPremiumCallback(cid) or not parent.premium) then
  428.             if(not isPlayerPzLocked(cid)) then
  429.                 if(doPlayerRemoveMoney(cid, parent.cost)) then
  430.                     module.npcHandler:say('It was a pleasure doing business with you.', cid)
  431.                     module.npcHandler:releaseFocus(cid)
  432.  
  433.                     doTeleportThing(cid, parent.destination, true)
  434.                     doSendMagicEffect(parent.destination, CONST_ME_TELEPORT)
  435.                 else
  436.                     module.npcHandler:say('You do not have enough money.', cid)
  437.                 end
  438.             else
  439.                 module.npcHandler:say('Get out of there with this blood!', cid)
  440.             end
  441.         else
  442.             module.npcHandler:say('I can only allow premium players to travel there.', cid)
  443.         end
  444.  
  445.         module.npcHandler:resetNpc()
  446.         return true
  447.     end
  448.  
  449.     -- onDecline keyword callback function. Generally called when the player sais 'no' after wanting to buy an item.
  450.     function TravelModule.onDecline(cid, message, keywords, parameters, node)
  451.         local module = parameters.module
  452.         if(not module.npcHandler:isFocused(cid)) then
  453.             return false
  454.         end
  455.  
  456.         module.npcHandler:say(module.npcHandler:parseMessage(module.npcHandler:getMessage(MESSAGE_DECLINE), {[TAG_PLAYERNAME] = getCreatureName(cid)}), cid)
  457.         module.npcHandler:resetNpc()
  458.         return true
  459.     end
  460.  
  461.     function TravelModule.bring(cid, message, keywords, parameters, node)
  462.         local module = parameters.module
  463.         if(not module.npcHandler:isFocused(cid)) then
  464.             return false
  465.         end
  466.  
  467.         if((isPlayerPremiumCallback(cid) or not parameters.premium) and not isPlayerPzLocked(cid) and doPlayerRemoveMoney(cid, parameters.cost)) then
  468.             module.npcHandler:say('Sure!', cid)
  469.             module.npcHandler:releaseFocus(cid)
  470.  
  471.             doTeleportThing(cid, parameters.destination, false)
  472.             doSendMagicEffect(parameters.destination, CONST_ME_TELEPORT)
  473.         end
  474.  
  475.         module.npcHandler:releaseFocus(cid)
  476.         return true
  477.     end
  478.  
  479.     function TravelModule.listDestinations(cid, message, keywords, parameters, node)
  480.         local module = parameters.module
  481.         if(not module.npcHandler:isFocused(cid)) then
  482.             return false
  483.         end
  484.  
  485.         local msg = nil
  486.         for _, destination in ipairs(module.destinations) do
  487.             if(msg ~= nil) then
  488.                 msg = msg .. ", "
  489.             else
  490.                 msg = ""
  491.             end
  492.  
  493.             msg = msg .. "{" .. destination .. "}"
  494.         end
  495.  
  496.         module.npcHandler:say(msg .. ".", cid)
  497.         module.npcHandler:resetNpc()
  498.         return true
  499.     end
  500.  
  501.     OutfitModule = {
  502.         npcHandler = nil,
  503.         outfits = nil,
  504.         yesNode = nil,
  505.         noNode = nil,
  506.     }
  507.     -- Add it to the parseable module list.
  508.     Modules.parseableModules['module_outfit'] = OutfitModule
  509.  
  510.     function OutfitModule:new()
  511.         if(OUTFITMODULE_FUNCTION[1] == nil or OUTFITMODULE_FUNCTION[2] == nil) then
  512.             return nil
  513.         end
  514.  
  515.         local obj = {}
  516.         setmetatable(obj, self)
  517.         self.__index = self
  518.         return obj
  519.     end
  520.  
  521.     function OutfitModule:init(handler)
  522.         self.npcHandler = handler
  523.         self.yesNode = KeywordNode:new(SHOP_YESWORD, OutfitModule.onConfirm, {module = self})
  524.         self.noNode = KeywordNode:new(SHOP_NOWORD, OutfitModule.onDecline, {module = self})
  525.  
  526.         self.outfits = {}
  527.     end
  528.  
  529.     -- Parses all known parameters.
  530.     function OutfitModule:parseParameters()
  531.         local ret = NpcSystem.getParameter('outfits')
  532.         if(ret ~= nil) then
  533.             self:parseKeywords(ret)
  534.             for _, word in ipairs({'outfits', 'addons'}) do
  535.                 self.npcHandler.keywordHandler:addKeyword({word}, OutfitModule.listOutfits, {module = self})
  536.             end
  537.         end
  538.     end
  539.  
  540.     function OutfitModule:parseKeywords(data)
  541.         local n = 1
  542.         for outfit in string.gmatch(data, '[^;]+') do
  543.             local i, keywords = 1, {}
  544.             for tmp in string.gmatch(outfit, '[^,]+') do
  545.                 table.insert(keywords, tmp)
  546.                 i = i + 1
  547.             end
  548.  
  549.             if(i > 0) then
  550.                 local ret = NpcSystem.getParameter('outfit' .. n)
  551.                 if(ret ~= nil) then
  552.                     self:parseList(keywords, ret)
  553.                 else
  554.                     print('[Warning] NpcSystem:', 'Missing \'outfit' .. n .. '\' parameter, skipping...')
  555.                 end
  556.             else
  557.                 print('[Warning] NpcSystem:', 'No keywords found for outfit set #' .. n .. ', skipping...')
  558.             end
  559.  
  560.             n = n + 1
  561.         end
  562.     end
  563.  
  564.     function OutfitModule:parseList(keywords, data)
  565.         local outfit, items = nil, {}
  566.         for list in string.gmatch(data, '[^;]+') do
  567.             local a, b, c, d, e = nil, nil, nil, nil, 1
  568.             for tmp in string.gmatch(list, '[^,]+') do
  569.                 if(e == 1) then
  570.                     a = tmp
  571.                 elseif(e == 2) then
  572.                     b = tmp
  573.                 elseif(e == 3) then
  574.                     c = tmp
  575.                 elseif(e == 4) then
  576.                     d = tmp
  577.                 else
  578.                     print('[Warning] NpcSystem:', 'Unknown parameter found in outfit list while parsing ' .. (outfit == nil and 'outfit' or 'item') .. '.', tmp, list)
  579.                 end
  580.  
  581.                 e = e + 1
  582.             end
  583.  
  584.             if(outfit == nil) then
  585.                 outfit = {tonumber(a), tonumber(b), getBooleanFromString(c), d}
  586.             elseif(a ~= nil) then
  587.                 local tmp = tonumber(a)
  588.                 if((tmp ~= nil or tostring(a) == "money") and b ~= nil and c ~= nil) then
  589.                     a = tmp or 20000
  590.                     tmp = tonumber(d)
  591.                     if(tmp == nil) then
  592.                         tmp = -1
  593.                     end
  594.  
  595.                     items[a] = {b, tmp, c}
  596.                 else
  597.                     print('[Warning] NpcSystem:', 'Missing parameter(s) for outfit items.', b, c, d)
  598.                 end
  599.             else
  600.                 print('[Warning] NpcSystem:', 'Missing base parameter for outfit items.', a)
  601.             end
  602.         end
  603.  
  604.         if(type(outfit) == 'table') then
  605.             local tmp = true
  606.             for i = 1, 2 do
  607.                 if(outfit[i] == nil) then
  608.                     tmp = false
  609.                     break
  610.                 end
  611.             end
  612.  
  613.             if(tmp and table.maxn(items) > 0) then
  614.                 self:addOutfit(keywords, outfit, items)
  615.             else
  616.                 print('[Warning] NpcSystem:', 'Invalid outfit, addon or empty items pool.', data)
  617.             end
  618.         end
  619.     end
  620.  
  621.     function OutfitModule:addOutfit(keywords, outfit, items)
  622.         table.insert(self.outfits, keywords[1])
  623.         local parameters = {
  624.             outfit = outfit[1],
  625.             addon = outfit[2],
  626.             premium = outfit[3],
  627.             gender = nil,
  628.             items = items,
  629.             module = self
  630.         }
  631.  
  632.         if(outfit[4] ~= nil) then
  633.             local tmp = string.lower(tostring(outfit[5]))
  634.             if(tmp == 'male' or tmp == '1') then
  635.                 parameters.gender = 1
  636.             elseif(tmp == 'female' or tmp == '0') then
  637.                 parameters.gender = 0
  638.             end
  639.         end
  640.  
  641.         for i, name in pairs(keywords) do
  642.             local words = {}
  643.             table.insert(words, name)
  644.  
  645.             local node = self.npcHandler.keywordHandler:addKeyword(words, OutfitModule.obtain, parameters)
  646.             node:addChildKeywordNode(self.yesNode)
  647.             node:addChildKeywordNode(self.noNode)
  648.         end
  649.     end
  650.  
  651.     function OutfitModule.obtain(cid, message, keywords, parameters, node)
  652.         local module = parameters.module
  653.         if(not module.npcHandler:isFocused(cid)) then
  654.             return false
  655.         end
  656.  
  657.         local i, items, size = 0, nil, table.maxn(parameters.items)
  658.         for k, v in pairs(parameters.items) do
  659.             if(v[1] ~= "storageset") then
  660.                 i = i + 1
  661.                 if(items ~= nil) then
  662.                     if(i == size) then
  663.                         items = items .. " and "
  664.                     else
  665.                         items = items .. ", "
  666.                     end
  667.                 else
  668.                     items = ""
  669.                 end
  670.  
  671.                 if(tonumber(v[1]) ~= nil and tonumber(v[1]) > 1) then
  672.                     items = items .. v[1] .. " "
  673.                 end
  674.  
  675.                 items = items .. v[3]
  676.             end
  677.         end
  678.    
  679.         module.npcHandler:say('Do you want ' .. keywords[1] .. ' ' .. (addon == 0 and "outfit" or "addon") .. ' for ' .. items .. '?', cid)
  680.         return true
  681.  
  682.     end
  683.  
  684.     function OutfitModule.onConfirm(cid, message, keywords, parameters, node)
  685.         local module = parameters.module
  686.         if(not module.npcHandler:isFocused(cid)) then
  687.             return false
  688.         end
  689.  
  690.         local parent = node:getParent():getParameters()
  691.         if(isPlayerPremiumCallback(cid) or not parent.premium) then
  692.             if(not OUTFITMODULE_FUNCTION[2](cid, parent.outfit, parent.addon)) then
  693.                 if(parent.addon == 0 or OUTFITMODULE_FUNCTION[2](cid, parent.outfit)) then
  694.                     if(parent.gender == nil or parent.gender == getPlayerSex(cid)) then
  695.                         local found = true
  696.                         for k, v in pairs(parent.items) do
  697.                             local tmp = tonumber(v[1])
  698.                             if(tmp == nil) then
  699.                                 if(v[1] == "storagecheck") then
  700.                                     if(getCreatureStorage(cid, k) < v[2]) then
  701.                                         found = false
  702.                                     end
  703.                                 elseif(v[1] == "outfitid") then
  704.                                     if(not canPlayerWearOutfitId(cid, k, v[2])) then
  705.                                         found = false
  706.                                     end
  707.                                 elseif(v[1] == "outfit") then
  708.                                     if(not canPlayerWearOutfit(cid, k, v[2])) then
  709.                                         found = false
  710.                                     end
  711.                                 else
  712.                                     found = false
  713.                                 end
  714.                             elseif(k == 20000) then
  715.                                 if(getPlayerMoney(cid) < tmp) then
  716.                                     found = false
  717.                                 end
  718.                             elseif(getPlayerItemCount(cid, k, v[2]) < tmp) then
  719.                                 found = false
  720.                             end
  721.  
  722.                             if(not found) then
  723.                                 break
  724.                             end
  725.                         end
  726.  
  727.                         if(found) then
  728.                             for k, v in pairs(parent.items) do
  729.                                 if(tonumber(v[1]) ~= nil) then
  730.                                     if(k == 20000) then
  731.                                         doPlayerRemoveMoney(cid, v[1])
  732.                                     else
  733.                                         doPlayerRemoveItem(cid, k, v[1], v[2])
  734.                                     end
  735.                                 elseif(v[1] == "storageset") then
  736.                                     doCreatureSetStorage(cid, k, v[2])
  737.                                 end
  738.                             end
  739.  
  740.                             module.npcHandler:say('It was a pleasure to dress you.', cid)
  741.                             OUTFITMODULE_FUNCTION[1](cid, parent.outfit, parent.addon)
  742.                             doPlayerSetStorageValue(cid, parent.storageId, storage)
  743.                         else
  744.                             module.npcHandler:say('You don\'t have these items!', cid)
  745.                         end
  746.                     else
  747.                         module.npcHandler:say('Sorry, this ' .. (parent.addon == 0 and 'outfit' or 'addon') .. ' is not for your gender.', cid)
  748.                     end
  749.                 else
  750.                     module.npcHandler:say('I will not dress you with addon of outfit you cannot wear!', cid)
  751.                 end
  752.             else
  753.                 module.npcHandler:say('You alrady have this ' .. (parent.addon == 0 and 'outfit' or 'addon') .. '!', cid)
  754.             end
  755.         else
  756.             module.npcHandler:say('Sorry, I dress only premium players.', cid)
  757.         end
  758.  
  759.         module.npcHandler:resetNpc()
  760.         return true
  761.     end
  762.  
  763.     -- onDecline keyword callback function. Generally called when the player sais 'no' after wanting to buy an item.
  764.     function OutfitModule.onDecline(cid, message, keywords, parameters, node)
  765.         local module = parameters.module
  766.         if(not module.npcHandler:isFocused(cid)) then
  767.             return false
  768.         end
  769.  
  770.         module.npcHandler:say(module.npcHandler:parseMessage(module.npcHandler:getMessage(MESSAGE_DECLINE), {[TAG_PLAYERNAME] = getCreatureName(cid)}), cid)
  771.         module.npcHandler:resetNpc()
  772.         return true
  773.     end
  774.  
  775.     function OutfitModule.listOutfits(cid, message, keywords, parameters, node)
  776.         local module = parameters.module
  777.         if(not module.npcHandler:isFocused(cid)) then
  778.             return false
  779.         end
  780.  
  781.         local msg, size = nil, table.maxn(module.outfits)
  782.         if(size > 0) then
  783.             for i, outfit in ipairs(module.outfits) do
  784.                 if(msg ~= nil) then
  785.                     if(i == size) then
  786.                         msg = msg .. " and "
  787.                     else
  788.                         msg = msg .. ", "
  789.                     end
  790.                 else
  791.                     msg = "I can dress you into "
  792.                 end
  793.  
  794.                 msg = msg .. "{" .. outfit .. "}"
  795.             end
  796.         else
  797.             msg = "Sorry, I have nothing to offer right now."
  798.         end
  799.  
  800.         module.npcHandler:say(msg .. ".", cid)
  801.         module.npcHandler:resetNpc()
  802.         return true
  803.     end
  804.  
  805.     ShopModule = {
  806.         npcHandler = nil,
  807.         yesNode = nil,
  808.         noNode = nil,
  809.         noText = '',
  810.         maxCount = 100,
  811.         amount = 0
  812.     }
  813.  
  814.     -- Add it to the parseable module list.
  815.     Modules.parseableModules['module_shop'] = ShopModule
  816.  
  817.     -- Creates a new instance of ShopModule
  818.     function ShopModule:new()
  819.         local obj = {}
  820.         setmetatable(obj, self)
  821.         self.__index = self
  822.         return obj
  823.     end
  824.  
  825.     -- Parses all known parameters.
  826.     function ShopModule:parseParameters()
  827.         local ret = NpcSystem.getParameter('shop_buyable')
  828.         if(ret ~= nil) then
  829.             self:parseBuyable(ret)
  830.         end
  831.  
  832.         local ret = NpcSystem.getParameter('shop_sellable')
  833.         if(ret ~= nil) then
  834.             self:parseSellable(ret)
  835.         end
  836.  
  837.         local ret = NpcSystem.getParameter('shop_buyable_containers')
  838.         if(ret ~= nil) then
  839.             self:parseBuyableContainers(ret)
  840.         end
  841.     end
  842.  
  843.     -- Parse a string contaning a set of buyable items.
  844.     function ShopModule:parseBuyable(data)
  845.         for item in string.gmatch(data, '[^;]+') do
  846.             local i, name, itemid, cost, subType, realName = 1, nil, nil, nil, nil, nil
  847.             for tmp in string.gmatch(item, '[^,]+') do
  848.                 if(i == 1) then
  849.                     name = tmp
  850.                 elseif(i == 2) then
  851.                     itemid = tonumber(tmp)
  852.                 elseif(i == 3) then
  853.                     cost = tonumber(tmp)
  854.                 elseif(i == 4) then
  855.                     subType = tonumber(tmp)
  856.                 elseif(i == 5) then
  857.                     realName = tmp
  858.                 else
  859.                     print('[Warning] NpcSystem:', 'Unknown parameter found in buyable items parameter.', tmp, item)
  860.                 end
  861.  
  862.                 i = i + 1
  863.             end
  864.  
  865.             if(SHOPMODULE_MODE == SHOPMODULE_MODE_TRADE) then
  866.                 if(itemid ~= nil and cost ~= nil) then
  867.                     if((isItemRune(itemid) or isItemFluidContainer(itemid)) and subType == nil) then
  868.                         print('[Warning] NpcSystem:', 'SubType missing for parameter item:', item)
  869.                     else
  870.                         self:addBuyableItem(nil, itemid, cost, subType, realName)
  871.                     end
  872.                 else
  873.                     print('[Warning] NpcSystem:', 'Parameter(s) missing for item:', itemid, cost)
  874.                 end
  875.             elseif(name ~= nil and itemid ~= nil and cost ~= nil) then
  876.                 if((isItemRune(itemid) or isItemFluidContainer(itemid)) and subType == nil) then
  877.                     print('[Warning] NpcSystem:', 'SubType missing for parameter item:', item)
  878.                 else
  879.                     local names = {}
  880.                     table.insert(names, name)
  881.                     self:addBuyableItem(names, itemid, cost, subType, realName)
  882.                 end
  883.             else
  884.                 print('[Warning] NpcSystem:', 'Parameter(s) missing for item:', name, itemid, cost)
  885.             end
  886.         end
  887.     end
  888.  
  889.     -- Parse a string contaning a set of sellable items.
  890.     function ShopModule:parseSellable(data)
  891.         for item in string.gmatch(data, '[^;]+') do
  892.             local i, name, itemid, cost, realName = 1, nil, nil, nil, nil
  893.             for temp in string.gmatch(item, '[^,]+') do
  894.                 if(i == 1) then
  895.                     name = temp
  896.                 elseif(i == 2) then
  897.                     itemid = tonumber(temp)
  898.                 elseif(i == 3) then
  899.                     cost = tonumber(temp)
  900.                 elseif(i == 4) then
  901.                     realName = temp
  902.                 else
  903.                     print('[Warning] NpcSystem:', 'Unknown parameter found in sellable items parameter.', temp, item)
  904.                 end
  905.                 i = i + 1
  906.             end
  907.  
  908.             if(SHOPMODULE_MODE == SHOPMODULE_MODE_TRADE) then
  909.                 if(itemid ~= nil and cost ~= nil) then
  910.                     self:addSellableItem(nil, itemid, cost, realName)
  911.                 else
  912.                     print('[Warning] NpcSystem:', 'Parameter(s) missing for item:', itemid, cost)
  913.                 end
  914.             elseif(name ~= nil and itemid ~= nil and cost ~= nil) then
  915.                 local names = {}
  916.                 table.insert(names, name)
  917.                 self:addSellableItem(names, itemid, cost, realName)
  918.             else
  919.                 print('[Warning] NpcSystem:', 'Parameter(s) missing for item:', name, itemid, cost)
  920.             end
  921.         end
  922.     end
  923.  
  924.     -- Parse a string contaning a set of buyable items.
  925.     function ShopModule:parseBuyableContainers(data)
  926.         for item in string.gmatch(data, '[^;]+') do
  927.             local i, name, container, itemid, cost, subType, realName = 1, nil, nil, nil, nil, nil, nil
  928.             for temp in string.gmatch(item, '[^,]+') do
  929.                 if(i == 1) then
  930.                     name = temp
  931.                 elseif(i == 2) then
  932.                     itemid = tonumber(temp)
  933.                 elseif(i == 3) then
  934.                     itemid = tonumber(temp)
  935.                 elseif(i == 4) then
  936.                     cost = tonumber(temp)
  937.                 elseif(i == 5) then
  938.                     subType = tonumber(temp)
  939.                 elseif(i == 6) then
  940.                     realName = temp
  941.                 else
  942.                     print('[Warning] NpcSystem:', 'Unknown parameter found in buyable items parameter.', temp, item)
  943.                 end
  944.                 i = i + 1
  945.             end
  946.  
  947.             if(name ~= nil and container ~= nil and itemid ~= nil and cost ~= nil) then
  948.                 if((isItemRune(itemid) or isItemFluidContainer(itemid)) and subType == nil) then
  949.                     print('[Warning] NpcSystem:', 'SubType missing for parameter item:', item)
  950.                 else
  951.                     local names = {}
  952.                     table.insert(names, name)
  953.                     self:addBuyableItemContainer(names, container, itemid, cost, subType, realName)
  954.                 end
  955.             else
  956.                 print('[Warning] NpcSystem:', 'Parameter(s) missing for item:', name, container, itemid, cost)
  957.             end
  958.         end
  959.     end
  960.  
  961.     -- Initializes the module and associates handler to it.
  962.     function ShopModule:init(handler)
  963.         self.npcHandler = handler
  964.         self.yesNode = KeywordNode:new(SHOP_YESWORD, ShopModule.onConfirm, {module = self})
  965.         self.noNode = KeywordNode:new(SHOP_NOWORD, ShopModule.onDecline, {module = self})
  966.  
  967.         self.noText = handler:getMessage(MESSAGE_DECLINE)
  968.         if(SHOPMODULE_MODE ~= SHOPMODULE_MODE_TALK) then
  969.             for i, word in pairs(SHOP_TRADEREQUEST) do
  970.                 local obj = {}
  971.                 table.insert(obj, word)
  972.  
  973.                 obj.callback = SHOP_TRADEREQUEST.callback or ShopModule.messageMatcher
  974.                 handler.keywordHandler:addKeyword(obj, ShopModule.requestTrade, {module = self})
  975.             end
  976.         end
  977.     end
  978.  
  979.     -- Custom message matching callback function for requesting trade messages.
  980.     function ShopModule.messageMatcher(keywords, message)
  981.         for i, word in pairs(keywords) do
  982.             if(type(word) == 'string' and string.find(message, word) and not string.find(message, '[%w+]' .. word) and not string.find(message, word .. '[%w+]')) then
  983.                 return true
  984.             end
  985.         end
  986.  
  987.         return false
  988.     end
  989.  
  990.     -- Resets the module-specific variables.
  991.     function ShopModule:reset()
  992.         self.amount = 0
  993.     end
  994.  
  995.     -- Function used to match a number value from a string.
  996.     function ShopModule:getCount(message)
  997.         local ret, b, e = 1, string.find(message, PATTERN_COUNT)
  998.         if(b ~= nil and e ~= nil) then
  999.             ret = tonumber(string.sub(message, b, e))
  1000.         end
  1001.  
  1002.         return math.max(1, math.min(self.maxCount, ret))
  1003.     end
  1004.  
  1005.     -- Adds a new buyable item.
  1006.     --  names = A table containing one or more strings of alternative names to this item. Used only for old buy/sell system.
  1007.     --  itemid = The itemid of the buyable item
  1008.     --  cost = The price of one single item
  1009.     --  subType - The subType of each rune or fluidcontainer item. Can be left out if it is not a rune/fluidcontainer. Default value is 1.
  1010.     --  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)
  1011.     function ShopModule:addBuyableItem(names, itemid, cost, subType, realName)
  1012.         if(SHOPMODULE_MODE ~= SHOPMODULE_MODE_TALK) then
  1013.             local item = {
  1014.                 id = itemid,
  1015.                 buy = cost,
  1016.                 sell = -1,
  1017.                 subType = subType or 1,
  1018.                 name = realName or getItemNameById(itemid)
  1019.             }
  1020.  
  1021.             for i, shopItem in ipairs(self.npcHandler.shopItems) do
  1022.                 if(shopItem.id == item.id and shopItem.subType == item.subType) then
  1023.                     if(item.sell ~= shopItem.sell) then
  1024.                         item.sell = shopItem.sell
  1025.                     end
  1026.  
  1027.                     self.npcHandler.shopItems[i] = item
  1028.                     item = nil
  1029.                     break
  1030.                 end
  1031.             end
  1032.  
  1033.             if(item ~= nil) then
  1034.                 table.insert(self.npcHandler.shopItems, item)
  1035.             end
  1036.         end
  1037.  
  1038.         if(names ~= nil and SHOPMODULE_MODE ~= SHOPMODULE_MODE_TRADE) then
  1039.             local parameters = {
  1040.                 itemid = itemid,
  1041.                 cost = cost,
  1042.                 eventType = SHOPMODULE_BUY_ITEM,
  1043.                 module = self,
  1044.                 realName = realName or getItemNameById(itemid),
  1045.                 subType = subType or 1
  1046.             }
  1047.  
  1048.             for i, name in pairs(names) do
  1049.                 local keywords = {}
  1050.                 table.insert(keywords, 'buy')
  1051.                 table.insert(keywords, name)
  1052.  
  1053.                 local node = self.npcHandler.keywordHandler:addKeyword(keywords, ShopModule.tradeItem, parameters)
  1054.                 node:addChildKeywordNode(self.yesNode)
  1055.                 node:addChildKeywordNode(self.noNode)
  1056.             end
  1057.         end
  1058.     end
  1059.  
  1060.     -- Adds a new buyable container of items.
  1061.     --  names = A table containing one or more strings of alternative names to this item.
  1062.     --  container = Backpack, bag or any other itemid of container where bought items will be stored
  1063.     --  itemid = The itemid of the buyable item
  1064.     --  cost = The price of one single item
  1065.     --  subType - The subType of each rune or fluidcontainer item. Can be left out if it is not a rune/fluidcontainer. Default value is 1.
  1066.     --  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)
  1067.     function ShopModule:addBuyableItemContainer(names, container, itemid, cost, subType, realName)
  1068.         if(names ~= nil) then
  1069.             local parameters = {
  1070.                 container = container,
  1071.                 itemid = itemid,
  1072.                 cost = cost,
  1073.                 eventType = SHOPMODULE_BUY_ITEM_CONTAINER,
  1074.                 module = self,
  1075.                 realName = realName or getItemNameById(itemid),
  1076.                 subType = subType or 1
  1077.             }
  1078.  
  1079.             for i, name in pairs(names) do
  1080.                 local keywords = {}
  1081.                 table.insert(keywords, 'buy')
  1082.                 table.insert(keywords, name)
  1083.  
  1084.                 local node = self.npcHandler.keywordHandler:addKeyword(keywords, ShopModule.tradeItem, parameters)
  1085.                 node:addChildKeywordNode(self.yesNode)
  1086.                 node:addChildKeywordNode(self.noNode)
  1087.             end
  1088.         end
  1089.     end
  1090.  
  1091.     -- Adds a new sellable item.
  1092.     --  names = A table containing one or more strings of alternative names to this item. Used only by old buy/sell system.
  1093.     --  itemid = The itemid of the sellable item
  1094.     --  cost = The price of one single item
  1095.     --  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)
  1096.     function ShopModule:addSellableItem(names, itemid, cost, realName)
  1097.         if(SHOPMODULE_MODE ~= SHOPMODULE_MODE_TALK) then
  1098.             local item = {
  1099.                 id = itemid,
  1100.                 buy = -1,
  1101.                 sell = cost,
  1102.                 subType = 1,
  1103.                 name = realName or getItemNameById(itemid)
  1104.             }
  1105.  
  1106.             for i, shopItem in ipairs(self.npcHandler.shopItems) do
  1107.                 if(shopItem.id == item.id and shopItem.subType == item.subType) then
  1108.                     if(item.buy ~= shopItem.buy) then
  1109.                         item.buy = shopItem.buy
  1110.                     end
  1111.  
  1112.                     self.npcHandler.shopItems[i] = item
  1113.                     item = nil
  1114.                     break
  1115.                 end
  1116.             end
  1117.  
  1118.             if(item ~= nil) then
  1119.                 table.insert(self.npcHandler.shopItems, item)
  1120.             end
  1121.         end
  1122.  
  1123.         if(names ~= nil and SHOPMODULE_MODE ~= SHOPMODULE_MODE_TRADE) then
  1124.             local parameters = {
  1125.                 itemid = itemid,
  1126.                 cost = cost,
  1127.                 eventType = SHOPMODULE_SELL_ITEM,
  1128.                 module = self,
  1129.                 realName = realName or getItemNameById(itemid)
  1130.             }
  1131.  
  1132.             for i, name in pairs(names) do
  1133.                 local keywords = {}
  1134.                 table.insert(keywords, 'sell')
  1135.                 table.insert(keywords, name)
  1136.  
  1137.                 local node = self.npcHandler.keywordHandler:addKeyword(keywords, ShopModule.tradeItem, parameters)
  1138.                 node:addChildKeywordNode(self.yesNode)
  1139.                 node:addChildKeywordNode(self.noNode)
  1140.             end
  1141.         end
  1142.     end
  1143.  
  1144.     -- onModuleReset callback function. Calls ShopModule:reset()
  1145.     function ShopModule:callbackOnModuleReset()
  1146.         self:reset()
  1147.         return true
  1148.     end
  1149.  
  1150.     -- Callback onBuy() function. If you wish, you can change certain Npc to use your onBuy().
  1151.     function ShopModule:callbackOnBuy(cid, itemid, subType, amount, ignoreCap, inBackpacks)
  1152.         local shopItem = nil
  1153.         for _, item in ipairs(self.npcHandler.shopItems) do
  1154.             if(item.id == itemid and item.subType == subType) then
  1155.                 shopItem = item
  1156.                 break
  1157.             end
  1158.         end
  1159.  
  1160.         if(shopItem == nil) then
  1161.             print("[ShopModule.onBuy]", "Item not found on shopItems list")
  1162.             return false
  1163.         end
  1164.  
  1165.         if(shopItem.buy == -1) then
  1166.             print("[ShopModule.onSell]", "Attempt to purchase an item which only sellable")
  1167.             return false
  1168.         end
  1169.  
  1170.         local backpack, totalCost = 1988, amount * shopItem.buy
  1171.         if(inBackpacks) then
  1172.             totalCost = totalCost + (math.max(1, math.floor(amount / getContainerCapById(backpack))) * 20)
  1173.         end
  1174.  
  1175.         local parseInfo = {
  1176.             [TAG_PLAYERNAME] = getPlayerName(cid),
  1177.             [TAG_ITEMCOUNT] = amount,
  1178.             [TAG_TOTALCOST] = totalCost,
  1179.             [TAG_ITEMNAME] = shopItem.name
  1180.         }
  1181.  
  1182.         if(getPlayerMoney(cid) < totalCost) then
  1183.             local msg = self.npcHandler:getMessage(MESSAGE_NEEDMONEY)
  1184.             doPlayerSendCancel(cid, self.npcHandler:parseMessage(msg, parseInfo))
  1185.             return false
  1186.         end
  1187.  
  1188.         local subType = shopItem.subType or 1
  1189.         local a, b = doNpcSellItem(cid, itemid, amount, subType, ignoreCap, inBackpacks, backpack)
  1190.         if(a < amount) then
  1191.             local msgId = MESSAGE_NEEDMORESPACE
  1192.             if(a == 0) then
  1193.                 msgId = MESSAGE_NEEDSPACE
  1194.             end
  1195.  
  1196.             local msg = self.npcHandler:getMessage(msgId)
  1197.             parseInfo[TAG_ITEMCOUNT] = a
  1198.  
  1199.             doPlayerSendCancel(cid, self.npcHandler:parseMessage(msg, parseInfo))
  1200.             if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
  1201.                 self.npcHandler.talkStart[cid] = os.time()
  1202.             else
  1203.                 self.npcHandler.talkStart = os.time()
  1204.             end
  1205.  
  1206.             if(a > 0) then
  1207.                 doPlayerRemoveMoney(cid, ((a * shopItem.buy) + (b * 20)))
  1208.                 return true
  1209.             end
  1210.  
  1211.             return false
  1212.         end
  1213.  
  1214.         local msg = self.npcHandler:getMessage(MESSAGE_BOUGHT)
  1215.         doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, self.npcHandler:parseMessage(msg, parseInfo))
  1216.  
  1217.         doPlayerRemoveMoney(cid, totalCost)
  1218.         if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
  1219.             self.npcHandler.talkStart[cid] = os.time()
  1220.         else
  1221.             self.npcHandler.talkStart = os.time()
  1222.         end
  1223.  
  1224.         return true
  1225.     end
  1226.  
  1227.     -- Callback onSell() function. If you wish, you can change certain Npc to use your onSell().
  1228.     function ShopModule:callbackOnSell(cid, itemid, subType, amount, ignoreCap, inBackpacks)
  1229.         local shopItem = nil
  1230.         for _, item in ipairs(self.npcHandler.shopItems) do
  1231.             if(item.id == itemid and item.subType == subType) then
  1232.                 shopItem = item
  1233.                 break
  1234.             end
  1235.         end
  1236.  
  1237.         if(shopItem == nil) then
  1238.             print("[ShopModule.onBuy]", "Item not found on shopItems list")
  1239.             return false
  1240.         end
  1241.  
  1242.         if(shopItem.sell == -1) then
  1243.             print("[ShopModule.onSell]", "Attempt to sell an item which is only buyable")
  1244.             return false
  1245.         end
  1246.  
  1247.         local parseInfo = {
  1248.             [TAG_PLAYERNAME] = getPlayerName(cid),
  1249.             [TAG_ITEMCOUNT] = amount,
  1250.             [TAG_TOTALCOST] = amount * shopItem.sell,
  1251.             [TAG_ITEMNAME] = shopItem.name
  1252.         }
  1253.  
  1254.         if(subType < 1 or getItemInfo(itemid).stackable) then
  1255.             subType = -1
  1256.         end
  1257.  
  1258.         if(doPlayerRemoveItem(cid, itemid, amount, subType)) then
  1259.             local msg = self.npcHandler:getMessage(MESSAGE_SOLD)
  1260.             doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, self.npcHandler:parseMessage(msg, parseInfo))
  1261.  
  1262.             doPlayerAddMoney(cid, amount * shopItem.sell)
  1263.             if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
  1264.                 self.npcHandler.talkStart[cid] = os.time()
  1265.             else
  1266.                 self.npcHandler.talkStart = os.time()
  1267.             end
  1268.  
  1269.             return true
  1270.         end
  1271.  
  1272.         local msg = self.npcHandler:getMessage(MESSAGE_NEEDITEM)
  1273.         doPlayerSendCancel(cid, self.npcHandler:parseMessage(msg, parseInfo))
  1274.         if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
  1275.             self.npcHandler.talkStart[cid] = os.time()
  1276.         else
  1277.             self.npcHandler.talkStart = os.time()
  1278.         end
  1279.  
  1280.         return false
  1281.     end
  1282.  
  1283.     -- Callback for requesting a trade window with the NPC.
  1284.     function ShopModule.requestTrade(cid, message, keywords, parameters, node)
  1285.         local module = parameters.module
  1286.         if(not module.npcHandler:isFocused(cid)) then
  1287.             return false
  1288.         end
  1289.  
  1290.         if(table.maxn(module.npcHandler.shopItems) == 0) then
  1291.             local parseInfo = { [TAG_PLAYERNAME] = getPlayerName(cid) }
  1292.             local msg = module.npcHandler:parseMessage(module.npcHandler:getMessage(MESSAGE_NOSHOP), parseInfo)
  1293.  
  1294.             module.npcHandler:say(msg, cid)
  1295.             return true
  1296.         end
  1297.  
  1298.         local parseInfo = { [TAG_PLAYERNAME] = getPlayerName(cid) }
  1299.         local msg = module.npcHandler:parseMessage(module.npcHandler:getMessage(MESSAGE_SENDTRADE), parseInfo)
  1300.         openShopWindow(cid, module.npcHandler.shopItems,
  1301.             function(cid, itemid, subType, amount, ignoreCap, inBackpacks)
  1302.                 module.npcHandler:onBuy(cid, itemid, subType, amount, ignoreCap, inBackpacks)
  1303.             end,
  1304.             function(cid, itemid, subType, amount, ignoreCap, inBackpacks)
  1305.                 module.npcHandler:onSell(cid, itemid, subType, amount, ignoreCap, inBackpacks)
  1306.             end
  1307.         )
  1308.  
  1309.         module.npcHandler:say(msg, cid)
  1310.         return true
  1311.     end
  1312.  
  1313.     -- onConfirm keyword callback function. Sells/buys the actual item.
  1314.     function ShopModule.onConfirm(cid, message, keywords, parameters, node)
  1315.         local module = parameters.module
  1316.         if(not module.npcHandler:isFocused(cid)) then
  1317.             return false
  1318.         end
  1319.  
  1320.         local parentParameters = node:getParent():getParameters()
  1321.         local parseInfo = {
  1322.             [TAG_PLAYERNAME] = getPlayerName(cid),
  1323.             [TAG_ITEMCOUNT] = module.amount,
  1324.             [TAG_TOTALCOST] = parentParameters.cost * module.amount,
  1325.             [TAG_ITEMNAME] = parentParameters.realName
  1326.         }
  1327.  
  1328.         if(parentParameters.eventType == SHOPMODULE_SELL_ITEM) then
  1329.             local ret = doPlayerSellItem(cid, parentParameters.itemid, module.amount, parentParameters.cost * module.amount)
  1330.             if(ret) then
  1331.                 local msg = module.npcHandler:getMessage(MESSAGE_ONSELL)
  1332.                 msg = module.npcHandler:parseMessage(msg, parseInfo)
  1333.                 module.npcHandler:say(msg, cid)
  1334.             else
  1335.                 local msg = module.npcHandler:getMessage(MESSAGE_MISSINGITEM)
  1336.                 msg = module.npcHandler:parseMessage(msg, parseInfo)
  1337.                 module.npcHandler:say(msg, cid)
  1338.             end
  1339.         elseif(parentParameters.eventType == SHOPMODULE_BUY_ITEM) then
  1340.             local ret = doPlayerBuyItem(cid, parentParameters.itemid, module.amount, parentParameters.cost * module.amount, parentParameters.subType)
  1341.             if(ret) then
  1342.                 if parentParameters.itemid == ITEM_PARCEL then
  1343.                     doPlayerBuyItem(cid, ITEM_LABEL, module.amount, 0, parentParameters.subType)
  1344.                 end
  1345.                 local msg = module.npcHandler:getMessage(MESSAGE_ONBUY)
  1346.                 msg = module.npcHandler:parseMessage(msg, parseInfo)
  1347.                 module.npcHandler:say(msg, cid)
  1348.             else
  1349.                 local msg = module.npcHandler:getMessage(MESSAGE_MISSINGMONEY)
  1350.                 msg = module.npcHandler:parseMessage(msg, parseInfo)
  1351.                 module.npcHandler:say(msg, cid)
  1352.             end
  1353.         elseif(parentParameters.eventType == SHOPMODULE_BUY_ITEM_CONTAINER) then
  1354.             local ret = doPlayerBuyItemContainer(cid, parentParameters.container, parentParameters.itemid, module.amount, parentParameters.cost * module.amount, parentParameters.subType)
  1355.             if(ret) then
  1356.                 local msg = module.npcHandler:getMessage(MESSAGE_ONBUY)
  1357.                 msg = module.npcHandler:parseMessage(msg, parseInfo)
  1358.                 module.npcHandler:say(msg, cid)
  1359.             else
  1360.                 local msg = module.npcHandler:getMessage(MESSAGE_MISSINGMONEY)
  1361.                 msg = module.npcHandler:parseMessage(msg, parseInfo)
  1362.                 module.npcHandler:say(msg, cid)
  1363.             end
  1364.         end
  1365.  
  1366.         module.npcHandler:resetNpc()
  1367.         return true
  1368.     end
  1369.  
  1370.     -- onDecliune keyword callback function. Generally called when the player sais 'no' after wanting to buy an item.
  1371.     function ShopModule.onDecline(cid, message, keywords, parameters, node)
  1372.         local module = parameters.module
  1373.         if(not module.npcHandler:isFocused(cid)) then
  1374.             return false
  1375.         end
  1376.  
  1377.         local parentParameters = node:getParent():getParameters()
  1378.         local parseInfo = {
  1379.             [TAG_PLAYERNAME] = getPlayerName(cid),
  1380.             [TAG_ITEMCOUNT] = module.amount,
  1381.             [TAG_TOTALCOST] = parentParameters.cost * module.amount,
  1382.             [TAG_ITEMNAME] = parentParameters.realName
  1383.         }
  1384.  
  1385.         local msg = module.npcHandler:parseMessage(module.noText, parseInfo)
  1386.         module.npcHandler:say(msg, cid)
  1387.         module.npcHandler:resetNpc()
  1388.         return true
  1389.     end
  1390.  
  1391.     -- tradeItem callback function. Makes the npc say the message defined by MESSAGE_BUY or MESSAGE_SELL
  1392.     function ShopModule.tradeItem(cid, message, keywords, parameters, node)
  1393.         local module = parameters.module
  1394.         if(not module.npcHandler:isFocused(cid)) then
  1395.             return false
  1396.         end
  1397.  
  1398.         local count = module:getCount(message)
  1399.         module.amount = count
  1400.         local parseInfo = {
  1401.             [TAG_PLAYERNAME] = getPlayerName(cid),
  1402.             [TAG_ITEMCOUNT] = module.amount,
  1403.             [TAG_TOTALCOST] = parameters.cost * module.amount,
  1404.             [TAG_ITEMNAME] = parameters.realName
  1405.         }
  1406.  
  1407.         if(parameters.eventType == SHOPMODULE_SELL_ITEM) then
  1408.             local msg = module.npcHandler:getMessage(MESSAGE_SELL)
  1409.             msg = module.npcHandler:parseMessage(msg, parseInfo)
  1410.             module.npcHandler:say(msg, cid)
  1411.         elseif(parameters.eventType == SHOPMODULE_BUY_ITEM) then
  1412.             local msg = module.npcHandler:getMessage(MESSAGE_BUY)
  1413.             msg = module.npcHandler:parseMessage(msg, parseInfo)
  1414.             module.npcHandler:say(msg, cid)
  1415.         elseif(parameters.eventType == SHOPMODULE_BUY_ITEM_CONTAINER) then
  1416.             local msg = module.npcHandler:getMessage(MESSAGE_BUY)
  1417.             msg = module.npcHandler:parseMessage(msg, parseInfo)
  1418.             module.npcHandler:say(msg, cid)
  1419.         end
  1420.  
  1421.         return true
  1422.     end
  1423. end
Add Comment
Please, Sign In to add comment