• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Error in NPC (dont talk)

Pyromaniack

New Member
Joined
Feb 9, 2011
Messages
56
Reaction score
3
Well my error i cant talk with npc they just dont respond:

Console error:
[Error - NpcScript Interface]
Description:
data/npc/lib/npc.lua:51: attempt to call global 'isValidPosition' (a nil value)
stack traceback:
data/npc/lib/npc.lua:51: in function 'getNpcDestanceTo'
data/npc/lib/npcsystem/npchandler.lua:597: in function 'isInRange'
data/npc/lib/npcsystem/npchandler.lua:414: in function 'onCreatureSay'

My script
npc.lua
Code:
function selfSayChannel(cid, message)
	return selfSay(message, cid, false)
end

function selfMoveToThing(id)
	errors(false)
	local thing = getThing(id)

	errors(true)
	if(thing.uid == 0) then
		return
	end

	local t = getThingPosition(id)
	selfMoveTo(t.x, t.y, t.z)
	return
end

function selfMoveTo(x, y, z)
	local position = {x = 0, y = 0, z = 0}
	if(type(x) ~= "table") then
		position = Position(x, y, z)
	else
		position = x
	end

	if(isValidPosition(position)) then
		doSteerCreature(getNpcId(), position)
	end
end

function selfMove(direction, flags)
	local flags = flags or 0
	doMoveCreature(getNpcId(), direction, flags)
end

function selfTurn(direction)
	doCreatureSetLookDirection(getNpcId(), direction)
end

function getNpcDistanceTo(id)
	errors(false)
	local thing = getThing(id)

	errors(true)
	if(thing.uid == 0) then
		return nil
	end

	local c = getCreaturePosition(id)
	if(not isValidPosition(c)) then
		return nil
	end

	local s = getCreaturePosition(getNpcId())
	if(not isValidPosition(s) or s.z ~= c.z) then
		return nil
	end

	return math.max(math.abs(s.x - c.x), math.abs(s.y - c.y))
end

function doMessageCheck(message, keyword)
	if(type(keyword) == "table") then
		return table.isStrIn(keyword, message)
	end

	local a, b = message:lower(), keyword:lower()
	if(keyword == message) then
		return true
	end

	return message:find(keyword) and not message:find('(%w+)' .. keyword)
end

function doNpcSellItem(cid, itemid, amount, subType, ignoreCap, inBackpacks, backpack)
	local amount, subType, ignoreCap, item = amount or 1, subType or 1, ignoreCap and true or false, 0
	if(isItemStackable(itemid)) then
		if(isItemRune(itemid)) then
			amount = amount * subType
		end

		local count = amount
		repeat
			item = doCreateItemEx(itemid, math.min(100, count))
			if(doPlayerAddItemEx(cid, item, ignoreCap) ~= RETURNVALUE_NOERROR) then
				return 0, 0
			end

			count = count - math.min(100, count)
		until count == 0
		return amount, 0
	end

	local a = 0
	if(inBackpacks) then
		local container, b = doCreateItemEx(backpack, 1), 1
		for i = 1, amount do
			item = doAddContainerItem(container, itemid, subType)
			if(itemid == ITEM_PARCEL) then
				doAddContainerItem(item, ITEM_LABEL)
			end

			if(isInArray({(getContainerCapById(backpack) * b), amount}, i)) then
				if(doPlayerAddItemEx(cid, container, ignoreCap) ~= RETURNVALUE_NOERROR) then
					b = b - 1
					break
				end

				a = i
				if(amount > i) then
					container = doCreateItemEx(backpack, 1)
					b = b + 1
				end
			end
		end

		return a, b
	end

	for i = 1, amount do
		item = doCreateItemEx(itemid, subType)
		if(itemid == ITEM_PARCEL) then
			doAddContainerItem(item, ITEM_LABEL)
		end

		if(doPlayerAddItemEx(cid, item, ignoreCap) ~= RETURNVALUE_NOERROR) then
			break
		end

		a = i
	end

	return a, 0
end

function doRemoveItemIdFromPosition(id, n, position)
	local thing = getThingFromPos({x = position.x, y = position.y, z = position.z, stackpos = 1})
	if(thing.itemid ~= id) then
		return false
	end

	doRemoveItem(thing.uid, n)
	return true
end

function getNpcName()
	return getCreatureName(getNpcId())
end

function getNpcPos()
	return getThingPosition(getNpcId())
end

function selfGetPosition()
	local t = getThingPosition(getNpcId())
	return t.x, t.y, t.z
end

msgcontains = doMessageCheck
moveToPosition = selfMoveTo
moveToCreature = selfMoveToThing
selfMoveToCreature = selfMoveToThing
selfMoveToPosition = selfMoveTo
isPlayerPremiumCallback = isPremium
doPosRemoveItem = doRemoveItemIdFromPosition
doRemoveItemIdFromPos = doRemoveItemIdFromPosition
doNpcBuyItem = doPlayerRemoveItem
doNpcSetCreatureFocus = selfFocus
getNpcCid = getNpcId
getDistanceTo = getNpcDistanceTo
getDistanceToCreature = getNpcDistanceTo
getNpcDistanceToCreature = getNpcDistanceTo

npchandler.lua

Code:
-- Advanced NPC System (Created by Jiddo),
-- Modified by TheForgottenServer Team,
-- Modified by Silver Moonlight Team

