Guest User

Untitled

a guest
Sep 8th, 2011
101
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 22.00 KB | None | 0 0
  1. -- Advanced NPC System (Created by Jiddo),
  2. -- Modified by TheForgottenServer Team.
  3.  
  4. if(NpcHandler == nil) then
  5. -- Constant talkdelay behaviors.
  6. TALKDELAY_NONE = 0 -- No talkdelay. Npc will reply immedeatly.
  7. TALKDELAY_ONTHINK = 1 -- Talkdelay handled through the onThink callback function. (Default)
  8. TALKDELAY_EVENT = 2 -- Not yet implemented
  9.  
  10. -- Currently applied talkdelay behavior. TALKDELAY_ONTHINK is default.
  11. NPCHANDLER_TALKDELAY = TALKDELAY_ONTHINK
  12.  
  13. -- Constant conversation behaviors.
  14. CONVERSATION_DEFAULT = 0 -- Conversation through default window, like it was before 8.2 update.
  15. CONVERSATION_PRIVATE = 1 -- Conversation through NPCs chat window, as of 8.2 update. (Default)
  16. --Small Note: Private conversations also means the NPC will use multi-focus system.
  17.  
  18. -- Currently applied conversation behavior. CONVERSATION_PRIVATE is default.
  19. NPCHANDLER_CONVBEHAVIOR = CONVERSATION_PRIVATE
  20.  
  21. -- Constant indexes for defining default messages.
  22. MESSAGE_GREET = 1 -- When the player greets the npc.
  23. MESSAGE_FAREWELL = 2 -- When the player unGreets the npc.
  24. MESSAGE_BUY = 3 -- When the npc asks the player if he wants to buy something.
  25. MESSAGE_ONBUY = 4 -- When the player successfully buys something via talk.
  26. MESSAGE_BOUGHT = 5 -- When the player bought something through the shop window.
  27. MESSAGE_SELL = 6 -- When the npc asks the player if he wants to sell something.
  28. MESSAGE_ONSELL = 7 -- When the player successfully sells something via talk.
  29. MESSAGE_SOLD = 8 -- When the player sold something through the shop window.
  30. MESSAGE_MISSINGMONEY = 9 -- When the player does not have enough money.
  31. MESSAGE_NEEDMONEY = 10 -- Same as above, used for shop window.
  32. MESSAGE_MISSINGITEM = 11 -- When the player is trying to sell an item he does not have.
  33. MESSAGE_NEEDITEM = 12 -- Same as above, used for shop window.
  34. MESSAGE_NEEDSPACE = 13 -- When the player don't have any space to buy an item
  35. MESSAGE_NEEDMORESPACE = 14 -- When the player has some space to buy an item, but not enough space
  36. MESSAGE_IDLETIMEOUT = 15 -- When the player has been idle for longer then idleTime allows.
  37. MESSAGE_WALKAWAY = 16 -- When the player walks out of the talkRadius of the npc.
  38. MESSAGE_DECLINE = 17 -- When the player says no to something.
  39. MESSAGE_SENDTRADE = 18 -- When the npc sends the trade window to the player
  40. MESSAGE_NOSHOP = 19 -- When the npc's shop is requested but he doesn't have any
  41. MESSAGE_ONCLOSESHOP = 20 -- When the player closes the npc's shop window
  42. MESSAGE_ALREADYFOCUSED = 21 -- When the player already has the focus of this npc.
  43. MESSAGE_PLACEDINQUEUE = 22 -- When the player has been placed in the costumer queue.
  44.  
  45. -- Constant indexes for callback functions. These are also used for module callback ids.
  46. CALLBACK_CREATURE_APPEAR = 1
  47. CALLBACK_CREATURE_DISAPPEAR = 2
  48. CALLBACK_CREATURE_SAY = 3
  49. CALLBACK_ONTHINK = 4
  50. CALLBACK_GREET = 5
  51. CALLBACK_FAREWELL = 6
  52. CALLBACK_MESSAGE_DEFAULT = 7
  53. CALLBACK_PLAYER_ENDTRADE = 8
  54. CALLBACK_PLAYER_CLOSECHANNEL = 9
  55. CALLBACK_ONBUY = 10
  56. CALLBACK_ONSELL = 11
  57.  
  58. -- Addidional module callback ids
  59. CALLBACK_MODULE_INIT = 12
  60. CALLBACK_MODULE_RESET = 13
  61.  
  62. -- Constant strings defining the keywords to replace in the default messages.
  63. TAG_PLAYERNAME = '|PLAYERNAME|'
  64. TAG_ITEMCOUNT = '|ITEMCOUNT|'
  65. TAG_TOTALCOST = '|TOTALCOST|'
  66. TAG_ITEMNAME = '|ITEMNAME|'
  67. TAG_QUEUESIZE = '|QUEUESIZE|'
  68.  
  69. NpcHandler = {
  70. keywordHandler = nil,
  71. focuses = nil,
  72. talkStart = nil,
  73. idleTime = 300,
  74. talkRadius = 3,
  75. talkDelayTime = 400, -- Seconds to delay outgoing messages.
  76. queue = nil,
  77. talkDelay = nil,
  78. callbackFunctions = nil,
  79. modules = nil,
  80. shopItems = nil, -- They must be here since ShopModule uses "static" functions
  81. messages = {
  82. -- These are the default replies of all npcs. They can/should be changed individually for each npc.
  83. [MESSAGE_GREET] = 'Welcome, |PLAYERNAME|! I have been expecting you.',
  84. [MESSAGE_FAREWELL] = 'Good bye, |PLAYERNAME|!',
  85. [MESSAGE_BUY] = 'Do you want to buy |ITEMCOUNT| |ITEMNAME| for |TOTALCOST| gold coins?',
  86. [MESSAGE_ONBUY] = 'It was a pleasure doing business with you.',
  87. [MESSAGE_BOUGHT] = 'Bought |ITEMCOUNT|x |ITEMNAME| for |TOTALCOST| gold.',
  88. [MESSAGE_SELL] = 'Do you want to sell |ITEMCOUNT| |ITEMNAME| for |TOTALCOST| gold coins?',
  89. [MESSAGE_ONSELL] = 'Thank you for this |ITEMNAME|, |PLAYERNAME| gold.',
  90. [MESSAGE_SOLD] = 'Sold |ITEMCOUNT|x |ITEMNAME| for |TOTALCOST| gold.',
  91. [MESSAGE_MISSINGMONEY] = 'Sorry, you don\'t have enough money.',
  92. [MESSAGE_NEEDMONEY] = 'You do not have enough money.',
  93. [MESSAGE_MISSINGITEM] = 'You don\'t even have that item, |PLAYERNAME|!',
  94. [MESSAGE_NEEDITEM] = 'You do not have this object.',
  95. [MESSAGE_NEEDSPACE] = 'You do not have enough capacity.',
  96. [MESSAGE_NEEDMORESPACE] = 'You do not have enough capacity for all items.',
  97. [MESSAGE_IDLETIMEOUT] = 'Next, please!',
  98. [MESSAGE_WALKAWAY] = 'How rude!',
  99. [MESSAGE_DECLINE] = 'Not good enough, is it... ?',
  100. [MESSAGE_SENDTRADE] = 'Here\'s my offer, |PLAYERNAME|. Don\'t you like it?',
  101. [MESSAGE_NOSHOP] = 'Sorry, I\'m not offering anything.',
  102. [MESSAGE_ONCLOSESHOP] = 'Thank you, come back when you want something more.',
  103. [MESSAGE_ALREADYFOCUSED]= '|PLAYERNAME|! I am already talking to you...',
  104. [MESSAGE_PLACEDINQUEUE] = '|PLAYERNAME|, please wait for your turn. There are |QUEUESIZE| customers before you.'
  105. }
  106. }
  107.  
  108. -- Creates a new NpcHandler with an empty callbackFunction stack.
  109. function NpcHandler:new(keywordHandler)
  110. local obj = {}
  111. obj.callbackFunctions = {}
  112. obj.modules = {}
  113. if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
  114. obj.focuses = {}
  115. obj.talkStart = {}
  116. else
  117. obj.queue = Queue:new(obj)
  118. obj.focuses = 0
  119. obj.talkStart = 0
  120. end
  121.  
  122. obj.talkDelay = {}
  123. obj.keywordHandler = keywordHandler
  124. obj.messages = {}
  125. obj.shopItems = {}
  126.  
  127. setmetatable(obj.messages, self.messages)
  128. self.messages.__index = self.messages
  129.  
  130. setmetatable(obj, self)
  131. self.__index = self
  132. return obj
  133. end
  134.  
  135. -- Re-defines the maximum idle time allowed for a player when talking to this npc.
  136. function NpcHandler:setMaxIdleTime(newTime)
  137. self.idleTime = newTime
  138. end
  139.  
  140. -- Attackes a new keyword handler to this npchandler
  141. function NpcHandler:setKeywordHandler(newHandler)
  142. self.keywordHandler = newHandler
  143. end
  144.  
  145. -- Function used to change the focus of this npc.
  146. function NpcHandler:addFocus(newFocus)
  147. if(not isCreature(newFocus)) then
  148. return
  149. end
  150.  
  151. if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
  152. if(self:isFocused(newFocus, true)) then
  153. return
  154. end
  155.  
  156. table.insert(self.focuses, newFocus)
  157. else
  158. self.focuses = newFocus
  159. end
  160.  
  161. self:updateFocus(true)
  162. end
  163. NpcHandler.changeFocus = NpcHandler.addFocus -- "changeFocus" looks better for CONVERSATION_DEFAULT
  164.  
  165. -- Function used to verify if npc is focused to certain player
  166. function NpcHandler:isFocused(focus, creatureCheck)
  167. local creatureCheck = creatureCheck or false
  168. if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
  169. for k, v in pairs(self.focuses) do
  170. if(v == focus) then
  171. if(creatureCheck or isCreature(v)) then
  172. return true
  173. end
  174.  
  175. self:internalReleaseFocus(focus, k)
  176. return false
  177. end
  178. end
  179.  
  180. return false
  181. end
  182.  
  183. if(creatureCheck or isCreature(self.focuses)) then
  184. return self.focuses == focus
  185. end
  186.  
  187. self:changeFocus(0)
  188. return false
  189. end
  190.  
  191. -- This function should be called on each onThink and makes sure the npc faces the player it is talking to.
  192. -- Should also be called whenever a new player is focused.
  193. function NpcHandler:updateFocus(creatureCheck)
  194. local creatureCheck = creatureCheck or false
  195. if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
  196. for _, focus in pairs(self.focuses) do
  197. if(creatureCheck or isCreature(focus)) then
  198. doNpcSetCreatureFocus(focus)
  199. return
  200. end
  201. end
  202. elseif(creatureCheck or isCreature(self.focuses)) then
  203. doNpcSetCreatureFocus(self.focuses)
  204. return
  205. end
  206.  
  207. doNpcSetCreatureFocus(0)
  208. end
  209.  
  210. -- Used when the npc should un-focus the player.
  211. function NpcHandler:releaseFocus(focus)
  212. if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
  213. if(not self:isFocused(focus)) then
  214. return
  215. end
  216.  
  217. local pos = nil
  218. for k, v in pairs(self.focuses) do
  219. if(v == focus) then
  220. pos = k
  221. end
  222. end
  223.  
  224. if(pos ~= nil) then
  225. self:internalReleaseFocus(focus, pos)
  226. closeShopWindow(focus)
  227. end
  228. elseif(self.focuses == focus) then
  229. self:changeFocus(0)
  230. if(isCreature(focus)) then
  231. closeShopWindow(focus)
  232. end
  233. end
  234. end
  235.  
  236. -- Internal un-focusing function, beware using!
  237. function NpcHandler:internalReleaseFocus(focus, pos)
  238. if(type(self.focuses) ~= "table" or pos == nil or self.focuses[pos] == nil) then
  239. return
  240. end
  241.  
  242. table.remove(self.focuses, pos)
  243. self.talkStart[focus] = nil
  244. self:updateFocus()
  245. end
  246.  
  247. -- Returns the callback function with the specified id or nil if no such callback function exists.
  248. function NpcHandler:getCallback(id)
  249. local ret = nil
  250. if(self.callbackFunctions ~= nil) then
  251. ret = self.callbackFunctions[id]
  252. end
  253.  
  254. return ret
  255. end
  256.  
  257. -- Changes the callback function for the given id to callback.
  258. function NpcHandler:setCallback(id, callback)
  259. if(self.callbackFunctions ~= nil) then
  260. self.callbackFunctions[id] = callback
  261. end
  262. end
  263.  
  264. -- Adds a module to this npchandler and inits it.
  265. function NpcHandler:addModule(module)
  266. if(self.modules == nil or module == nil) then
  267. return false
  268. end
  269.  
  270. module:init(self)
  271. if(module.parseParameters ~= nil) then
  272. module:parseParameters()
  273. end
  274.  
  275. table.insert(self.modules, module)
  276. return true
  277. end
  278.  
  279. -- Calls the callback function represented by id for all modules added to this npchandler with the given arguments.
  280. function NpcHandler:processModuleCallback(id, ...)
  281. local ret = true
  282. for _, module in pairs(self.modules) do
  283. local tmpRet = true
  284. if(id == CALLBACK_CREATURE_APPEAR and module.callbackOnCreatureAppear ~= nil) then
  285. tmpRet = module:callbackOnCreatureAppear(unpack(arg))
  286. elseif(id == CALLBACK_CREATURE_DISAPPEAR and module.callbackOnCreatureDisappear ~= nil) then
  287. tmpRet = module:callbackOnCreatureDisappear(unpack(arg))
  288. elseif(id == CALLBACK_CREATURE_SAY and module.callbackOnCreatureSay ~= nil) then
  289. tmpRet = module:callbackOnCreatureSay(unpack(arg))
  290. elseif(id == CALLBACK_PLAYER_ENDTRADE and module.callbackOnPlayerEndTrade ~= nil) then
  291. tmpRet = module:callbackOnPlayerEndTrade(unpack(arg))
  292. elseif(id == CALLBACK_PLAYER_CLOSECHANNEL and module.callbackOnPlayerCloseChannel ~= nil) then
  293. tmpRet = module:callbackOnPlayerCloseChannel(unpack(arg))
  294. elseif(id == CALLBACK_ONBUY and module.callbackOnBuy ~= nil) then
  295. tmpRet = module:callbackOnBuy(unpack(arg))
  296. elseif(id == CALLBACK_ONSELL and module.callbackOnSell ~= nil) then
  297. tmpRet = module:callbackOnSell(unpack(arg))
  298. elseif(id == CALLBACK_ONTHINK and module.callbackOnThink ~= nil) then
  299. tmpRet = module:callbackOnThink(unpack(arg))
  300. elseif(id == CALLBACK_GREET and module.callbackOnGreet ~= nil) then
  301. tmpRet = module:callbackOnGreet(unpack(arg))
  302. elseif(id == CALLBACK_FAREWELL and module.callbackOnFarewell ~= nil) then
  303. tmpRet = module:callbackOnFarewell(unpack(arg))
  304. elseif(id == CALLBACK_MESSAGE_DEFAULT and module.callbackOnMessageDefault ~= nil) then
  305. tmpRet = module:callbackOnMessageDefault(unpack(arg))
  306. elseif(id == CALLBACK_MODULE_RESET and module.callbackOnModuleReset ~= nil) then
  307. tmpRet = module:callbackOnModuleReset(unpack(arg))
  308. end
  309.  
  310. if(not tmpRet) then
  311. ret = false
  312. break
  313. end
  314. end
  315.  
  316. return ret
  317. end
  318.  
  319. -- Returns the message represented by id.
  320. function NpcHandler:getMessage(id)
  321. local ret = nil
  322. if(self.messages ~= nil) then
  323. ret = self.messages[id]
  324. end
  325.  
  326. return ret
  327. end
  328.  
  329. -- Changes the default response message with the specified id to newMessage.
  330. function NpcHandler:setMessage(id, newMessage)
  331. if(self.messages ~= nil) then
  332. self.messages[id] = newMessage
  333. end
  334. end
  335.  
  336. -- Translates all message tags found in msg using parseInfo
  337. function NpcHandler:parseMessage(msg, parseInfo)
  338. for search, replace in pairs(parseInfo) do
  339. if(replace ~= nil) then
  340. msg = msg:gsub(search, replace)
  341. end
  342. end
  343.  
  344. return msg
  345. end
  346.  
  347. -- Makes sure the npc un-focuses the currently focused player
  348. function NpcHandler:unGreet(cid)
  349. if(not self:isFocused(cid)) then
  350. return
  351. end
  352.  
  353. local callback = self:getCallback(CALLBACK_FAREWELL)
  354. if(callback == nil or callback(cid)) then
  355. if(self:processModuleCallback(CALLBACK_FAREWELL)) then
  356. if(self.queue == nil or not self.queue:greetNext()) then
  357. local msg = self:getMessage(MESSAGE_FAREWELL)
  358. local parseInfo = { [TAG_PLAYERNAME] = getPlayerName(cid) }
  359. msg = self:parseMessage(msg, parseInfo)
  360.  
  361. self:say(msg, cid)
  362. self:releaseFocus(cid)
  363. self:say(msg)
  364. end
  365. end
  366. end
  367. end
  368.  
  369. -- Greets a new player.
  370. function NpcHandler:greet(cid)
  371. if(cid ~= 0) then
  372. local callback = self:getCallback(CALLBACK_GREET)
  373. if(callback == nil or callback(cid)) then
  374. if(self:processModuleCallback(CALLBACK_GREET, cid)) then
  375. local msg = self:getMessage(MESSAGE_GREET)
  376. local parseInfo = { [TAG_PLAYERNAME] = getCreatureName(cid) }
  377. msg = self:parseMessage(msg, parseInfo)
  378.  
  379. self:say(msg)
  380. self:addFocus(cid)
  381. self:say(msg, cid)
  382. end
  383. end
  384. end
  385. end
  386.  
  387. -- Handles onCreatureAppear events. If you with to handle this yourself, please use the CALLBACK_CREATURE_APPEAR callback.
  388. function NpcHandler:onCreatureAppear(cid)
  389. local callback = self:getCallback(CALLBACK_CREATURE_APPEAR)
  390. if(callback == nil or callback(cid)) then
  391. if(self:processModuleCallback(CALLBACK_CREATURE_APPEAR, cid)) then
  392. --
  393. end
  394. end
  395. end
  396.  
  397. -- Handles onCreatureDisappear events. If you with to handle this yourself, please use the CALLBACK_CREATURE_DISAPPEAR callback.
  398. function NpcHandler:onCreatureDisappear(cid)
  399. local callback = self:getCallback(CALLBACK_CREATURE_DISAPPEAR)
  400. if(callback == nil or callback(cid)) then
  401. if(self:processModuleCallback(CALLBACK_CREATURE_DISAPPEAR, cid)) then
  402. if(self:isFocused(cid)) then
  403. self:unGreet(cid)
  404. end
  405. end
  406. end
  407. end
  408.  
  409. -- Handles onCreatureSay events. If you with to handle this yourself, please use the CALLBACK_CREATURE_SAY callback.
  410. function NpcHandler:onCreatureSay(cid, class, msg)
  411. local callback = self:getCallback(CALLBACK_CREATURE_SAY)
  412. if(callback == nil or callback(cid, class, msg)) then
  413. if(self:processModuleCallback(CALLBACK_CREATURE_SAY, cid, class, msg)) then
  414. if(not self:isInRange(cid)) then
  415. return
  416. end
  417.  
  418. if(self.keywordHandler ~= nil) then
  419. if((self:isFocused(cid) and (class == TALKTYPE_PRIVATE_PN or NPCHANDLER_CONVBEHAVIOR == CONVERSATION_DEFAULT)) or not self:isFocused(cid)) then
  420. local ret = self.keywordHandler:processMessage(cid, msg)
  421. if(not ret) then
  422. local callback = self:getCallback(CALLBACK_MESSAGE_DEFAULT)
  423. if(callback ~= nil and callback(cid, class, msg)) then
  424. if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
  425. self.talkStart[cid] = os.time()
  426. else
  427. self.talkStart = os.time()
  428. end
  429. end
  430. elseif(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
  431. self.talkStart[cid] = os.time()
  432. else
  433. self.talkStart = os.time()
  434. end
  435. end
  436. end
  437. end
  438. end
  439. end
  440.  
  441. -- Handles onPlayerEndTrade events. If you wish to handle this yourself, use the CALLBACK_PLAYER_ENDTRADE callback.
  442. function NpcHandler:onPlayerEndTrade(cid)
  443. local callback = self:getCallback(CALLBACK_PLAYER_ENDTRADE)
  444. if(callback == nil or callback(cid)) then
  445. if(self:processModuleCallback(CALLBACK_PLAYER_ENDTRADE, cid, class, msg)) then
  446. if(self:isFocused(cid)) then
  447. local parseInfo = { [TAG_PLAYERNAME] = getPlayerName(cid) }
  448. local msg = self:parseMessage(self:getMessage(MESSAGE_ONCLOSESHOP), parseInfo)
  449. self:say(msg, cid)
  450. end
  451. end
  452. end
  453. end
  454.  
  455. -- Handles onPlayerCloseChannel events. If you wish to handle this yourself, use the CALLBACK_PLAYER_CLOSECHANNEL callback.
  456. function NpcHandler:onPlayerCloseChannel(cid)
  457. local callback = self:getCallback(CALLBACK_PLAYER_CLOSECHANNEL)
  458. if(callback == nil or callback(cid)) then
  459. if(self:processModuleCallback(CALLBACK_PLAYER_CLOSECHANNEL, cid, class, msg)) then
  460. if(self:isFocused(cid)) then
  461. self:unGreet(cid)
  462. end
  463. end
  464. end
  465. end
  466.  
  467. -- Handles onBuy events. If you wish to handle this yourself, use the CALLBACK_ONBUY callback.
  468. function NpcHandler:onBuy(cid, itemid, subType, amount, ignoreCap, inBackpacks)
  469. local callback = self:getCallback(CALLBACK_ONBUY)
  470. if(callback == nil or callback(cid, itemid, subType, amount, ignoreCap, inBackpacks)) then
  471. if(self:processModuleCallback(CALLBACK_ONBUY, cid, itemid, subType, amount, ignoreCap, inBackpacks)) then
  472. --
  473. end
  474. end
  475. end
  476.  
  477. -- Handles onSell events. If you wish to handle this yourself, use the CALLBACK_ONSELL callback.
  478. function NpcHandler:onSell(cid, itemid, subType, amount, ignoreCap, inBackpacks)
  479. local callback = self:getCallback(CALLBACK_ONSELL)
  480. if(callback == nil or callback(cid, itemid, subType, amount, ignoreCap, inBackpacks)) then
  481. if(self:processModuleCallback(CALLBACK_ONSELL, cid, itemid, subType, amount, ignoreCap, inBackpacks)) then
  482. --
  483. end
  484. end
  485. end
  486.  
  487. -- Handles onThink events. If you wish to handle this yourself, please use the CALLBACK_ONTHINK callback.
  488. function NpcHandler:onThink()
  489. local callback = self:getCallback(CALLBACK_ONTHINK)
  490. if(callback == nil or callback()) then
  491. for i, speech in pairs(self.talkDelay) do
  492. if(speech.cid ~= nil and isCreature(speech.cid) and speech.start ~= nil and speech.time ~= nil and speech.message ~= nil) then
  493. if(os.mtime() >= speech.time) then
  494. local talkStart = (NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT and self.talkStart[speech.cid] or self.talkStart)
  495. if(self:isFocused(speech.cid) and talkStart == speech.start) then
  496. if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
  497. selfSay(speech.message, speech.cid)
  498. else
  499. selfSay(speech.message)
  500. end
  501. end
  502.  
  503. self.talkDelay[i] = nil
  504. end
  505. else
  506. self.talkDelay[i] = nil
  507. end
  508. end
  509.  
  510. if(self:processModuleCallback(CALLBACK_ONTHINK)) then
  511. if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
  512. for _, focus in pairs(self.focuses) do
  513. if(focus ~= nil) then
  514. if(not self:isInRange(focus)) then
  515. self:onWalkAway(focus)
  516. elseif((os.time() - self.talkStart[focus]) > self.idleTime) then
  517. self:unGreet(focus)
  518. else
  519. self:updateFocus()
  520. end
  521. end
  522. end
  523. elseif(self.focuses ~= 0) then
  524. if(not self:isInRange(self.focuses)) then
  525. self:onWalkAway(self.focuses)
  526. elseif((os.time() - self.talkStart) > self.idleTime) then
  527. self:unGreet(self.focuses)
  528. else
  529. self:updateFocus()
  530. end
  531. end
  532. end
  533. end
  534. end
  535.  
  536. -- Tries to greet the player with the given cid.
  537. function NpcHandler:onGreet(cid)
  538. if(self:isInRange(cid)) then
  539. if(NPCHANDLER_CONVBEHAVIOR == CONVERSATION_PRIVATE) then
  540. if(not self:isFocused(cid)) then
  541. self:greet(cid)
  542. return
  543. end
  544. elseif(NPCHANDLER_CONVBEHAVIOR == CONVERSATION_DEFAULT) then
  545. if(self.focuses == 0) then
  546. self:greet(cid)
  547. elseif(self.focuses == cid) then
  548. local msg = self:getMessage(MESSAGE_ALREADYFOCUSED)
  549. local parseInfo = { [TAG_PLAYERNAME] = getCreatureName(cid) }
  550. msg = self:parseMessage(msg, parseInfo)
  551. self:say(msg)
  552. else
  553. if(not self.queue:isInQueue(cid)) then
  554. self.queue:push(cid)
  555. end
  556.  
  557. local msg = self:getMessage(MESSAGE_PLACEDINQUEUE)
  558. local parseInfo = { [TAG_PLAYERNAME] = getCreatureName(cid), [TAG_QUEUESIZE] = self.queue:getSize() }
  559. msg = self:parseMessage(msg, parseInfo)
  560. self:say(msg)
  561. end
  562. end
  563. end
  564. end
  565.  
  566. -- Simply calls the underlying unGreet function.
  567. function NpcHandler:onFarewell(cid)
  568. self:unGreet(cid)
  569. end
  570.  
  571. -- Should be called on this npc's focus if the distance to focus is greater then talkRadius.
  572. function NpcHandler:onWalkAway(cid)
  573. if(self:isFocused(cid)) then
  574. local callback = self:getCallback(CALLBACK_CREATURE_DISAPPEAR)
  575. if(callback == nil or callback(cid)) then
  576. if(self:processModuleCallback(CALLBACK_CREATURE_DISAPPEAR, cid)) then
  577. if(self.queue == nil or not self.queue:greetNext()) then
  578. local msg = self:getMessage(MESSAGE_WALKAWAY)
  579. local parseInfo = { [TAG_PLAYERNAME] = getPlayerName(cid) }
  580. msg = self:parseMessage(msg, parseInfo)
  581.  
  582. self:say(msg, cid)
  583. self:releaseFocus(cid)
  584. self:say(msg)
  585. end
  586. end
  587. end
  588. end
  589. end
  590.  
  591. -- Returns true if cid is within the talkRadius of this npc.
  592. function NpcHandler:isInRange(cid)
  593. local distance = getNpcDistanceTo(cid) or -1
  594. return distance ~= -1 and distance <= self.talkRadius
  595. end
  596.  
  597. -- Resets the npc into it's initial state (in regard of the keyrodhandler).
  598. -- All modules are also receiving a reset call through their callbackOnModuleReset function.
  599. function NpcHandler:resetNpc()
  600. if(self:processModuleCallback(CALLBACK_MODULE_RESET)) then
  601. self.keywordHandler:reset()
  602. end
  603. end
  604.  
  605. -- Makes the npc represented by this instance of NpcHandler say something.
  606. -- This implements the currently set type of talkdelay.
  607. function NpcHandler:say(message, focus, delay)
  608. local delay = delay or 0
  609. if(NPCHANDLER_TALKDELAY == TALKDELAY_NONE and delay <= 0) then
  610. if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
  611. selfSay(message, focus)
  612. else
  613. selfSay(message)
  614. end
  615.  
  616. return
  617. end
  618.  
  619. -- TODO: Add an event handling method for delayed messages
  620. table.insert(self.talkDelay, {
  621. cid = focus,
  622. message = message,
  623. time = os.mtime() + (delay <= 0 and self.talkDelayTime or delay),
  624. start = os.time()
  625. })
  626. end
  627. end
Advertisement
Add Comment
Please, Sign In to add comment