@@ -73,18 +73,24 @@ if not NpcEvents then
7373 --- @param npc Npc The NPC that disappeared.
7474 --- @param creature Creature The creature (player ) that the NPC disappeared from.
7575 function NpcEvents .onDisappear (npc , creature )
76- if not creature :isPlayer () then
77- return
78- end
7976 local focus = NpcFocus (npc )
80- if focus :isFocused (creature ) then
81- focus :removeFocus (creature )
82- local talkQueue = NpcTalkQueue (npc )
77+ local talkQueue = NpcTalkQueue (npc )
78+ local voices = NpcVoices (npc )
79+ -- If the creature is a player and is focused on the NPC, the focus is removed and the talk state is reset
80+ if creature :isPlayer () and focus :isFocused (creature ) then
8381 local handler = NpcsHandler (npc )
82+ focus :removeFocus (creature )
8483 talkQueue :clearQueue (creature )
8584 handler :setTalkState (handler , creature )
8685 handler :resetData (creature )
8786 end
87+
88+ -- Npc is being removed we clear all the data which is specific to it's npc id he holds to not leak memory
89+ if npc == creature then
90+ focus :clear ()
91+ talkQueue :clear ()
92+ voices :clear ()
93+ end
8894 end
8995
9096 -- onThink function is called when an NPC thinks.
@@ -166,12 +172,25 @@ if not NpcEvents then
166172 focus :removeFocus (creature )
167173 closeShopWindow (creature )
168174 local msg = handler .farewellResponses [math.random (1 , # handler .farewellResponses )]:replaceTags ({playerName = creature :getName ()})
175+ if handler :getTalkState (creature ).farewellResponses then
176+ msg = handler :getTalkState (creature ).farewellResponses [math.random (1 , # handler :getTalkState (creature ).farewellResponses )]:replaceTags ({playerName = creature :getName ()})
177+ end
169178 talkQueue :addToQueue (creature , msg , TALK .defaultDelay )
170179 handler :setTalkState (handler , creature )
171180 handler :resetData (creature )
172181 return
173182 end
174183 end
184+ -- incase the player is not focused but he has a talk state which was not resetted
185+ -- this can only happen if player talked with the npc and the npc somehow disappeared
186+ else
187+ if not handler :getTalkState (creature ):isKeyword (message ) then
188+ if handler ~= handler :getTalkState (creature ) then
189+ handler :setTalkState (handler , creature )
190+ handler :getTalkState (creature ):checkOnStorage (creature , handler )
191+ handler :resetData (creature )
192+ end
193+ end
175194 end
176195
177196 -- Checks if the NPC has a response for the given message
@@ -189,7 +208,10 @@ if not NpcEvents then
189208 if message == word then
190209 focus :addFocus (creature )
191210 doNpcSetCreatureFocus (creature :getId ())
192- local msg = handler :getTalkState (creature ).greetResponses [math.random (1 , # handler :getTalkState (creature ).greetResponses )]:replaceTags ({playerName = creature :getName ()})
211+ local msg = handler .greetResponses [math.random (1 , # handler .greetResponses )]:replaceTags ({playerName = creature :getName ()})
212+ if handler :getTalkState (creature ).greetResponses then
213+ msg = handler :getTalkState (creature ).greetResponses [math.random (1 , # handler :getTalkState (creature ).greetResponses )]:replaceTags ({playerName = creature :getName ()})
214+ end
193215 talkQueue :addToQueue (creature , msg , TALK .defaultDelay )
194216 greeted = true
195217 break
@@ -199,6 +221,8 @@ if not NpcEvents then
199221 return
200222 end
201223 end
224+ -- incase shop is open and the player swaps the talk state, then we need to close the shop
225+ closeShopWindow (creature )
202226 -- renewing the focus for the player
203227 focus :addFocus (creature )
204228
@@ -209,29 +233,16 @@ if not NpcEvents then
209233 handler :getTalkState (creature ):checkOnStorage (creature , handler )
210234 end
211235 -- checking for requirements
212- local ret , msg , reqType = handler :getTalkState (creature ):requirements ():init (creature )
236+ local ret , msg = handler :getTalkState (creature ):requirements ():init (creature )
213237 if not ret then
214- if handler : getTalkState ( creature ): requirements (): getFailureRespond ( reqType ) then
215- msg = handler : getTalkState (creature ): requirements (): getFailureRespond ( reqType ): replaceTags ({ playerName = creature : getName ()} )
238+ if msg then
239+ talkQueue : addToQueue (creature , msg , TALK . defaultDelay )
216240 end
217- talkQueue :addToQueue (creature , msg , TALK .defaultDelay )
218241 local _ , start = next (handler .keywords )
219242 handler :setTalkState (start , creature )
220243 handler :getTalkState (creature ):checkOnStorage (creature , handler )
221244 return
222245 end
223- -- check if we want to release focus for this keyword
224- if handler :getTalkState (creature ).releaseFocus then
225- if handler :getTalkState (creature ):getResponse () then
226- local msg = handler :getTalkState (creature ):getResponse ():replaceTags ({playerName = creature :getName ()})
227- talkQueue :addToQueue (creature , msg , TALK .defaultDelay )
228- end
229- focus :removeFocus (creature )
230- closeShopWindow (creature )
231- handler :setTalkState (handler , creature )
232- handler :resetData (creature )
233- return
234- end
235246 -- check if we have a callback for this talk state
236247 local messageSent = false
237248 if handler :getTalkState (creature ).callback then
@@ -246,7 +257,8 @@ if not NpcEvents then
246257 handler :setTalkState (start , creature )
247258 handler :getTalkState (creature ):checkOnStorage (creature , handler )
248259 if msg == " " then
249- print (" [Warning - NpcEvents.onSay] There is no failureResponse set for keyword: " .. message .. " .\n " .. debug.getinfo (2 ).source :match (" @?(.*)" ))
260+ print (" [Warning - NpcEvents.onSay] Npc: " .. npc :getName () .. " There is no failureResponse set for keyword: " .. message )
261+ print (debug.getinfo (handler :getTalkState (creature ).callback ).source :match (" @?(.*)" ))
250262 end
251263 return
252264 end
@@ -256,18 +268,11 @@ if not NpcEvents then
256268 end
257269 end
258270 -- checking for modules
259- -- todo implement modules
260- if handler :getTalkState (creature ).teleportPosition then
261- focus :removeFocus (creature )
262- closeShopWindow (creature )
263- local msg = handler :getTalkState (creature ):getResponse ():replaceTags ({playerName = creature :getName ()})
264- selfSay (msg , creature )
265- Position (creature :getPosition ()):sendMagicEffect (handler :getTalkState (creature ).teleportPosition .magicEffectFromPos )
266- creature :teleportTo (handler :getTalkState (creature ).teleportPosition .position )
267- Position (creature :getPosition ()):sendMagicEffect (handler :getTalkState (creature ).teleportPosition .magicEffectToPos )
268- handler :setTalkState (handler , creature )
269- handler :resetData (creature )
270- return
271+ if handler :getTalkState (creature ).modules then
272+ if handler :getTalkState (creature ).modules :init (npc , creature ) == false then
273+ -- need to do that because of teleport
274+ return
275+ end
271276 end
272277 -- If the NPC has a shop for the message, it opens the shop window
273278 if handler :getTalkState (creature ):getShop (message ) then
@@ -284,53 +289,24 @@ if not NpcEvents then
284289 subtype = item .subtype == nil and nil or item .subtype
285290 })
286291 end
287- npc :openShopWindow (creature , afterDiscount , shop .onBuy , shop .onSell )
288- else
289- npc :openShopWindow (creature , items , shop .onBuy , shop .onSell )
290- end
291- end
292- -- If the Player gets a storage value set
293- if handler :getTalkState (creature ).setStorage then
294- local storage = handler :getTalkState (creature ).setStorage
295- creature :setStorageValue (storage .key , storage .value )
296- end
297- -- If the Player gets items added (goes into the backpack by default but if there is no space/capacity it goes into inbox)
298- if handler :getTalkState (creature ).items then
299- local weight = 0
300- for _ , item in pairs (handler :getTalkState (creature ).items .items ) do
301- -- checking how much all items would weight
302- weight = weight + ItemType (item .item ):getWeight (item .count )
303- end
304- local backpack = creature :getSlotItem (CONST_SLOT_BACKPACK ) and Container (creature :getSlotItem (CONST_SLOT_BACKPACK ).uid ) or nil
305- -- checking if the player has enough capacity or has a backpack
306- if creature :getFreeCapacity () < weight or not backpack then
307- local containerId = handler :getTalkState (creature ).items .container or ITEM_SHOPPING_BAG
308- creature :sendInboxItems (handler :getTalkState (creature ).items .items , containerId )
309- local msg = " The items are to heavy for you to carry. I've sent them to your inbox."
310- creature :sendTextMessage (MESSAGE_STATUS_CONSOLE_BLUE , msg )
311- -- checking if the player has enough space in the backpack
312- elseif backpack and backpack :getEmptySlots (true ) < # handler :getTalkState (creature ).items .items then
313- local containerId = handler :getTalkState (creature ).items .container or ITEM_SHOPPING_BAG
314- creature :sendInboxItems (handler :getTalkState (creature ).items .items , containerId )
315- local msg = " You don't have enough space in your backpack. I've sent the items to your inbox."
316- creature :sendTextMessage (MESSAGE_STATUS_CONSOLE_BLUE , msg )
317- -- checking if we should add the items by default into inbox
318- elseif handler :getTalkState (creature ).items .inbox then
319- local containerId = handler :getTalkState (creature ).items .container or ITEM_SHOPPING_BAG
320- creature :sendInboxItems (handler :getTalkState (creature ).items .items , containerId )
321- local msg = " Your items are waiting for you in your inbox."
322- creature :sendTextMessage (MESSAGE_STATUS_CONSOLE_BLUE , msg )
292+ if shop .callback then
293+ afterDiscount = shop :callback (npc , creature , handler , items , afterDiscount )
294+ end
295+ if type (afterDiscount ) == " table" then
296+ npc :openShopWindow (creature , afterDiscount , shop .onBuy , shop .onSell )
297+ else
298+ print (" [Warning - NpcEvents.onSay] Callback for Npc: " .. npc :getName () .. " with shop: " .. handler :getActiveShop (creature ) .. " did not return a table." )
299+ print (debug.getinfo (shop .callback ).source :match (" @?(.*)" ))
300+ end
323301 else
324- if handler :getTalkState (creature ).items .container then
325- local container = Game .createItem (handler :getTalkState (creature ).items .container , 1 )
326- for _ , item in pairs (handler :getTalkState (creature ).items .items ) do
327- container :addItem (item .item , item .count )
328- end
329- container :moveTo (creature )
302+ if shop .callback then
303+ items = shop :callback (npc , creature , handler , items )
304+ end
305+ if type (items ) == " table" then
306+ npc :openShopWindow (creature , items , shop .onBuy , shop .onSell )
330307 else
331- for _ , item in pairs (handler :getTalkState (creature ).items .items ) do
332- creature :addItem (item .item , item .count )
333- end
308+ print (" [Warning - NpcEvents.onSay] Callback for Npc: " .. npc :getName () .. " with shop: " .. handler :getActiveShop (creature ) .. " did not return a table." )
309+ print (debug.getinfo (shop .callback ).source :match (" @?(.*)" ))
334310 end
335311 end
336312 end
@@ -341,6 +317,18 @@ if not NpcEvents then
341317 talkQueue :addToQueue (creature , msg , TALK .defaultDelay )
342318 end
343319 end
320+ -- check if we want to release focus for this keyword
321+ if handler :getTalkState (creature ).releaseFocus then
322+ if handler :getTalkState (creature ):getResponse () then
323+ local msg = handler :getTalkState (creature ):getResponse ():replaceTags ({playerName = creature :getName ()})
324+ talkQueue :addToQueue (creature , msg , TALK .defaultDelay )
325+ end
326+ focus :removeFocus (creature )
327+ closeShopWindow (creature )
328+ handler :setTalkState (handler , creature )
329+ handler :resetData (creature )
330+ return
331+ end
344332 -- if the NPC has reached the last keyword, it resets the talk state
345333 if next (handler :getTalkState (creature ).keywords ) == nil and not handler :getTalkState (creature ).answer then
346334 local _ , start = next (handler .keywords )
@@ -397,7 +385,8 @@ if not NpcEvents then
397385 handler :setTalkState (start , creature )
398386 handler :getTalkState (creature ):checkOnStorage (creature , handler )
399387 if msg == " " then
400- print (" [Warning - NpcEvents.onSay] There is no failureResponse set for keyword: " .. message .. " .\n " .. debug.getinfo (2 ).source :match (" @?(.*)" ))
388+ print (" [Warning - NpcEvents.onSay] Npc: " .. npc :getName () .. " has no failureResponse set for keyword: " .. message .. " ." )
389+ print (debug.getinfo (handler :getTalkState (creature ).callback ).source :match (" @?(.*)" ))
401390 end
402391 handler :resetData (creature )
403392 return
@@ -407,7 +396,8 @@ if not NpcEvents then
407396 messageSent = true
408397 end
409398 else
410- print (" [Warning - NpcEvents.onSay] Npc: " .. npc :getName () .. " has no callback set for onAnswer\n " .. debug.getinfo (2 ).source :match (" @?(.*)" ))
399+ print (" [Error - NpcEvents.onSay] Npc: " .. npc :getName () .. " has no callback set for onAnswer" )
400+ print (debug.getinfo (handler :getTalkState (creature ).callback ).source :match (" @?(.*)" ))
411401 local _ , start = next (handler .keywords )
412402 handler :setTalkState (start , creature )
413403 handler :getTalkState (creature ):checkOnStorage (creature , handler )
0 commit comments