Guest User

Untitled

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