if(NpcHandler == nil) then
	-- Constant talkdelay behaviors.
	TALKDELAY_NONE = 0 -- No talkdelay. Npc will reply immedeatly.
	TALKDELAY_ONTHINK = 1 -- Talkdelay handled through the onThink callback function. (Default)
	TALKDELAY_EVENT = 2 -- Not yet implemented

	-- Currently applied talkdelay behavior. TALKDELAY_ONTHINK is default.
	NPCHANDLER_TALKDELAY = TALKDELAY_ONTHINK

	-- Constant conversation behaviors.
	CONVERSATION_DEFAULT = 0 -- Conversation through default window, like it was before 8.2 update.
	CONVERSATION_PRIVATE = 1 -- Conversation through NPCs chat window, as of 8.2 update. (Default)
		--Small Note: Private conversations also means the NPC will use multi-focus system.

	-- Currently applied conversation behavior. CONVERSATION_PRIVATE is default.
	NPCHANDLER_CONVBEHAVIOR = CONVERSATION_PRIVATE

	-- Constant indexes for defining default messages.
	MESSAGE_GREET 			= 1 -- When the player greets the npc.
	MESSAGE_FAREWELL 		= 2 -- When the player unGreets the npc.
	MESSAGE_BUY 			= 3 -- When the npc asks the player if he wants to buy something.
	MESSAGE_ONBUY 			= 4 -- When the player successfully buys something via talk.
	MESSAGE_BOUGHT			= 5 -- When the player bought something through the shop window.
	MESSAGE_SELL 			= 6 -- When the npc asks the player if he wants to sell something.
	MESSAGE_ONSELL 			= 7 -- When the player successfully sells something via talk.
	MESSAGE_SOLD			= 8 -- When the player sold something through the shop window.
	MESSAGE_MISSINGMONEY		= 9 -- When the player does not have enough money.
	MESSAGE_NEEDMONEY		= 10 -- Same as above, used for shop window.
	MESSAGE_MISSINGITEM		= 11 -- When the player is trying to sell an item he does not have.
	MESSAGE_NEEDITEM		= 12 -- Same as above, used for shop window.
	MESSAGE_NEEDSPACE 		= 13 -- When the player don't have any space to buy an item
	MESSAGE_NEEDMORESPACE		= 14 -- When the player has some space to buy an item, but not enough space
	MESSAGE_IDLETIMEOUT		= 15 -- When the player has been idle for longer then idleTime allows.
	MESSAGE_WALKAWAY		= 16 -- When the player walks out of the talkRadius of the npc.
	MESSAGE_DECLINE			= 17 -- When the player says no to something.
	MESSAGE_SENDTRADE		= 18 -- When the npc sends the trade window to the player
	MESSAGE_NOSHOP			= 19 -- When the npc's shop is requested but he doesn't have any
	MESSAGE_ONCLOSESHOP		= 20 -- When the player closes the npc's shop window
	MESSAGE_ALREADYFOCUSED		= 21 -- When the player already has the focus of this npc.
	MESSAGE_PLACEDINQUEUE		= 22 -- When the player has been placed in the costumer queue.

	-- Constant indexes for callback functions. These are also used for module callback ids.
	CALLBACK_CREATURE_APPEAR 	= 1
	CALLBACK_CREATURE_DISAPPEAR	= 2
	CALLBACK_CREATURE_SAY 		= 3
	CALLBACK_ONTHINK 		= 4
	CALLBACK_GREET 			= 5
	CALLBACK_FAREWELL 		= 6
	CALLBACK_MESSAGE_DEFAULT 	= 7
	CALLBACK_PLAYER_ENDTRADE 	= 8
	CALLBACK_PLAYER_CLOSECHANNEL	= 9
	CALLBACK_ONBUY			= 10
	CALLBACK_ONSELL			= 11

	-- Addidional module callback ids
	CALLBACK_MODULE_INIT		= 12
	CALLBACK_MODULE_RESET		= 13

	-- Constant strings defining the keywords to replace in the default messages.
	TAG_PLAYERNAME = '|PLAYERNAME|'
	TAG_ITEMCOUNT = '|ITEMCOUNT|'
	TAG_TOTALCOST = '|TOTALCOST|'
	TAG_ITEMNAME = '|ITEMNAME|'
	TAG_QUEUESIZE = '|QUEUESIZE|'

	NpcHandler = {
		keywordHandler = nil,
		focuses = nil,
		talkStart = nil,
		idleTime = 300,
		talkRadius = 4,
		talkDelayTime = 1, -- Seconds to delay outgoing messages.
		queue = nil,
		talkDelay = nil,
		callbackFunctions = nil,
		modules = nil,
		shopItems = nil, -- They must be here since ShopModule uses "static" functions
		messages = {
			-- These are the default replies of all npcs. They can/should be changed individually for each npc.
			[MESSAGE_GREET] 	= 'Welcome, |PLAYERNAME|! I have been expecting you.',
			[MESSAGE_FAREWELL] 	= 'Good bye, |PLAYERNAME|!',
			[MESSAGE_BUY] 		= 'Do you want to buy |ITEMCOUNT| |ITEMNAME| for |TOTALCOST| gold coins?',
			[MESSAGE_ONBUY] 	= 'It was a pleasure doing business with you.',
			[MESSAGE_BOUGHT] 	= 'Bought |ITEMCOUNT|x |ITEMNAME| for |TOTALCOST| gold.',
			[MESSAGE_SELL] 		= 'Do you want to sell |ITEMCOUNT| |ITEMNAME| for |TOTALCOST| gold coins?',
			[MESSAGE_ONSELL] 	= 'Thank you for this |ITEMNAME|, |PLAYERNAME| gold.',
			[MESSAGE_SOLD]	 	= 'Sold |ITEMCOUNT|x |ITEMNAME| for |TOTALCOST| gold.',
			[MESSAGE_MISSINGMONEY]	= 'Sorry, you don\'t have enough money.',
			[MESSAGE_NEEDMONEY] 	= 'You do not have enough money.',
			[MESSAGE_MISSINGITEM] 	= 'You don\'t even have that item, |PLAYERNAME|!',
			[MESSAGE_NEEDITEM]	= 'You do not have this object.',
			[MESSAGE_NEEDSPACE]	= 'You do not have enough capacity.',
			[MESSAGE_NEEDMORESPACE]	= 'You do not have enough capacity for all items.',
			[MESSAGE_IDLETIMEOUT] 	= 'Next, please!',
			[MESSAGE_WALKAWAY] 	= 'How rude!',
			[MESSAGE_DECLINE]	= 'Not good enough, is it... ?',
			[MESSAGE_SENDTRADE]	= 'Here\'s my offer, |PLAYERNAME|. Don\'t you like it?',
			[MESSAGE_NOSHOP]	= 'Sorry, I\'m not offering anything.',
			[MESSAGE_ONCLOSESHOP]	= 'Thank you, come back when you want something more.',
			[MESSAGE_ALREADYFOCUSED]= '|PLAYERNAME|! I am already talking to you...',
			[MESSAGE_PLACEDINQUEUE] = '|PLAYERNAME|, please wait for your turn. There are |QUEUESIZE| customers before you.'
		}
	}

	-- Creates a new NpcHandler with an empty callbackFunction stack.
	function NpcHandler:new(keywordHandler)
		local obj = {}
		obj.callbackFunctions = {}
		obj.modules = {}
		if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
			obj.focuses = {}
			obj.talkStart = {}
		else
			obj.queue = Queue:new(obj)
			obj.focuses = 0
			obj.talkStart = 0
		end
		obj.talkDelay = {}
		obj.keywordHandler = keywordHandler
		obj.messages = {}
		obj.shopItems = {}

		setmetatable(obj.messages, self.messages)
		self.messages.__index = self.messages

		setmetatable(obj, self)
		self.__index = self
		return obj
	end

	-- Re-defines the maximum idle time allowed for a player when talking to this npc.
	function NpcHandler:setMaxIdleTime(newTime)
		self.idleTime = newTime
	end

	-- Attackes a new keyword handler to this npchandler
	function NpcHandler:setKeywordHandler(newHandler)
		self.keywordHandler = newHandler
	end

	-- Function used to change the focus of this npc.
	function NpcHandler:addFocus(newFocus)
		if(not isCreature(newFocus)) then
			return
		end

		if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
			if(self:isFocused(newFocus, true)) then
				return
			end

			table.insert(self.focuses, newFocus)
		else
			self.focuses = newFocus
		end

		self:updateFocus(true)
	end
	NpcHandler.changeFocus = NpcHandler.addFocus -- "changeFocus" looks better for CONVERSATION_DEFAULT

	-- Function used to verify if npc is focused to certain player
	function NpcHandler:isFocused(focus, creatureCheck)
		local creatureCheck = creatureCheck or false
		if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
			for k, v in pairs(self.focuses) do
				if(v == focus) then
					if(creatureCheck or isCreature(v)) then
						return true
					end

					self:internalReleaseFocus(focus, k)
					return false
				end
			end

			return false
		end

		if(creatureCheck or isCreature(self.focuses)) then
			return self.focuses == focus
		end

		self:changeFocus(0)
		return false
	end

	-- This function should be called on each onThink and makes sure the npc faces the player it is talking to.
	--	Should also be called whenever a new player is focused.
	function NpcHandler:updateFocus(creatureCheck)
		local creatureCheck = creatureCheck or false
		if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
			for _, focus in pairs(self.focuses) do
				if(creatureCheck or isCreature(focus)) then
					doNpcSetCreatureFocus(focus)
					return
				end
			end
		elseif(creatureCheck or isCreature(self.focuses)) then
			doNpcSetCreatureFocus(self.focuses)
			return
		end

		doNpcSetCreatureFocus(0)
	end

	-- Used when the npc should un-focus the player.
	function NpcHandler:releaseFocus(focus)
		if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
			if(not self:isFocused(focus)) then
				return
			end

			local pos = nil
			for k, v in pairs(self.focuses) do
				if(v == focus) then
					pos = k
				end
			end

			if(pos ~= nil) then
				self:internalReleaseFocus(focus, pos)
				closeShopWindow(focus)
			end
		elseif(self.focuses == focus) then
			self:changeFocus(0)
			if(isCreature(focus)) then
				closeShopWindow(focus)
			end
		end
	end

	-- Internal un-focusing function, beware using!
	function NpcHandler:internalReleaseFocus(focus, pos)
		if(type(self.focuses) ~= "table" or pos == nil or self.focuses[pos] == nil) then
			return
		end

		table.remove(self.focuses, pos)
		self.talkStart[focus] = nil
		self:updateFocus()
	end

	-- Returns the callback function with the specified id or nil if no such callback function exists.
	function NpcHandler:getCallback(id)
		local ret = nil
		if(self.callbackFunctions ~= nil) then
			ret = self.callbackFunctions[id]
		end

		return ret
	end

	-- Changes the callback function for the given id to callback.
	function NpcHandler:setCallback(id, callback)
		if(self.callbackFunctions ~= nil) then
			self.callbackFunctions[id] = callback
		end
	end

	-- Adds a module to this npchandler and inits it.
	function NpcHandler:addModule(module)
		if(self.modules == nil or module == nil) then
			return false
		end

		module:init(self)
		if(module.parseParameters ~= nil) then
			module:parseParameters()
		end

		table.insert(self.modules, module)
		return true
	end

	-- Calls the callback function represented by id for all modules added to this npchandler with the given arguments.
	function NpcHandler:processModuleCallback(id, ...)
		local ret = true
		for _, module in pairs(self.modules) do
			local tmpRet = true
			if(id == CALLBACK_CREATURE_APPEAR and module.callbackOnCreatureAppear ~= nil) then
				tmpRet = module:callbackOnCreatureAppear(unpack(arg))
			elseif(id == CALLBACK_CREATURE_DISAPPEAR and module.callbackOnCreatureDisappear ~= nil) then
				tmpRet = module:callbackOnCreatureDisappear(unpack(arg))
			elseif(id == CALLBACK_CREATURE_SAY and module.callbackOnCreatureSay ~= nil) then
				tmpRet = module:callbackOnCreatureSay(unpack(arg))
			elseif(id == CALLBACK_PLAYER_ENDTRADE and module.callbackOnPlayerEndTrade ~= nil) then
				tmpRet = module:callbackOnPlayerEndTrade(unpack(arg))
			elseif(id == CALLBACK_PLAYER_CLOSECHANNEL and module.callbackOnPlayerCloseChannel ~= nil) then
				tmpRet = module:callbackOnPlayerCloseChannel(unpack(arg))
			elseif(id == CALLBACK_ONBUY and module.callbackOnBuy ~= nil) then
				tmpRet = module:callbackOnBuy(unpack(arg))
			elseif(id == CALLBACK_ONSELL and module.callbackOnSell ~= nil) then
				tmpRet = module:callbackOnSell(unpack(arg))
			elseif(id == CALLBACK_ONTHINK and module.callbackOnThink ~= nil) then
				tmpRet = module:callbackOnThink(unpack(arg))
			elseif(id == CALLBACK_GREET and module.callbackOnGreet ~= nil) then
				tmpRet = module:callbackOnGreet(unpack(arg))
			elseif(id == CALLBACK_FAREWELL and module.callbackOnFarewell ~= nil) then
				tmpRet = module:callbackOnFarewell(unpack(arg))
			elseif(id == CALLBACK_MESSAGE_DEFAULT and module.callbackOnMessageDefault ~= nil) then
				tmpRet = module:callbackOnMessageDefault(unpack(arg))
			elseif(id == CALLBACK_MODULE_RESET and module.callbackOnModuleReset ~= nil) then
				tmpRet = module:callbackOnModuleReset(unpack(arg))
			end

			if(not tmpRet) then
				ret = false
				break
			end
		end

		return ret
	end

	-- Returns the message represented by id.
	function NpcHandler:getMessage(id)
		local ret = nil
		if(self.messages ~= nil) then
			ret = self.messages[id]
		end

		return ret
	end

	-- Changes the default response message with the specified id to newMessage.
	function NpcHandler:setMessage(id, newMessage)
		if(self.messages ~= nil) then
			self.messages[id] = newMessage
		end
	end

	-- Translates all message tags found in msg using parseInfo
	function NpcHandler:parseMessage(msg, parseInfo)
		for search, replace in pairs(parseInfo) do
			if(replace ~= nil) then
				msg = msg:gsub(search, replace)
			end
		end

		return msg
	end

	-- Makes sure the npc un-focuses the currently focused player
	function NpcHandler:unGreet(cid)
		if(not self:isFocused(cid)) then
			return
		end

		local callback = self:getCallback(CALLBACK_FAREWELL)
		if(callback == nil or callback(cid)) then
			if(self:processModuleCallback(CALLBACK_FAREWELL)) then
				if(self.queue == nil or not self.queue:greetNext()) then
					local msg = self:getMessage(MESSAGE_FAREWELL)
					local parseInfo = { [TAG_PLAYERNAME] = getPlayerName(cid) }
					msg = self:parseMessage(msg, parseInfo)

					self:say(msg, cid)
					self:releaseFocus(cid)
					self:say(msg)
				end
			end
		end
	end

	-- Greets a new player.
	function NpcHandler:greet(cid)
		if(cid ~= 0) then
			local callback = self:getCallback(CALLBACK_GREET)
			if(callback == nil or callback(cid)) then
				if(self:processModuleCallback(CALLBACK_GREET, cid)) then
					local msg = self:getMessage(MESSAGE_GREET)
					local parseInfo = { [TAG_PLAYERNAME] = getCreatureName(cid) }
					msg = self:parseMessage(msg, parseInfo)

					self:say(msg)
					self:addFocus(cid)
					self:say(msg, cid)
				end
			end
		end
	end

	-- Handles onCreatureAppear events. If you with to handle this yourself, please use the CALLBACK_CREATURE_APPEAR callback.
	function NpcHandler:onCreatureAppear(cid)
		local callback = self:getCallback(CALLBACK_CREATURE_APPEAR)
		if(callback == nil or callback(cid)) then
			if(self:processModuleCallback(CALLBACK_CREATURE_APPEAR, cid)) then
				--
			end
		end
	end

	-- Handles onCreatureDisappear events. If you with to handle this yourself, please use the CALLBACK_CREATURE_DISAPPEAR callback.
	function NpcHandler:onCreatureDisappear(cid)
		local callback = self:getCallback(CALLBACK_CREATURE_DISAPPEAR)
		if(callback == nil or callback(cid)) then
			if(self:processModuleCallback(CALLBACK_CREATURE_DISAPPEAR, cid)) then
				if(self:isFocused(cid)) then
					self:unGreet(cid)
				end
			end
		end
	end

	-- Handles onCreatureSay events. If you with to handle this yourself, please use the CALLBACK_CREATURE_SAY callback.
	function NpcHandler:onCreatureSay(cid, class, msg)
		local callback = self:getCallback(CALLBACK_CREATURE_SAY)
		if(callback == nil or callback(cid, class, msg)) then
			if(self:processModuleCallback(CALLBACK_CREATURE_SAY, cid, class, msg)) then
				if(not self:isInRange(cid)) then
					return
				end

				if(self.keywordHandler ~= nil) then
					if((self:isFocused(cid) and (class == TALKTYPE_PRIVATE_PN or NPCHANDLER_CONVBEHAVIOR == CONVERSATION_DEFAULT)) or not self:isFocused(cid)) then
						local ret = self.keywordHandler:processMessage(cid, msg)
						if(not ret) then
							local callback = self:getCallback(CALLBACK_MESSAGE_DEFAULT)
							if(callback ~= nil and callback(cid, class, msg)) then
								if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
									self.talkStart[cid] = os.time()
								else
									self.talkStart = os.time()
								end
							end
						elseif(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
							self.talkStart[cid] = os.time()
						else
							self.talkStart = os.time()
						end
					end
				end
			end
		end
	end

	-- Handles onPlayerEndTrade events. If you wish to handle this yourself, use the CALLBACK_PLAYER_ENDTRADE callback.
	function NpcHandler:onPlayerEndTrade(cid)
		local callback = self:getCallback(CALLBACK_PLAYER_ENDTRADE)
		if(callback == nil or callback(cid)) then
			if(self:processModuleCallback(CALLBACK_PLAYER_ENDTRADE, cid, class, msg)) then
				if(self:isFocused(cid)) then
					local parseInfo = { [TAG_PLAYERNAME] = getPlayerName(cid) }
					local msg = self:parseMessage(self:getMessage(MESSAGE_ONCLOSESHOP), parseInfo)
					self:say(msg, cid)
				end
			end
		end
	end

	-- Handles onPlayerCloseChannel events. If you wish to handle this yourself, use the CALLBACK_PLAYER_CLOSECHANNEL callback.
	function NpcHandler:onPlayerCloseChannel(cid)
		local callback = self:getCallback(CALLBACK_PLAYER_CLOSECHANNEL)
		if(callback == nil or callback(cid)) then
			if(self:processModuleCallback(CALLBACK_PLAYER_CLOSECHANNEL, cid, class, msg)) then
				if(self:isFocused(cid)) then
					self:unGreet(cid)
				end
			end
		end
	end

	-- Handles onBuy events. If you wish to handle this yourself, use the CALLBACK_ONBUY callback.
	function NpcHandler:onBuy(cid, itemid, subType, amount, ignoreCap, inBackpacks)
		local callback = self:getCallback(CALLBACK_ONBUY)
		if(callback == nil or callback(cid, itemid, subType, amount, ignoreCap, inBackpacks)) then
			if(self:processModuleCallback(CALLBACK_ONBUY, cid, itemid, subType, amount, ignoreCap, inBackpacks)) then
				--
			end
		end
	end

	-- Handles onSell events. If you wish to handle this yourself, use the CALLBACK_ONSELL callback.
	function NpcHandler:onSell(cid, itemid, subType, amount, ignoreCap, inBackpacks)
		local callback = self:getCallback(CALLBACK_ONSELL)
		if(callback == nil or callback(cid, itemid, subType, amount, ignoreCap, inBackpacks)) then
			if(self:processModuleCallback(CALLBACK_ONSELL, cid, itemid, subType, amount, ignoreCap, inBackpacks)) then
				--
			end
		end
	end

	-- Handles onThink events. If you wish to handle this yourself, please use the CALLBACK_ONTHINK callback.
	function NpcHandler:onThink()
		local callback = self:getCallback(CALLBACK_ONTHINK)
		if(callback == nil or callback()) then
			for i, speech in pairs(self.talkDelay) do
				if(speech.cid ~= nil and isCreature(speech.cid) and speech.start ~= nil and speech.time ~= nil and speech.message ~= nil) then
					if(os.mtime() >= speech.time) then
						local talkStart = (NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT and self.talkStart[speech.cid] or self.talkStart)
						if(self:isFocused(speech.cid) and talkStart == speech.start) then
							if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
								selfSay(speech.message, speech.cid)
							else
								selfSay(speech.message)
							end
						end

						self.talkDelay[i] = nil
					end
				else
					self.talkDelay[i] = nil
				end
			end

			if(self:processModuleCallback(CALLBACK_ONTHINK)) then
				if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
					for _, focus in pairs(self.focuses) do
						if(focus ~= nil) then
							if(not self:isInRange(focus)) then
								self:onWalkAway(focus)
							elseif((os.time() - self.talkStart[focus]) > self.idleTime) then
								self:unGreet(focus)
							else
								self:updateFocus()
							end
						end
					end
				elseif(self.focuses ~= 0) then
					if(not self:isInRange(self.focuses)) then
						self:onWalkAway(self.focuses)
					elseif((os.time() - self.talkStart) > self.idleTime) then
						self:unGreet(self.focuses)
					else
						self:updateFocus()
					end
				end
			end
		end
	end

	-- Tries to greet the player with the given cid.
	function NpcHandler:onGreet(cid)
		if(self:isInRange(cid)) then
			if(NPCHANDLER_CONVBEHAVIOR == CONVERSATION_PRIVATE) then
				if(not self:isFocused(cid)) then
					self:greet(cid)
					return
				end
			elseif(NPCHANDLER_CONVBEHAVIOR == CONVERSATION_DEFAULT) then
				if(self.focuses == 0) then
					self:greet(cid)
				elseif(self.focuses == cid) then
					local msg = self:getMessage(MESSAGE_ALREADYFOCUSED)
					local parseInfo = { [TAG_PLAYERNAME] = getCreatureName(cid) }
					msg = self:parseMessage(msg, parseInfo)
					self:say(msg)
				else
					if(not self.queue:isInQueue(cid)) then
						self.queue:push(cid)
					end

					local msg = self:getMessage(MESSAGE_PLACEDINQUEUE)
					local parseInfo = { [TAG_PLAYERNAME] = getCreatureName(cid), [TAG_QUEUESIZE] = self.queue:getSize() }
					msg = self:parseMessage(msg, parseInfo)
					self:say(msg)
				end
			end
		end
	end

	-- Simply calls the underlying unGreet function.
	function NpcHandler:onFarewell(cid)
		self:unGreet(cid)
	end

	-- Should be called on this npc's focus if the distance to focus is greater then talkRadius.
	function NpcHandler:onWalkAway(cid)
		if(self:isFocused(cid)) then
			local callback = self:getCallback(CALLBACK_CREATURE_DISAPPEAR)
			if(callback == nil or callback(cid)) then
				if(self:processModuleCallback(CALLBACK_CREATURE_DISAPPEAR, cid)) then
					if(self.queue == nil or not self.queue:greetNext()) then
						local msg = self:getMessage(MESSAGE_WALKAWAY)
						local parseInfo = { [TAG_PLAYERNAME] = getPlayerName(cid) or -1 }
						msg = self:parseMessage(msg, parseInfo)

						self:say(msg, cid)
						self:releaseFocus(cid)
						self:say(msg)
					end
				end
			end
		end
	end

	-- Returns true if cid is within the talkRadius of this npc.
	function NpcHandler:isInRange(cid)
		if not isPlayer(cid) then
			return false
		end

		local distance = getNpcDistanceTo(cid) or -1
		return distance ~= -1 and distance <= self.talkRadius
	end

	-- Resets the npc into it's initial state (in regard of the keyrodhandler).
	--	All modules are also receiving a reset call through their callbackOnModuleReset function.
	function NpcHandler:resetNpc()
		if(self:processModuleCallback(CALLBACK_MODULE_RESET)) then
			self.keywordHandler:reset()
		end
	end

	-- Makes the npc represented by this instance of NpcHandler say something.
	--	This implements the currently set type of talkdelay.
	function NpcHandler:say(message, focus, delay)
		local delay = delay or 0
		if(NPCHANDLER_TALKDELAY == TALKDELAY_NONE and delay <= 0) then
			if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
				selfSay(message, focus)
			else
				selfSay(message)
			end

			return
		end

		-- TODO: Add an event handling method for delayed messages
		table.insert(self.talkDelay, {
			cid = focus,
			message = message,
			time = os.mtime() + (delay <= 0 and self.talkDelayTime or delay),
			start = os.time()
		})
	end
end


PLEASE HELP ME IM USING TFS CRYING DAMSON 0.3.6
 
Last edited:
1213004 is the only way

and how can i fix npcs for normal mystic spirit? i got premium, but whenever i download a tfs 0.4 and convert the map it says FATAL Unable to load otbm file blablabla xD,
Thats why i use mystic spirit how can i fix this that npcs just talk in NPC channel, ive searched everywhere tried everything and couldnt fix it.. i tried otland.net / google.com and otfans.net T_T nothing that actually works or is compatible XD

Code:
-- Advanced NPC System (Created by Jiddo),
-- Modified by Talaturen.

if(NpcHandler == nil) then
	-- Constant talkdelay behaviors.
	TALKDELAY_NONE = 0 -- No talkdelay. Npc will reply immedeatly.
	TALKDELAY_ONTHINK = 1 -- Talkdelay handled through the onThink callback function. (Default)
	TALKDELAY_EVENT = 2 -- Not yet implemented

	-- Currently applied talkdelay behavior. TALKDELAY_ONTHINK is default.
	NPCHANDLER_TALKDELAY = TALKDELAY_ONTHINK

	-- Constant conversation behaviors.
	CONVERSATION_DEFAULT = 0 -- Conversation through default window, like it was before 8.2 update.
	CONVERSATION_PRIVATE = 1 -- Conversation through NPCs chat window, as of 8.2 update. (Default)
		--Small Note: Private conversations also means the NPC will use multi-focus system.

	-- Currently applied conversation behavior. CONVERSATION_DEFAULT is default.
	NPCHANDLER_CONVBEHAVIOR = CONVERSATION_PRIVATE

	-- Constant indexes for defining default messages.
	MESSAGE_GREET 			= 1 -- When the player greets the npc.
	MESSAGE_FAREWELL 		= 2 -- When the player unGreets the npc.
	MESSAGE_BUY 			= 3 -- When the npc asks the player if he wants to buy something.
	MESSAGE_ONBUY 			= 4 -- When the player successfully buys something via talk.
	MESSAGE_BOUGHT			= 5 -- When the player bought something through the shop window.
	MESSAGE_SELL 			= 6 -- When the npc asks the player if he wants to sell something.
	MESSAGE_ONSELL 			= 7 -- When the player successfully sells something via talk.
	MESSAGE_SOLD			= 8 -- When the player sold something through the shop window.
	MESSAGE_MISSINGMONEY	= 9 -- When the player does not have enough money.
	MESSAGE_NEEDMONEY		= 10 -- Same as above, used for shop window.
	MESSAGE_MISSINGITEM		= 11 -- When the player is trying to sell an item he does not have.
	MESSAGE_NEEDITEM		= 12 -- Same as above, used for shop window.
	MESSAGE_NEEDSPACE 		= 13 -- When the player don't have any space to buy an item
	MESSAGE_NEEDMORESPACE	= 14 -- When the player has some space to buy an item, but not enough space
	MESSAGE_IDLETIMEOUT		= 15 -- When the player has been idle for longer then idleTime allows.
	MESSAGE_WALKAWAY		= 16 -- When the player walks out of the talkRadius of the npc.
	MESSAGE_DECLINE			= 17 -- When the player says no to something.
	MESSAGE_SENDTRADE		= 18 -- When the npc sends the trade window to the player
	MESSAGE_NOSHOP			= 19 -- When the npc's shop is requested but he doesn't have any
	MESSAGE_ONCLOSESHOP		= 20 -- When the player closes the npc's shop window
	MESSAGE_ALREADYFOCUSED	= 21 -- When the player already has the focus of this npc.
	MESSAGE_PLACEDINQUEUE	= 22 -- When the player has been placed in the costumer queue.

	-- Constant indexes for callback functions. These are also used for module callback ids.
	CALLBACK_CREATURE_APPEAR 	= 1
	CALLBACK_CREATURE_DISAPPEAR = 2
	CALLBACK_CREATURE_SAY 		= 3
	CALLBACK_ONTHINK 			= 4
	CALLBACK_GREET 				= 5
	CALLBACK_FAREWELL 			= 6
	CALLBACK_MESSAGE_DEFAULT 	= 7
	CALLBACK_PLAYER_ENDTRADE 	= 8
	CALLBACK_PLAYER_CLOSECHANNEL= 9
	CALLBACK_ONBUY				= 10
	CALLBACK_ONSELL				= 11

	-- Addidional module callback ids
	CALLBACK_MODULE_INIT		= 12
	CALLBACK_MODULE_RESET		= 13

	-- Constant strings defining the keywords to replace in the default messages.
	TAG_PLAYERNAME = '|PLAYERNAME|'
	TAG_ITEMCOUNT = '|ITEMCOUNT|'
	TAG_TOTALCOST = '|TOTALCOST|'
	TAG_ITEMNAME = '|ITEMNAME|'
	TAG_QUEUESIZE = '|QUEUESIZE|'

	NpcHandler = {
		keywordHandler = nil,
		focuses = nil,
		talkStart = nil,
		idleTime = 90,
		talkRadius = 4,
		talkDelayTime = 1, -- Seconds to delay outgoing messages.
		queue = nil,
		talkDelay = nil,
		callbackFunctions = nil,
		modules = nil,
		shopItems = nil, -- They must be here since ShopModule uses "static" functions
		messages = {
			-- These are the default replies of all npcs. They can/should be changed individually for each npc.
			[MESSAGE_GREET] 			= 'Welcome, |PLAYERNAME|! I have been expecting you.',
			[MESSAGE_FAREWELL] 			= 'Good bye, |PLAYERNAME|!',
			[MESSAGE_BUY] 				= 'Do you want to buy |ITEMCOUNT| |ITEMNAME| for |TOTALCOST| gold coins?',
			[MESSAGE_ONBUY] 			= 'It was a pleasure doing business with you.',
			[MESSAGE_BOUGHT] 			= 'Bought |ITEMCOUNT|x |ITEMNAME| for |TOTALCOST| gold.',
			[MESSAGE_SELL] 				= 'Do you want to sell |ITEMCOUNT| |ITEMNAME| for |TOTALCOST| gold coins?',
			[MESSAGE_ONSELL] 			= 'Thank you for this |ITEMNAME|, |PLAYERNAME| gold.',
			[MESSAGE_SOLD]	 			= 'Sold |ITEMCOUNT|x |ITEMNAME| for |TOTALCOST| gold.',
			[MESSAGE_MISSINGMONEY]		= 'Sorry, you don\'t have enough money.',
			[MESSAGE_NEEDMONEY] 		= 'You do not have enough money.',
			[MESSAGE_MISSINGITEM] 		= 'You don\'t even have that item, |PLAYERNAME|!',
			[MESSAGE_NEEDITEM]	 		= 'You do not have this object.',
			[MESSAGE_NEEDSPACE]			= 'You do not have enough capacity.',
			[MESSAGE_NEEDMORESPACE]		= 'You do not have enough capacity for all items.',
			[MESSAGE_IDLETIMEOUT] 		= 'Next, please!',
			[MESSAGE_WALKAWAY] 			= 'How rude!',
			[MESSAGE_DECLINE]			= 'Not good enough, is it... ?',
			[MESSAGE_SENDTRADE]			= 'Here\'s my offer, |PLAYERNAME|. Don\'t you like it?',
			[MESSAGE_NOSHOP]			= 'Sorry, I\'m not offering anything.',
			[MESSAGE_ONCLOSESHOP]		= 'Thank you, come back when you want something more.',
			[MESSAGE_ALREADYFOCUSED]	= '|PLAYERNAME|! I am already talking to you...',
			[MESSAGE_PLACEDINQUEUE] 	= '|PLAYERNAME|, please wait for your turn. There are |QUEUESIZE| customers before you.'
		}
	}

	-- Creates a new NpcHandler with an empty callbackFunction stack.
	function NpcHandler:new(keywordHandler)
		local obj = {}
		obj.callbackFunctions = {}
		obj.modules = {}
		if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
			obj.focuses = {}
			obj.talkStart = {}
		else
			obj.queue = Queue:new(obj)
			obj.focuses = 0
			obj.talkStart = 0
		end
		obj.talkDelay = {}
		obj.keywordHandler = keywordHandler
		obj.messages = {}
		obj.shopItems = {}

		setmetatable(obj.messages, self.messages)
		self.messages.__index = self.messages

		setmetatable(obj, self)
		self.__index = self
		return obj
	end

	-- Re-defines the maximum idle time allowed for a player when talking to this npc.
	function NpcHandler:setMaxIdleTime(newTime)
		self.idleTime = newTime
	end

	-- Attackes a new keyword handler to this npchandler
	function NpcHandler:setKeywordHandler(newHandler)
		self.keywordHandler = newHandler
	end

	-- Function used to change the focus of this npc.
	function NpcHandler:addFocus(newFocus)
		if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
			if(self:isFocused(newFocus)) then
				return
			end

			table.insert(self.focuses, newFocus)
		else
			self.focuses = newFocus
		end
		self:updateFocus()
	end
	NpcHandler.changeFocus = NpcHandler.addFocus --"changeFocus" looks better for CONVERSATION_DEFAULT

	-- Function used to verify if npc is focused to certain player
	function NpcHandler:isFocused(focus)
		if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
			for k,v in pairs(self.focuses) do
				if v == focus then
					return true
				end
			end
			return false
		end
		return (self.focuses == focus)
	end

	-- This function should be called on each onThink and makes sure the npc faces the player it is talking to.
	--	Should also be called whenever a new player is focused.
	function NpcHandler:updateFocus()
		if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
			for pos, focus in pairs(self.focuses) do
				if(focus ~= nil) then
					doNpcSetCreatureFocus(focus)
					return
				end
			end
			doNpcSetCreatureFocus(0)
		else
			doNpcSetCreatureFocus(self.focuses)
		end
	end

	-- Used when the npc should un-focus the player.
	function NpcHandler:releaseFocus(focus)
		if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
			if(not self:isFocused(focus)) then
				return
			end

			local pos = nil
			for k,v in pairs(self.focuses) do
				if v == focus then
					pos = k
				end
			end
			table.remove(self.focuses, pos)
			self.talkStart[focus] = nil

			if isPlayer(focus) then
				closeShopWindow(focus) --Even if it can not exist, we need to prevent it.
			end
			self:updateFocus()
		else
			if isPlayer(focus) then
				closeShopWindow(focus)
			end
			self:changeFocus(0)
		end
	end

	-- Returns the callback function with the specified id or nil if no such callback function exists.
	function NpcHandler:getCallback(id)
		local ret = nil
		if(self.callbackFunctions ~= nil) then
			ret = self.callbackFunctions[id]
		end
		return ret
	end

	-- Changes the callback function for the given id to callback.
	function NpcHandler:setCallback(id, callback)
		if(self.callbackFunctions ~= nil) then
			self.callbackFunctions[id] = callback
		end
	end

	-- Adds a module to this npchandler and inits it.
	function NpcHandler:addModule(module)
		if(self.modules ~= nil) then
			table.insert(self.modules, module)
			module:init(self)
		end
	end

	-- Calls the callback function represented by id for all modules added to this npchandler with the given arguments.
	function NpcHandler:processModuleCallback(id, ...)
		local ret = true
		for i, module in pairs(self.modules) do
			local tmpRet = true
			if(id == CALLBACK_CREATURE_APPEAR and module.callbackOnCreatureAppear ~= nil) then
				tmpRet = module:callbackOnCreatureAppear(...)
			elseif(id == CALLBACK_CREATURE_DISAPPEAR and module.callbackOnCreatureDisappear ~= nil) then
				tmpRet = module:callbackOnCreatureDisappear(...)
			elseif(id == CALLBACK_CREATURE_SAY and module.callbackOnCreatureSay ~= nil) then
				tmpRet = module:callbackOnCreatureSay(...)
			elseif(id == CALLBACK_PLAYER_ENDTRADE and module.callbackOnPlayerEndTrade ~= nil) then
				tmpRet = module:callbackOnPlayerEndTrade(...)
			elseif(id == CALLBACK_PLAYER_CLOSECHANNEL and module.callbackOnPlayerCloseChannel ~= nil) then
				tmpRet = module:callbackOnPlayerCloseChannel(...)
			elseif(id == CALLBACK_ONBUY and module.callbackOnBuy ~= nil) then
				tmpRet = module:callbackOnBuy(...)
			elseif(id == CALLBACK_ONSELL and module.callbackOnSell ~= nil) then
				tmpRet = module:callbackOnSell(...)
			elseif(id == CALLBACK_ONTHINK and module.callbackOnThink ~= nil) then
				tmpRet = module:callbackOnThink(...)
			elseif(id == CALLBACK_GREET and module.callbackOnGreet ~= nil) then
				tmpRet = module:callbackOnGreet(...)
			elseif(id == CALLBACK_FAREWELL and module.callbackOnFarewell ~= nil) then
				tmpRet = module:callbackOnFarewell(...)
			elseif(id == CALLBACK_MESSAGE_DEFAULT and module.callbackOnMessageDefault ~= nil) then
				tmpRet = module:callbackOnMessageDefault(...)
			elseif(id == CALLBACK_MODULE_RESET and module.callbackOnModuleReset ~= nil) then
				tmpRet = module:callbackOnModuleReset(...)
			end
			if(not tmpRet) then
				ret = false
				break
			end
		end
		return ret
	end

	-- Returns the message represented by id.
	function NpcHandler:getMessage(id)
		local ret = nil
		if(self.messages ~= nil) then
			ret = self.messages[id]
		end
		return ret
	end

	-- Changes the default response message with the specified id to newMessage.
	function NpcHandler:setMessage(id, newMessage)
		if(self.messages ~= nil) then
			self.messages[id] = newMessage
		end
	end

	-- Translates all message tags found in msg using parseInfo
	function NpcHandler:parseMessage(msg, parseInfo)
		local ret = msg
		for search, replace in pairs(parseInfo) do
			ret = string.gsub(ret, search, replace)
		end
		return ret
	end

	-- Makes sure the npc un-focuses the currently focused player
	function NpcHandler:unGreet(cid)
		if(not self:isFocused(cid)) then
			return
		end

		local callback = self:getCallback(CALLBACK_FAREWELL)
		if(callback == nil or callback()) then
			if(self:processModuleCallback(CALLBACK_FAREWELL)) then
				if(self.queue == nil or not self.queue:greetNext()) then
					local msg = self:getMessage(MESSAGE_FAREWELL)
					local parseInfo = { [TAG_PLAYERNAME] = getPlayerName(cid) }
					msg = self:parseMessage(msg, parseInfo)
					self:say(msg, cid, true)
					self:releaseFocus(cid)
				end
			end
		end
	end

	-- Greets a new player.
	function NpcHandler:greet(cid)
		if(cid ~= 0) then
			local callback = self:getCallback(CALLBACK_GREET)
			if(callback == nil or callback(cid)) then
				if(self:processModuleCallback(CALLBACK_GREET, cid)) then
					local msg = self:getMessage(MESSAGE_GREET)
					local parseInfo = { [TAG_PLAYERNAME] = getCreatureName(cid) }
					msg = self:parseMessage(msg, parseInfo)
					self:say(msg, cid, true)
				else
					return
				end
			else
				return
			end
		end
		self:addFocus(cid)
	end

	-- Handles onCreatureAppear events. If you with to handle this yourself, please use the CALLBACK_CREATURE_APPEAR callback.
	function NpcHandler:onCreatureAppear(cid)
		local callback = self:getCallback(CALLBACK_CREATURE_APPEAR)
		if(callback == nil or callback(cid)) then
			if(self:processModuleCallback(CALLBACK_CREATURE_APPEAR, cid)) then
				--
			end
		end
	end

	-- Handles onCreatureDisappear events. If you with to handle this yourself, please use the CALLBACK_CREATURE_DISAPPEAR callback.
	function NpcHandler:onCreatureDisappear(cid)
		local callback = self:getCallback(CALLBACK_CREATURE_DISAPPEAR)
		if(callback == nil or callback(cid)) then
			if(self:processModuleCallback(CALLBACK_CREATURE_DISAPPEAR, cid)) then
				if(self:isFocused(cid)) then
					self:unGreet(cid)
				end
			end
		end
	end

	-- Handles onCreatureSay events. If you with to handle this yourself, please use the CALLBACK_CREATURE_SAY callback.
	function NpcHandler:onCreatureSay(cid, msgtype, msg)
		local callback = self:getCallback(CALLBACK_CREATURE_SAY)
		if(callback == nil or callback(cid, msgtype, msg)) then
			if(self:processModuleCallback(CALLBACK_CREATURE_SAY, cid, msgtype, msg)) then
				if(not self:isInRange(cid)) then
					return
				end

				if(self.keywordHandler ~= nil) then
					if(self:isFocused(cid) and (msgtype == TALKTYPE_PRIVATE_PN or NPCHANDLER_CONVBEHAVIOR == CONVERSATION_DEFAULT) or (not self:isFocused(cid))) then
						local ret = self.keywordHandler:processMessage(cid, msg)
						if(not ret) then
							local callback = self:getCallback(CALLBACK_MESSAGE_DEFAULT)
							if(callback ~= nil and callback(cid, msgtype, msg)) then
								if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
									self.talkStart[cid] = os.time()
								else
									self.talkStart = os.time()
								end
							end
						else
							if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
								self.talkStart[cid] = os.time()
							else
								self.talkStart = os.time()
							end
						end
					end
				end
			end
		end
	end

	-- Handles onPlayerEndTrade events. If you wish to handle this yourself, use the CALLBACK_PLAYER_ENDTRADE callback.
	function NpcHandler:onPlayerEndTrade(cid)
		local callback = self:getCallback(CALLBACK_PLAYER_ENDTRADE)
		if(callback == nil or callback(cid)) then
			if(self:processModuleCallback(CALLBACK_PLAYER_ENDTRADE, cid, msgtype, msg)) then
				if(self:isFocused(cid)) then
					local parseInfo = { [TAG_PLAYERNAME] = getPlayerName(cid) }
					local msg = self:parseMessage(self:getMessage(MESSAGE_ONCLOSESHOP), parseInfo)
					self:say(msg, cid)
				end
			end
		end
	end

	-- Handles onPlayerCloseChannel events. If you wish to handle this yourself, use the CALLBACK_PLAYER_CLOSECHANNEL callback.
	function NpcHandler:onPlayerCloseChannel(cid)
		local callback = self:getCallback(CALLBACK_PLAYER_CLOSECHANNEL)
		if(callback == nil or callback(cid)) then
			if(self:processModuleCallback(CALLBACK_PLAYER_CLOSECHANNEL, cid, msgtype, msg)) then
				if(self:isFocused(cid)) then
					self:unGreet(cid)
				end
			end
		end
	end

	-- Handles onBuy events. If you wish to handle this yourself, use the CALLBACK_ONBUY callback.
	function NpcHandler:onBuy(cid, itemid, subType, amount)
		local callback = self:getCallback(CALLBACK_ONBUY)
		if(callback == nil or callback(cid, itemid, subType, amount)) then
			if(self:processModuleCallback(CALLBACK_ONBUY, cid, itemid, subType, amount)) then
				--
			end
		end
	end

	-- Handles onSell events. If you wish to handle this yourself, use the CALLBACK_ONSELL callback.
	function NpcHandler:onSell(cid, itemid, subType, amount)
		local callback = self:getCallback(CALLBACK_ONSELL)
		if(callback == nil or callback(cid, itemid, subType, amount)) then
			if(self:processModuleCallback(CALLBACK_ONSELL, cid, itemid, subType, amount)) then
				--
			end
		end
	end

	-- Handles onThink events. If you wish to handle this yourself, please use the CALLBACK_ONTHINK callback.
	function NpcHandler:onThink()
		local callback = self:getCallback(CALLBACK_ONTHINK)
		if(callback == nil or callback()) then
			if(NPCHANDLER_TALKDELAY == TALKDELAY_ONTHINK) then
				if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
					for cid, talkDelay in pairs(self.talkDelay) do
						if(talkDelay.time ~= nil and talkDelay.message ~= nil and os.time() >= talkDelay.time) then
							selfSay(talkDelay.message, cid, talkDelay.publicize and TRUE or FALSE)
							self.talkDelay[cid] = nil
						end
					end
				elseif(self.talkDelay.time ~= nil and self.talkDelay.message ~= nil and os.time() >= self.talkDelay.time) then
					selfSay(self.talkDelay.message)
					self.talkDelay.time = nil
					self.talkDelay.message = nil
				end
			end

			if(self:processModuleCallback(CALLBACK_ONTHINK)) then
				if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
					for pos, focus in pairs(self.focuses) do
						if(focus ~= nil) then
							if(not self:isInRange(focus)) then
								self:onWalkAway(focus)
							elseif((os.time() - self.talkStart[focus]) > self.idleTime) then
								self:unGreet(focus)
							else
								self:updateFocus()
							end
						end
					end
				elseif(self.focuses ~= 0) then
					if(not self:isInRange(self.focuses)) then
						self:onWalkAway(self.focuses)
					elseif(os.time()-self.talkStart > self.idleTime) then
						self:unGreet(self.focuses)
					else
						self:updateFocus()
					end
				end
			end
		end
	end

	-- Tries to greet the player with the given cid.
	function NpcHandler:onGreet(cid)
		if(self:isInRange(cid)) then
			if(NPCHANDLER_CONVBEHAVIOR == CONVERSATION_PRIVATE) then
				if(not self:isFocused(cid)) then
					self:greet(cid)
					return
				end
			elseif(NPCHANDLER_CONVBEHAVIOR == CONVERSATION_DEFAULT) then
				if(self.focuses == 0) then
					self:greet(cid)
				elseif(self.focuses == cid) then
					local msg = self:getMessage(MESSAGE_ALREADYFOCUSED)
					local parseInfo = { [TAG_PLAYERNAME] = getCreatureName(cid) }
					msg = self:parseMessage(msg, parseInfo)
					self:say(msg)
				else
					if(not self.queue:isInQueue(cid)) then
						self.queue:push(cid)
					end
					local msg = self:getMessage(MESSAGE_PLACEDINQUEUE)
					local parseInfo = { [TAG_PLAYERNAME] = getCreatureName(cid), [TAG_QUEUESIZE] = self.queue:getSize() }
					msg = self:parseMessage(msg, parseInfo)
					self:say(msg)
				end
			end
		end
	end

	-- Simply calls the underlying unGreet function.
	function NpcHandler:onFarewell(cid)
		self:unGreet(cid)
	end

	-- Should be called on this npc's focus if the distance to focus is greater then talkRadius.
	function NpcHandler:onWalkAway(cid)
		if(self:isFocused(cid)) then
			local callback = self:getCallback(CALLBACK_CREATURE_DISAPPEAR)
			if(callback == nil or callback()) then
				if(self:processModuleCallback(CALLBACK_CREATURE_DISAPPEAR, cid)) then
					if(self.queue == nil or not self.queue:greetNext()) then
						local msg = self:getMessage(MESSAGE_WALKAWAY)
						local playerName = getPlayerName(cid)
						if not playerName then
							playerName = -1
						end

						local parseInfo = { [TAG_PLAYERNAME] = playerName }
						msg = self:parseMessage(msg, parseInfo)
						self:say(msg, cid, true)
						self:releaseFocus(cid)
					end
				end
			end
		end
	end

	-- Returns true if cid is within the talkRadius of this npc.
	function NpcHandler:isInRange(cid)
		if not isPlayer(cid) then
			return false
		end

		local distance = getDistanceTo(cid) or -1
		if distance == -1 then
			return false
		end

		return (distance <= self.talkRadius)
	end

	-- Resets the npc into it's initial state (in regard of the keyrodhandler).
	--	All modules are also receiving a reset call through their callbackOnModuleReset function.
	function NpcHandler:resetNpc()
		if(self:processModuleCallback(CALLBACK_MODULE_RESET)) then
			self.keywordHandler:reset()
		end
	end

	-- Makes the npc represented by this instance of NpcHandler say something.
	--	This implements the currently set type of talkdelay.
	--	shallDelay is a boolean value. If it is false, the message is not delayed. Default value is true.
	function NpcHandler:say(message, focus, publicize, shallDelay)
		if(shallDelay == nil) then
			shallDelay = true
		end
		if(NPCHANDLER_TALKDELAY == TALKDELAY_NONE or shallDelay == false) then
			if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
				selfSay(message, focus, publicize and TRUE or FALSE)
				return
			else
				selfSay(message)
				return
			end
		end
		if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
			self.talkDelay[focus] = {
				message = message,
				time = os.time() + self.talkDelayTime,
				publicize = publicize
			}
		else
			self.talkDelay = {
				message = message,
				time = os.time() + self.talkDelayTime
			}
		end
	end
end
 
i think this system is kinda weird, cause when i do talk to bank npc.. he greets me on default.. and when i say deposit / 100 / yes its in npc channel,
But other NPCS are totally not working on the NPC channel T_T ,

bank.lua
Code:
local config = {
	transferDisabledVocations = {0} -- disable non vocation characters
}
 
local talkState = {}
local count = {}
local transfer = {}
 
local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)
NpcSystem.parseParameters(npcHandler)
 
