Advertisement
Guest User

Untitled

a guest
Jul 4th, 2016
97
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.56 KB | None | 0 0
  1. -- This file is part of Jiddo's advanced NpcSystem v3.0x. This npcsystem is free to use by anyone, for any purpuse.
  2. -- Initial release date: 2007-02-21
  3. -- Credits: Jiddo, honux(I'm using a modified version of his Find function).
  4. -- Please include full credits whereever you use this system, or parts of it.
  5. -- For support, questions and updates, please consult the following thread:
  6. -- http://otfans.net/showthread.php?t=67810
  7.  
  8. if(NpcHandler == nil) then
  9.  
  10. -- Constant talkdelay behaviors.
  11. TALKDELAY_NONE = 0 -- No talkdelay. Npc will reply immedeatly.
  12. TALKDELAY_ONTHINK = 1 -- Talkdelay handled through the onThink callback function. (Default)
  13. TALKDELAY_EVENT = 2 -- Not yet implemented
  14.  
  15. -- Currently applied talkdelay behavior. TALKDELAY_ONTHINK is default.
  16. NPCHANDLER_TALKDELAY = TALKDELAY_ONTHINK
  17.  
  18.  
  19.  
  20. -- Constant indexes for defining default messages.
  21. MESSAGE_GREET = 1 -- When the player greets the npc.
  22. MESSAGE_FAREWELL = 2 -- When the player unGreets the npc.
  23. MESSAGE_BUY = 3 -- When the npc asks the player if he wants to buy something.
  24. MESSAGE_SELL = 4 -- When the npc asks the player if he wants to sell something.
  25. MESSAGE_ONBUY = 5 -- When the player successfully buys something
  26. MESSAGE_ONSELL = 6 -- When the player successfully sells something
  27. MESSAGE_NEEDMOREMONEY = 7 -- When the player does not have enough money
  28. MESSAGE_NOTHAVEITEM = 8 -- When the player is trying to sell an item he does not have.
  29. MESSAGE_IDLETIMEOUT = 9 -- When the player has been idle for longer then idleTime allows.
  30. MESSAGE_WALKAWAY = 10 -- When the player walks out of the talkRadius of the npc.
  31. MESSAGE_ALREADYFOCUSED = 11 -- When the player already has the focus of this nopc.
  32. MESSAGE_PLACEDINQUEUE = 12 -- When the player has been placed in the costumer queue.
  33. MESSAGE_DECLINE = 13 -- When the player sais no to something.
  34.  
  35. -- Constant indexes for callback functions. These are also used for module callback ids.
  36. CALLBACK_CREATURE_APPEAR = 1
  37. CALLBACK_CREATURE_DISAPPEAR = 2
  38. CALLBACK_CREATURE_SAY = 3
  39. CALLBACK_ONTHINK = 4
  40. CALLBACK_GREET = 5
  41. CALLBACK_FAREWELL = 6
  42. CALLBACK_MESSAGE_DEFAULT = 7
  43.  
  44. -- Addidional module callback ids
  45. CALLBACK_MODULE_INIT = 10
  46. CALLBACK_MODULE_RESET = 11
  47.  
  48.  
  49. -- Constant strings defining the keywords to replace in the default messages.
  50. TAG_PLAYERNAME = '|PLAYERNAME|'
  51. TAG_ITEMCOUNT = '|ITEMCOUNT|'
  52. TAG_TOTALCOST = '|TOTALCOST|'
  53. TAG_ITEMNAME = '|ITEMNAME|'
  54. TAG_QUEUESIZE = '|QUEUESIZE|'
  55.  
  56.  
  57. NpcHandler = {
  58. keywordHandler = nil,
  59. queue = nil,
  60. focus = 0,
  61. talkStart = 0,
  62. idleTime = 45,
  63. talkRadius = 5,
  64. talkDelayTime = 1, -- Seconds to delay outgoing messages.
  65. talkDelay = nil,
  66. callbackFunctions = nil,
  67. modules = nil,
  68. messages = {
  69. -- These are the default replies of all npcs. They can/should be changed individually for each npc.
  70. [MESSAGE_GREET] = 'Welcome, |PLAYERNAME|! I have been expecting you.',
  71. [MESSAGE_FAREWELL] = 'Good bye, |PLAYERNAME|!',
  72. [MESSAGE_BUY] = 'Do you want to buy |ITEMCOUNT| |ITEMNAME| for |TOTALCOST| gold coins?',
  73. [MESSAGE_SELL] = 'Do you want to sell |ITEMCOUNT| |ITEMNAME| for |TOTALCOST| gold coins?',
  74. [MESSAGE_ONBUY] = 'It was a pleasure doing business with you.',
  75. [MESSAGE_ONSELL] = 'Thank you for this item, |PLAYERNAME|.',
  76. [MESSAGE_NEEDMOREMONEY] = 'You do not have enough money.',
  77. [MESSAGE_NOTHAVEITEM] = 'You don\'t even have that item!',
  78. [MESSAGE_IDLETIMEOUT] = 'Next please!',
  79. [MESSAGE_WALKAWAY] = 'How rude!',
  80. [MESSAGE_ALREADYFOCUSED]= '|PLAYERNAME|, I am already talking to you.',
  81. [MESSAGE_PLACEDINQUEUE] = '|PLAYERNAME|, please wait for your turn. There are |QUEUESIZE| customers before you.',
  82. [MESSAGE_DECLINE] = 'Not good enough, is it?'
  83. }
  84. }
  85.  
  86.  
  87. -- Creates a new NpcHandler with an empty callbackFunction stack.
  88. function NpcHandler:new(keywordHandler)
  89. local obj = {}
  90. obj.callbackFunctions = {}
  91. obj.modules = {}
  92. obj.talkDelay = {
  93. message = nil,
  94. time = nil
  95. }
  96. obj.queue = Queue:new(obj)
  97. obj.keywordHandler = keywordHandler
  98. obj.messages = {}
  99. setmetatable(obj.messages, self.messages)
  100. self.messages.__index = self.messages
  101.  
  102. setmetatable(obj, self)
  103. self.__index = self
  104. return obj
  105. end
  106.  
  107. -- Re-defines the maximum idle time allowed for a player when talking to this npc.
  108. function NpcHandler:setMaxIdleTime(newTime)
  109. self.idleTime = newTime
  110. end
  111.  
  112. -- Attaches a new costumer queue to this npchandler.
  113. function NpcHandler:setQueue(newQueue)
  114. self.queue = newQueue
  115. self.queue:setHandler(self)
  116. end
  117.  
  118. -- Attackes a new keyword handler to this npchandler
  119. function NpcHandler:setKeywordHandler(newHandler)
  120. self.keywordHandler = newHandler
  121. end
  122.  
  123. -- Function used to change the focus of this npc.
  124. function NpcHandler:changeFocus(newFocus)
  125. self.focus = newFocus
  126. self:updateFocus()
  127. end
  128.  
  129. -- This function should be called on each onThink and makes sure the npc faces the player it is talking to.
  130. -- Should also be called whenever a new player is focused.
  131. function NpcHandler:updateFocus()
  132. doNpcSetCreatureFocus(self.focus)
  133. end
  134.  
  135. -- Used when the npc should un-focus the player.
  136. function NpcHandler:releaseFocus()
  137. self:changeFocus(0)
  138. end
  139.  
  140. -- Returns the callback function with the specified id or nil if no such callback function exists.
  141. function NpcHandler:getCallback(id)
  142. local ret = nil
  143. if(self.callbackFunctions ~= nil) then
  144. ret = self.callbackFunctions[id]
  145. end
  146. return ret
  147. end
  148.  
  149. -- Changes the callback function for the given id to callback.
  150. function NpcHandler:setCallback(id, callback)
  151. if(self.callbackFunctions ~= nil) then
  152. self.callbackFunctions[id] = callback
  153. end
  154. end
  155.  
  156. -- Adds a module to this npchandler and inits it.
  157. function NpcHandler:addModule(module)
  158. if(self.modules ~= nil) then
  159. table.insert(self.modules, module)
  160. module:init(self)
  161. end
  162. end
  163.  
  164. -- Calls the callback function represented by id for all modules added to this npchandler with the given arguments.
  165. function NpcHandler:processModuleCallback(id, ...)
  166. local ret = true
  167. for i, module in pairs(self.modules) do
  168. local tmpRet = true
  169. if(id == CALLBACK_CREATURE_APPEAR and module.callbackOnCreatureAppear ~= nil) then
  170. tmpRet = module:callbackCreatureAppear(unpack(arg))
  171.  
  172. elseif(id == CALLBACK_CREATURE_DISAPPEAR and module.callbackOnCreatureDisappear ~= nil) then
  173. tmpRet = module:callbackCreatureDisappear(unpack(arg))
  174.  
  175. elseif(id == CALLBACK_CREATURE_SAY and module.callbackOnCreatureSay ~= nil) then
  176. tmpRet = module:callbackCreatureSay(unpack(arg))
  177.  
  178. elseif(id == CALLBACK_ONTHINK and module.callbackOnThink ~= nil) then
  179. tmpRet = module:callbackOnThink(unpack(arg))
  180.  
  181. elseif(id == CALLBACK_GREET and module.callbackOnGreet ~= nil) then
  182. tmpRet = module:callbackOnGreet(unpack(arg))
  183.  
  184. elseif(id == CALLBACK_FAREWELL and module.callbackOnFarewell ~= nil) then
  185. tmpRet = module:callbackOnFarewell(unpack(arg))
  186.  
  187. elseif(id == CALLBACK_MESSAGE_DEFAULT and module.callbackOnMessageDefault ~= nil) then
  188. tmpRet = module:callbackOnMessageDefault(unpack(arg))
  189.  
  190. elseif(id == CALLBACK_MODULE_RESET and module.callbackOnModuleReset ~= nil) then
  191. tmpRet = module:callbackOnModuleReset(unpack(arg))
  192. end
  193. if(not tmpRet) then
  194. ret = false
  195. break
  196. end
  197. end
  198. return ret
  199. end
  200.  
  201. -- Returns the message represented by id.
  202. function NpcHandler:getMessage(id)
  203. local ret = nil
  204. if(self.messages ~= nil) then
  205. ret = self.messages[id]
  206. end
  207. return ret
  208. end
  209.  
  210. -- Changes the default response message with the specified id to newMessage.
  211. function NpcHandler:setMessage(id, newMessage)
  212. if(self.messages ~= nil) then
  213. self.messages[id] = newMessage
  214. end
  215. end
  216.  
  217. -- Translates all message tags found in msg using parseInfo
  218. function NpcHandler:parseMessage(msg, parseInfo)
  219. local ret = msg
  220. for search, replace in pairs(parseInfo) do
  221. ret = string.gsub(ret, search, replace)
  222. end
  223. return ret
  224. end
  225.  
  226. -- Makes sure the npc un-focuses the furrently focused player, and greets the next player in the queue is it is not empty.
  227. function NpcHandler:unGreet()
  228. if(self.focus == 0) then
  229. return
  230. end
  231. local callback = self:getCallback(CALLBACK_FAREWELL)
  232. if(callback == nil or callback()) then
  233. if(self:processModuleCallback(CALLBACK_FAREWELL)) then
  234. if(self.queue == nil or not self.queue:greetNext()) then
  235. local msg = self:getMessage(MESSAGE_FAREWELL)
  236. local parseInfo = { [TAG_PLAYERNAME] = getPlayerName(self.focus) }
  237. msg = self:parseMessage(msg, parseInfo)
  238. self:say(msg)
  239. self:releaseFocus()
  240. end
  241. end
  242. end
  243. end
  244.  
  245. -- Greets a new player.
  246. function NpcHandler:greet(cid)
  247. if(cid ~= 0) then
  248. local callback = self:getCallback(CALLBACK_GREET)
  249. if(callback == nil or callback(cid)) then
  250. if(self:processModuleCallback(CALLBACK_GREET, cid)) then
  251. local msg = self:getMessage(MESSAGE_GREET)
  252. local parseInfo = { [TAG_PLAYERNAME] = getPlayerName(cid) }
  253. msg = self:parseMessage(msg, parseInfo)
  254. self:say(msg)
  255. else
  256. return
  257. end
  258. else
  259. return
  260. end
  261. end
  262. self:changeFocus(cid)
  263. end
  264.  
  265. -- Handles onCreatureAppear events. If you with to handle this yourself, please use the CALLBACK_CREATURE_APPEAR callback.
  266. function NpcHandler:onCreatureAppear(cid)
  267. local callback = self:getCallback(CALLBACK_CREATURE_APPEAR)
  268. if(callback == nil or callback(cid)) then
  269. if(self:processModuleCallback(CALLBACK_CREATURE_APPEAR, cid)) then
  270.  
  271. end
  272. end
  273. end
  274.  
  275. -- Handles onCreatureDisappear events. If you with to handle this yourself, please use the CALLBACK_CREATURE_DISAPPEAR callback.
  276. function NpcHandler:onCreatureDisappear(cid)
  277. local callback = self:getCallback(CALLBACK_CREATURE_DISAPPEAR)
  278. if(callback == nil or callback(cid)) then
  279. if(self:processModuleCallback(CALLBACK_CREATURE_DISAPPEAR, cid)) then
  280. if(self.focus == cid) then
  281. self:unGreet()
  282. end
  283. end
  284. end
  285. end
  286.  
  287. -- Handles onCreatureSay events. If you with to handle this yourself, please use the CALLBACK_CREATURE_SAY callback.
  288. function NpcHandler:onCreatureSay(cid, msgtype, msg)
  289. local callback = self:getCallback(CALLBACK_CREATURE_SAY)
  290. if(callback == nil or callback(cid, msgtype, msg)) then
  291. if(self:processModuleCallback(CALLBACK_CREATURE_SAY, cid, msgtype, msg)) then
  292. if(not self:isInRange(cid)) then
  293. return
  294. end
  295. if(self.keywordHandler ~= nil) then
  296. local ret = self.keywordHandler:processMessage(cid, msg)
  297. if(not ret) then
  298. local callback = self:getCallback(CALLBACK_MESSAGE_DEFAULT)
  299. if(callback ~= nil and callback(cid, msgtype, msg)) then
  300. self.talkStart = os.time()
  301. end
  302. else
  303. self.talkStart = os.time()
  304. end
  305. end
  306. end
  307. end
  308. end
  309.  
  310. -- Handles onThink events. If you with to handle this yourself, please use the CALLBACK_ONTHINK callback.
  311. function NpcHandler:onThink()
  312. local callback = self:getCallback(CALLBACK_ONTHINK)
  313. if(callback == nil or callback()) then
  314.  
  315. if(NPCHANDLER_TALKDELAY == TALKDELAY_ONTHINK and self.talkDelay.time ~= nil and self.talkDelay.message ~= nil and os.time() >= self.talkDelay.time) then
  316. selfSay(self.talkDelay.message)
  317. self.talkDelay.time = nil
  318. self.talkDelay.message = nil
  319. end
  320.  
  321. if(self:processModuleCallback(CALLBACK_ONTHINK)) then
  322. if(self.focus ~= 0) then
  323. if(not self:isInRange(self.focus)) then
  324. self:onWalkAway(self.focus)
  325. elseif(os.time()-self.talkStart > self.idleTime) then
  326. self:unGreet()
  327. else
  328. self:updateFocus()
  329. end
  330. end
  331. end
  332. end
  333. end
  334.  
  335. -- Tries to greet the player iwth the given cid. This function does not override queue order, current focus etc.
  336. function NpcHandler:onGreet(cid)
  337. if(self:isInRange(cid)) then
  338. if(self.focus == 0) then
  339. self:greet(cid)
  340. elseif(cid == self.focus) then
  341. local msg = self:getMessage(MESSAGE_ALREADYFOCUSED)
  342. local parseInfo = { [TAG_PLAYERNAME] = getPlayerName(cid) }
  343. msg = self:parseMessage(msg, parseInfo)
  344. self:say(msg)
  345. else
  346. if(not self.queue:isInQueue(cid)) then
  347. self.queue:push(cid)
  348. end
  349. local msg = self:getMessage(MESSAGE_PLACEDINQUEUE)
  350. local parseInfo = { [TAG_PLAYERNAME] = getPlayerName(cid), [TAG_QUEUESIZE] = self.queue:getSize() }
  351. msg = self:parseMessage(msg, parseInfo)
  352. self:say(msg)
  353. end
  354. end
  355. end
  356.  
  357. -- Simply calls the underlying unGreet function.
  358. function NpcHandler:onFarewell()
  359. self:unGreet()
  360. end
  361.  
  362. -- Should be called on this npc's focus if the distance to focus is greater then talkRadius.
  363. function NpcHandler:onWalkAway(cid)
  364. if(cid == self.focus) then
  365. local callback = self:getCallback(CALLBACK_CREATURE_DISAPPEAR)
  366. if(callback == nil or callback()) then
  367. if(self:processModuleCallback(CALLBACK_CREATURE_DISAPPEAR, cid)) then
  368. if(self.queue == nil or not self.queue:greetNext()) then
  369. local msg = self:getMessage(MESSAGE_WALKAWAY)
  370. local parseInfo = { [TAG_PLAYERNAME] = getPlayerName(self.focus) }
  371. msg = self:parseMessage(msg, parseInfo)
  372. self:say(msg)
  373. self:releaseFocus()
  374. end
  375. end
  376. end
  377. end
  378. end
  379.  
  380. -- Returns true if cid is within the talkRadius of this npc.
  381. function NpcHandler:isInRange(cid)
  382. local playerPos = getPlayerPosition(cid)
  383. if playerPos == LUA_ERROR or playerPos == LUA_NO_ERROR then
  384. return false
  385. end
  386.  
  387. local sx = selfGetPosition().x
  388. local sy = selfGetPosition().y
  389. local sz = selfGetPosition().z
  390.  
  391. local dx = math.abs(sx-playerPos.x)
  392. local dy = math.abs(sy-playerPos.y)
  393. local dz = math.abs(sz-playerPos.z)
  394.  
  395. local dist = (dx^2 + dy^2)^0.5
  396.  
  397. return (dist <= self.talkRadius and dz == 0)
  398. end
  399.  
  400. -- Resets the npc into it's initial state (in regard of the keyrodhandler).
  401. -- All modules are also receiving a reset call through their callbackOnModuleReset function.
  402. function NpcHandler:resetNpc()
  403. if(self:processModuleCallback(CALLBACK_MODULE_RESET)) then
  404. self.keywordHandler:reset()
  405. end
  406. end
  407.  
  408.  
  409. -- Makes the npc represented by this instance of NpcHandler say something.
  410. -- This implements the currently set type of talkdelay.
  411. -- shallDelay is a boolean value. If it is false, the message is not delayed. Default value is true.
  412. function NpcHandler:say(message, shallDelay)
  413. if(shallDelay == nil) then
  414. shallDelay = true
  415. end
  416. if(NPCHANDLER_TALKDELAY == TALKDELAY_NONE or shallDelay == false) then
  417. selfSay(message)
  418. return
  419. end
  420. self.talkDelay.message = message
  421. self.talkDelay.time = os.time()+self.talkDelayTime
  422. end
  423.  
  424.  
  425. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement