Guest User

modules.lua

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