function onCreatureAppear(cid)			npcHandler:onCreatureAppear(cid) end
function onCreatureDisappear(cid)		npcHandler:onCreatureDisappear(cid) end
function onCreatureSay(cid, type, msg)		npcHandler:onCreatureSay(cid, type, msg) end
function onThink()				npcHandler:onThink() end
 
if(not getPlayerBalance) then
	getPlayerBalance = function(cid)
		local result = db.getResult("SELECT `balance` FROM `players` WHERE `id` = " .. getPlayerGUID(cid))
		if(result:getID() == -1) then
			return false
		end
 
		local value = tonumber(result:getDataString("balance"))
		result:free()
		return value
	end
 
	doPlayerSetBalance = function(cid, balance)
		db.executeQuery("UPDATE `players` SET `balance` = " .. balance .. " WHERE `id` = " .. getPlayerGUID(cid))
		return true
	end
 
	doPlayerWithdrawMoney = function(cid, amount)
		local balance = getPlayerBalance(cid)
		if(amount > balance or not doPlayerAddMoney(cid, amount)) then
			return false
		end
 
		doPlayerSetBalance(cid, balance - amount)
		return true
	end
 
	doPlayerDepositMoney = function(cid, amount)
		if(not doPlayerRemoveMoney(cid, amount)) then
			return false
		end
 
		doPlayerSetBalance(cid, getPlayerBalance(cid) + amount)
		return true
	end
 
	doPlayerTransferMoneyTo = function(cid, target, amount)
		local balance = getPlayerBalance(cid)
		if(amount > balance) then
			return false
		end
 
		local tid = getPlayerByName(target)
		if(tid > 0) then
			doPlayerSetBalance(tid, getPlayerBalance(tid) + amount)
		else
			if(playerExists(target) == FALSE) then
				return false
			end
 
			db.executeQuery("UPDATE `player_storage` SET `value` = `value` + '" .. amount .. "' WHERE `player_id` = (SELECT `id` FROM `players` WHERE `name` = '" .. escapeString(player) .. "') AND `key` = '" .. balance_storage .. "'")
		end
 
		doPlayerSetBalance(cid, getPlayerBalance(cid) - amount)
		return true
	end
