Advertisement
Guest User

Untitled

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