Advertisement
Berntan

Modules.lua

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