end
 
local function getPlayerVocationByName(name)
	local result = db.getResult("SELECT `vocation` FROM `players` WHERE `name` = " .. db.escapeString(name))
	if(result:getID() == -1) then
		return false
	end
 
	local value = result:getDataString("vocation")
	result:free()
	return value
end
 
local function isValidMoney(money)
	return (isNumber(money) and money > 0 and money < 400096)
end
 
local function getCount(string)
	local b, e = string:find("%d+")
	local money = b and e and tonumber(string:sub(b, e)) or -1
	if(isValidMoney(money)) then
		return money
	end
	return -1
end
 
function greetCallback(cid)
	talkState[cid], count[cid], transfer[cid] = 0, nil, nil
	return true
end
 
function creatureSayCallback(cid, type, msg)
 
	if(not npcHandler:isFocused(cid)) then
		return false
	end
 
---------------------------- help ------------------------
	if msgcontains(msg, 'advanced') then
		if isInArray(config.transferDisabledVocations, getPlayerVocation(cid)) then
			selfSay("Once you are on the Tibian mainland, you can access new functions of your bank account, such as transferring money to other players safely or taking part in house auctions.", cid)
		else
			selfSay("Renting a house has never been this easy. Simply make a bid for an auction. We will check immediately if you have enough money.", cid)
		end
		talkState[cid] = 0
	elseif msgcontains(msg, 'help') or msgcontains(msg, 'functions') then
		selfSay("You can check the {balance} of your bank account, {deposit} money or {withdraw} it. You can also {transfer} money to other characters, provided that they have a vocation.", cid)
		talkState[cid] = 0
	elseif msgcontains(msg, 'bank') then
		npcHandler:say("We can change money for you. You can also access your bank account.", cid)
		talkState[cid] = 0
	elseif msgcontains(msg, 'job') then
		npcHandler:say("I work in this bank. I can change money for you and help you with your bank account.", cid)
		talkState[cid] = 0
---------------------------- balance ---------------------
	elseif msgcontains(msg, 'balance') then
		selfSay("Your account balance is " .. getPlayerBalance(cid) .. " gold.", cid)
		talkState[cid] = 0
---------------------------- deposit ---------------------
	elseif msgcontains(msg, 'deposit all') and getPlayerMoney(cid) > 0 then
		count[cid] = getPlayerMoney(cid)
		if not isValidMoney(count[cid]) then
			selfSay("Sorry, but you can't deposit that much.", cid)
			talkState[cid] = 0
			return false
		end
 
		if count[cid] < 1 then
			selfSay("You don't have any money to deposit in you inventory..", cid)
			talkState[cid] = 0
		else
			selfSay("Would you really like to deposit " .. count[cid] .. " gold?", cid)
			talkState[cid] = 2
		end
	elseif msgcontains(msg, 'deposit') then
		selfSay("Please tell me how much gold it is you would like to deposit.", cid)
		talkState[cid] = 1
	elseif talkState[cid] == 1 then
		count[cid] = getCount(msg)
		if isValidMoney(count[cid]) then
			selfSay("Would you really like to deposit " .. count[cid] .. " gold?", cid)
			talkState[cid] = 2
		else
			selfSay("Is isnt valid amount of gold to deposit.", cid)
			talkState[cid] = 0
		end
	elseif talkState[cid] == 2 then
		if msgcontains(msg, 'yes') then
			if not doPlayerDepositMoney(cid, count[cid]) then
				selfSay("You don\'t have enough gold.", cid)
			else
				selfSay("Alright, we have added the amount of " .. count[cid] .. " gold to your balance. You can withdraw your money anytime you want to. Your account balance is " .. getPlayerBalance(cid) .. ".", cid)
			end
		elseif msgcontains(msg, 'no') then
			selfSay("As you wish. Is there something else I can do for you?", cid)
		end
		talkState[cid] = 0
---------------------------- withdraw --------------------
	elseif msgcontains(msg, 'withdraw') then
		selfSay("Please tell me how much gold you would like to withdraw.", cid)
		talkState[cid] = 6
	elseif talkState[cid] == 6 then
		count[cid] = getCount(msg)
		if isValidMoney(count[cid]) then
			selfSay("Are you sure you wish to withdraw " .. count[cid] .. " gold from your bank account?", cid)
			talkState[cid] = 7
		else
			selfSay("Is isnt valid amount of gold to withdraw.", cid)
			talkState[cid] = 0
		end
	elseif talkState[cid] == 7 then
		if msgcontains(msg, 'yes') then
			if not doPlayerWithdrawMoney(cid, count[cid]) then
				selfSay("There is not enough gold on your account. Your account balance is " .. getPlayerBalance(cid) .. ". Please tell me the amount of gold coins you would like to withdraw.", cid)
				talkState[cid] = 0
			else
				selfSay("Here you are, " .. count[cid] .. " gold. Please let me know if there is something else I can do for you.", cid)
				talkState[cid] = 0
			end
		elseif msgcontains(msg, 'no') then
			selfSay("As you wish. Is there something else I can do for you?", cid)
			talkState[cid] = 0
		end
---------------------------- transfer --------------------
	elseif msgcontains(msg, 'transfer') then
		selfSay("Please tell me the amount of gold you would like to transfer.", cid)
		talkState[cid] = 11
	elseif talkState[cid] == 11 then
		count[cid] = getCount(msg)
		if getPlayerBalance(cid) < count[cid] then
			selfSay("You dont have enough money on your bank account.", cid)
			talkState[cid] = 0
			return true
		end
 
		if isValidMoney(count[cid]) then
			selfSay("Who would you like transfer " .. count[cid] .. " gold to?", cid)
			talkState[cid] = 12
		else
			selfSay("Is isnt valid amount of gold to transfer.", cid)
			talkState[cid] = 0
		end
	elseif talkState[cid] == 12 then
		transfer[cid] = msg
 
		if getCreatureName(cid) == transfer[cid] then
			selfSay("Ekhm, You want transfer money to yourself? Its impossible!", cid)
			talkState[cid] = 0
			return true
		end
 
		if isInArray(config.transferDisabledVocations, getPlayerVocation(cid)) then
			selfSay("Your vocation cannot transfer money.", cid)
			talkState[cid] = 0
		end
 
		if playerExists(transfer[cid]) then
			selfSay("So you would like to transfer " .. count[cid] .. " gold to \"" .. transfer[cid] .. "\" ?", cid)
			talkState[cid] = 13
		else
			selfSay("Player with name \"" .. transfer[cid] .. "\" doesnt exist.", cid)
			talkState[cid] = 0
		end
	elseif talkState[cid] == 13 then
		if msgcontains(msg, 'yes') then
			local targetVocation = getPlayerVocationByName(transfer[cid])
			if not targetVocation or isInArray(config.transferDisabledVocations, targetVocation) or not doPlayerTransferMoneyTo(cid, transfer[cid], count[cid]) then
				selfSay("This player does not exist on this world or have no vocation.", cid)
			else
				selfSay("You have transferred " .. count[cid] .. " gold to \"" .. transfer[cid] .."\".", cid)
				transfer[cid] = nil
			end
		elseif msgcontains(msg, 'no') then
			selfSay("As you wish. Is there something else I can do for you?", cid)
		end
		talkState[cid] = 0
---------------------------- money exchange --------------
	elseif msgcontains(msg, 'change gold') then
		npcHandler:say("How many platinum coins would you like to get?", cid)
		talkState[cid] = 14
	elseif talkState[cid] == 14 then
		if getCount(msg) == -1 or getCount(msg) == 0 then
			npcHandler:say("Hmm, can I help you with something else?", cid)
			talkState[cid] = 0
		else
			count[cid] = getCount(msg)
			npcHandler:say("So you would like me to change " .. count[cid] * 100 .. " of your gold coins into " .. count[cid] .. " platinum coins?", cid)
			talkState[cid] = 15
		end
	elseif talkState[cid] == 15 then
		if msgcontains(msg, 'yes') then
			if doPlayerRemoveItem(cid, 2148, count[cid] * 100) then
				doPlayerAddItem(cid, 2152, count[cid])
				npcHandler:say("Here you are.", cid)
			else
				npcHandler:say("Sorry, you do not have enough gold coins.", cid)
			end
		else
			npcHandler:say("Well, can I help you with something else?", cid)
		end
		talkState[cid] = 0
	elseif msgcontains(msg, 'change platinum') then
		npcHandler:say("Would you like to change your platinum coins into gold or crystal?", cid)
		talkState[cid] = 16
	elseif talkState[cid] == 16 then
		if msgcontains(msg, 'gold') then
			npcHandler:say("How many platinum coins would you like to change into gold?", cid)
			talkState[cid] = 17
		elseif msgcontains(msg, 'crystal') then
			npcHandler:say("How many crystal coins would you like to get?", cid)
			talkState[cid] = 19
		else
			npcHandler:say("Well, can I help you with something else?", cid)
			talkState[cid] = 0
		end
	elseif talkState[cid] == 17 then
		if getCount(msg) == -1 or getCount(msg) == 0 then
			npcHandler:say("Hmm, can I help you with something else?", cid)
			talkState[cid] = 0
		else
			count[cid] = getCount(msg)
			npcHandler:say("So you would like me to change " .. count[cid] .. " of your platinum coins into " .. count[cid] * 100 .. " gold coins for you?", cid)
			talkState[cid] = 18
		end
	elseif talkState[cid] == 18 then
		if msgcontains(msg, 'yes') then
			if doPlayerRemoveItem(cid, 2152, count[cid]) then
				npcHandler:say("Here you are.", cid)
				doPlayerAddItem(cid, 2148, count[cid] * 100)
			else
				npcHandler:say("Sorry, you do not have enough platinum coins.", cid)
			end
		else
			npcHandler:say("Well, can I help you with something else?", cid)
		end
		talkState[cid] = 0
	elseif talkState[cid] == 19 then
		if getCount(msg) == -1 or getCount(msg) == 0 then
			npcHandler:say("Hmm, can I help you with something else?", cid)
			talkState[cid] = 0
		else
			count[cid] = getCount(msg)
			npcHandler:say("So you would like me to change " .. count[cid] * 100 .. " of your platinum coins into " .. count[cid] .. " crystal coins for you?", cid)
			talkState[cid] = 20
		end
	elseif talkState[cid] == 20 then
		if msgcontains(msg, 'yes') then
			if doPlayerRemoveItem(cid, 2152, count[cid] * 100) then
				npcHandler:say("Here you are.", cid)
				doPlayerAddItem(cid, 2160, count[cid])
			else
				npcHandler:say("Sorry, you do not have enough platinum coins.", cid)
			end
		else
			npcHandler:say("Well, can I help you with something else?", cid)
		end
		talkState[cid] = 0
	elseif msgcontains(msg, 'change crystal') then
		npcHandler:say("How many crystal coins would you like to change into platinum?", cid)
		talkState[cid] = 21
	elseif talkState[cid] == 21 then
		if getCount(msg) == -1 or getCount(msg) == 0 then
			npcHandler:say("Hmm, can I help you with something else?", cid)
			talkState[cid] = 0
		else
			count[cid] = getCount(msg)
			npcHandler:say("So you would like me to change " .. count[cid] .. " of your crystal coins into " .. count[cid] * 100 .. " platinum coins for you?", cid)
			talkState[cid] = 22
		end
	elseif talkState[cid] == 22 then
		if msgcontains(msg, 'yes') then
			if doPlayerRemoveItem(cid, 2160, count[cid]) then
				npcHandler:say("Here you are.", cid)
				doPlayerAddItem(cid, 2152, count[cid] * 100)
			else
				npcHandler:say("Sorry, you do not have enough crystal coins.", cid)
			end
		else
			npcHandler:say("Well, can I help you with something else?", cid)
		end
		talkState[cid] = 0
	elseif msgcontains(msg, 'change') then
		npcHandler:say("There are three different coin types in Tibia: 100 gold coins equal 1 platinum coin, 100 platinum coins equal 1 crystal coin. So if you'd like to change 100 gold into 1 platinum, simply say '{change gold}' and then '1 platinum'.", cid)
		talkState[cid] = 0
	end
 
	return true
end
 
npcHandler:setCallback(CALLBACK_GREET, greetCallback)
npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
npcHandler:addModule(FocusModule:new())

default.lua
Code:
local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)
NpcSystem.parseParameters(npcHandler)
 
function onCreatureAppear(cid)				npcHandler:onCreatureAppear(cid) end
function onCreatureDisappear(cid) 			npcHandler:onCreatureDisappear(cid) end
function onCreatureSay(cid, type, msg)			npcHandler:onCreatureSay(cid, type, msg) end
function onThink()					npcHandler:onThink() end
function onPlayerEndTrade(cid)				npcHandler:onPlayerEndTrade(cid)			end
function onPlayerCloseChannel(cid)			npcHandler:onPlayerCloseChannel(cid)		end

npcHandler:addModule(FocusModule:new())
 
i think copy the right distro and transfer all NPC lib folder to your distro..

and i found a solution.. butt that means that we have to change everything T_T ,

solution NPC channel
Code:
npcHandler:say('How can i help you?', cid)
That means.. we gotta adjust all scripts and we need lua scripts for item npcs.. to make it sellable if you want to use PRIVATE T_T
 
Back
Top