Ir para conteúdo
Banner com Efeitos

Featured Replies

Postado

.Qual servidor ou website você utiliza como base? 

OTX 2 - 0.7

Qual o motivo deste tópico? 

Preciso de ajuda para corrigir o sistema de loja do meu servidor para os npcs dos DJINNS e o RASHID.

Acontece o seguinte, meu servidor é 7.72 mas esta configurado para 7.4.
Fiz toda a quest do Green Djinn, está funcionando normalmente. Porém o sistema da loja não obedece quando mando verificar o Storage da quest completa que é o 1038 = 1.

Eu coloco pra verificar esse storage antes de usar a loja, mas ele ignora, ou as vezes se alguem não tem o Storage ele funciona, mas se chegar alguem que tem o Storage ele libera o npc pra qualquer 1 usar.

Ja tentei varias coisas e não sei resolver, se alguem puder me ajudar. Vou colocar os arquivos do Alesar e a lib dos npcs se puder me dizer como faço pra corrigir.

A unica coisa que preciso é que o player so consiga negociar com o NPC se tiver o Storage 1038 = 1 ... Se não ele fala que nao pode negociar.

Npchandler.lua

Spoiler

-- Advanced NPC System (Created by Jiddo),
-- Modified by TheForgottenServer Team,
-- Modified by The OTX Server 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_DEFAULT

	-- 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_MISSINGITEM		= 10 -- When the player is trying to sell an item he does not have.
	MESSAGE_NEEDMONEY		= 11 -- Same as above, used for shop window.
	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 = 60,
		talkRadius = 3,
		talkDelayTime = 350, -- 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|.',
			[MESSAGE_SOLD]	 	= 'Sold |ITEMCOUNT|x |ITEMNAME| for |TOTALCOST| gold.',
			[MESSAGE_MISSINGMONEY]	= 'Sorry, you don\'t have enough money.',
			[MESSAGE_MISSINGITEM] 	= 'You don\'t even have that item, |PLAYERNAME|!',
			[MESSAGE_NEEDMONEY] 	= 'You do not have enough money.',
			[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.messages = {}

		obj.keywordHandler = keywordHandler
		obj.queue = Queue:new(obj)
		obj.focuses = 0
		obj.talkStart = 0
		obj.callbackFunctions = {}
		obj.modules = {}
		obj.talkDelay = {}
		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((newFocus ~= 0 and not isCreature(newFocus))) then
			return
		end

		self.focuses = newFocus
		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(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(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(self.focuses == focus) then
			self:changeFocus(0)
		end
	end

	-- Internal un-focusing function, beware using!
	function NpcHandler:unsetFocus(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
	
		-- Adds a module to this npchandler and inits it.
	function NpcHandler:addModulealesar(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(...)
			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)
		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)
					msg = self:parseMessage(msg, { [TAG_PLAYERNAME] = getPlayerName(cid) or -1 })

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

	-- Greets a new player.
	function NpcHandler:greet(cid)
		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)
				msg = self:parseMessage(msg, { [TAG_PLAYERNAME] = getCreatureName(cid) })

				self:addFocus(cid)
				self:say(msg)
			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
					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
							self.talkStart = os.time()
						end
					else
						self.talkStart = os.time()
					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)) 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)) 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 or speech.cid == 0) and speech.time ~= nil and speech.message ~= nil) then
					if(os.mtime() >= speech.time) then
						selfSay(speech.message)
						self.talkDelay[i] = nil
					end
				elseif(isCreature(speech.cid) and speech.start ~= nil and speech.time ~= nil and speech.message ~= nil) then
					if(os.mtime() >= speech.time) then
						local talkStart = self.talkStart
						if(speech.force or (self:isFocused(speech.cid) and talkStart == speech.start)) then
							selfSay(speech.message)
						end

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

			if(self:processModuleCallback(CALLBACK_ONTHINK)) then
				if(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(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

	-- 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)
						self:resetNpc(cid)
						self:say(self:parseMessage(msg, { [TAG_PLAYERNAME] = getPlayerName(cid) or -1 }))
						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 = 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(cid)
		if(self:processModuleCallback(CALLBACK_MODULE_RESET)) then
			self.keywordHandler:reset(cid)
		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, force)
		local delay = delay or 0
		if(NPCHANDLER_TALKDELAY == TALKDELAY_NONE or delay <= 0) then
			selfSay(message)
			return
		end
			
		-- TODO: Add an event handling method for delayed messages
		table.insert(self.talkDelay, {
			id = getNpcId(),
			cid = focus,
			message = message,
			time = os.mtime() + (delay and delay or self.talkDelayTime),
			start = os.time(),
			force = force or false
		})
	end
end

 

 

Modules.lua

Spoiler

-- Advanced NPC System (Created by Jiddo),
-- Modified by TheForgottenServer Team,
-- Modified by The OTX Server Team.

if(Modules == nil) then
	-- Constants used to separate buying from selling.
	SHOPMODULE_SELL_ITEM = 1
	SHOPMODULE_BUY_ITEM = 2
	SHOPMODULE_BUY_ITEM_CONTAINER = 3

	-- Constants used for shop mode. Notice: addBuyableItemContainer is working on all modes
	SHOPMODULE_MODE_TALK = 1 -- Old system used before Tibia 8.2: sell/buy item name
	SHOPMODULE_MODE_TRADE = 2 -- Trade window system introduced in Tibia 8.2
	SHOPMODULE_MODE_BOTH = 3 -- Both working at one time

	-- Used in shop mode
	SHOPMODULE_MODE = SHOPMODULE_MODE_TALK

	-- Constants used for outfit giving mode
	OUTFITMODULE_FUNCTION_OLD = { doPlayerAddOutfit, canPlayerWearOutfit } -- lookType usage
	OUTFITMODULE_FUNCTION_NEW = { doPlayerAddOutfitId, canPlayerWearOutfitId } -- OutfitId usage

	-- Used in outfit module
	OUTFITMODULE_FUNCTION = OUTFITMODULE_FUNCTION_NEW
	if(OUTFITMODULE_FUNCTION[1] == nil or OUTFITMODULE_FUNCTION[2] == nil) then
		OUTFITMODULE_FUNCTION = OUTFITMODULE_FUNCTION_OLD
	end

	Modules = {
		parseableModules = {}
	}

	StdModule = {}

	-- These callback function must be called with parameters.npcHandler = npcHandler in the parameters table or they will not work correctly.
	-- Notice: The members of StdModule have not yet been tested. If you find any bugs, please report them to me.
	-- Usage:
		-- keywordHandler:addKeyword({'offer'}, StdModule.say, {npcHandler = npcHandler, text = 'I sell many powerful melee weapons.'})
	function StdModule.say(cid, message, keywords, parameters, node)
		local npcHandler = parameters.npcHandler
		if(npcHandler == nil) then
			print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'StdModule.say - Call without any npcHandler instance.')
			return false
		end

		local onlyFocus = (parameters.onlyFocus == nil or parameters.onlyFocus == true)
		if(not npcHandler:isFocused(cid) and onlyFocus) then
			return false
		end

		local parseInfo = {[TAG_PLAYERNAME] = getCreatureName(cid)}
		npcHandler:say(npcHandler:parseMessage(parameters.text or parameters.message, parseInfo), cid, parameters.publicize and true)
		if(parameters.reset) then
			npcHandler:resetNpc(cid)
		elseif(parameters.moveup and type(parameters.moveup) == 'number') then
			npcHandler.keywordHandler:moveUp(parameters.moveup)
		end

		return true
	end

	--Usage:
		-- local node1 = keywordHandler:addKeyword({'promot'}, StdModule.say, {npcHandler = npcHandler, text = 'I can promote you for 20000 brozne coins. Do you want me to promote you?'})
		-- 		node1:addChildKeyword({'yes'}, StdModule.promotePlayer, {npcHandler = npcHandler, cost = 20000, promotion = 1, level = 20}, text = 'Congratulations! You are now promoted.')
		-- 		node1:addChildKeyword({'no'}, StdModule.say, {npcHandler = npcHandler, text = 'Alright then, come back when you are ready.'}, reset = true)
	function StdModule.promotePlayer(cid, message, keywords, parameters, node)
		local npcHandler = parameters.npcHandler
		if(npcHandler == nil) then
			print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'StdModule.promotePlayer - Call without any npcHandler instance.')
			return false
		end

		if(not npcHandler:isFocused(cid)) then
			return false
		end

		if(isPremium(cid) or not getBooleanFromString(getConfigValue('premiumForPromotion'))) then
			if(getPlayerPromotionLevel(cid) >= parameters.promotion) then
				npcHandler:say('You are already promoted!', cid)
			elseif(getPlayerLevel(cid) < parameters.level) then
				npcHandler:say('I am sorry, but I can only promote you once you have reached level ' .. parameters.level .. '.', cid)
			elseif(not doPlayerRemoveMoney(cid, parameters.cost)) then
				npcHandler:say('You do not have enough money!', cid)
			else
				doPlayerSetPromotionLevel(cid, parameters.promotion)
				npcHandler:say(parameters.text, cid)
			end
		else
			npcHandler:say("You need a premium account in order to get promoted.", cid)
		end

		npcHandler:resetNpc(cid)
		return true
	end

	function StdModule.learnSpell(cid, message, keywords, parameters, node)
		local npcHandler = parameters.npcHandler
		if(npcHandler == nil) then
			print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'StdModule.learnSpell - Call without any npcHandler instance.')
			return false
		end

		if(not npcHandler:isFocused(cid)) then
			return false
		end

		if(isPremium(cid) or not(parameters.premium)) then
			if(getPlayerLearnedInstantSpell(cid, parameters.spellName)) then
				npcHandler:say('You already know this spell.', cid)
			elseif(getPlayerLevel(cid) < parameters.level) then
				npcHandler:say('You need to obtain a level of ' .. parameters.level .. ' or higher to be able to learn ' .. parameters.spellName .. '.', cid)
			elseif(not parameters.vocation(cid)) then
				npcHandler:say('This spell is not for your vocation', cid)
			elseif(not doPlayerRemoveMoney(cid, parameters.price)) then
				npcHandler:say('You do not have enough money, this spell costs ' .. parameters.price .. ' gold coins.', cid)
			else
				npcHandler:say('You have learned ' .. parameters.spellName .. '.', cid)
				playerLearnInstantSpell(cid, parameters.spellName)
			end
		else
			npcHandler:say('You need a premium account in order to buy ' .. parameters.spellName .. '.', cid)
		end

		npcHandler:resetNpc(cid)
		return true
	end

	function StdModule.bless(cid, message, keywords, parameters, node)
		local npcHandler = parameters.npcHandler
		if(npcHandler == nil) then
			print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'StdModule.bless - Call without any npcHandler instance.')
			return false
		end

		if(not getBooleanFromString(getConfigValue('blessings'))) then
			npcHandler:say("Sorry, but Gods moved back my permission to bless anyone.", cid)
			return false
		end

		if(not npcHandler:isFocused(cid)) then
			return false
		end

		if(isPremium(cid) or not getBooleanFromString(getConfigValue('blessingsOnlyPremium')) or not parameters.premium) then

			if(parameters.number > 0) then
				if(getPlayerBlessing(cid, parameters.number)) then
					npcHandler:say("Gods have already blessed you with this blessing!", cid)
				elseif(not doPlayerRemoveMoney(cid, parameters.cost)) then
					npcHandler:say("You don't have enough money for blessing.", cid)
				else
					npcHandler:say("You have been blessed by one of the five gods!", cid)
					doPlayerAddBlessing(cid, parameters.number)
				end
			else
				if(getPlayerPVPBlessing(cid)) then
					npcHandler:say("Gods have already blessed you with this blessing!", cid)
				elseif(not doPlayerRemoveMoney(cid, parameters.cost)) then
					npcHandler:say("You don't have enough money for blessing.", cid)
				else
					local any = false
					for i = 1, 5 do
						if(getPlayerBlessing(cid, i)) then
							any = true
							break
						end
					end

					if(any) then
						npcHandler:say("You have been blessed by the god of war!", cid)
						doPlayerSetPVPBlessing(cid)
					else
						npcHandler:say("You need to be blessed by at least one god to get this blessing.", cid)
					end
				end
			end
		else
			npcHandler:say('You need a premium account in order to be blessed.', cid)
		end

		npcHandler:resetNpc(cid)
		return true
	end

	function StdModule.travel(cid, message, keywords, parameters, node)
		local npcHandler = parameters.npcHandler
		if(npcHandler == nil) then
			print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'StdModule.travel - Call without any npcHandler instance.')
			return false
		end

		if(not npcHandler:isFocused(cid)) then
			return false
		end

		local storage, pzLocked = parameters.storageValue or (EMPTY_STORAGE + 1), parameters.allowLocked or false
		if(parameters.premium and not isPremium(cid)) then
			npcHandler:say('I\'m sorry, but you need a premium account in order to travel onboard our ships.', cid)
		elseif(parameters.level ~= nil and getPlayerLevel(cid) < parameters.level) then
			npcHandler:say('You must reach level ' .. parameters.level .. ' before I can let you go there.', cid)
		elseif(parameters.storageId ~= nil and getPlayerStorageValue(cid, parameters.storageId) < storage) then
			npcHandler:say(parameters.storageInfo or 'You may not travel there yet!', cid)
		elseif(not pzLocked and isPlayerPzLocked(cid)) then
			npcHandler:say('First get rid of those blood stains! You are not going to ruin my vehicle!', cid)
		elseif(not doPlayerRemoveMoney(cid, parameters.cost)) then
			npcHandler:say('You don\'t have enough money.', cid)
		else
			npcHandler:say('Set the sails!', cid)
			npcHandler:releaseFocus(cid)

			doTeleportThing(cid, parameters.destination, false)
			doSendMagicEffect(parameters.destination, CONST_ME_TELEPORT)
		end

		npcHandler:resetNpc(cid)
		return true
	end

	FocusModule = {
		npcHandler = nil
	}

	-- Creates a new instance of FocusModule without an associated NpcHandler.
	function FocusModule:new()
		local obj = {}
		setmetatable(obj, self)
		self.__index = self
		return obj
	end

	-- Inits the module and associates handler to it.
	function FocusModule:init(handler)
		self.npcHandler = handler
		for i, word in pairs(FOCUS_GREETWORDS) do
			local obj = {}
			table.insert(obj, word)

			obj.callback = FOCUS_GREETWORDS.callback or FocusModule.messageMatcher
			handler.keywordHandler:addKeyword(obj, FocusModule.onGreet, {module = self})
		end

		for i, word in pairs(FOCUS_FAREWELLWORDS) do
			local obj = {}
			table.insert(obj, word)

			obj.callback = FOCUS_FAREWELLWORDS.callback or FocusModule.messageMatcher
			handler.keywordHandler:addKeyword(obj, FocusModule.onFarewell, {module = self})
		end
	end

	-- Greeting callback function.
	function FocusModule.onGreet(cid, message, keywords, parameters)
		parameters.module.npcHandler:onGreet(cid)
		return true
	end

	-- UnGreeting callback function.
	function FocusModule.onFarewell(cid, message, keywords, parameters)
		if(not parameters.module.npcHandler:isFocused(cid)) then
			return false
		end

		parameters.module.npcHandler:onFarewell(cid)
		parameters.module.npcHandler:resetNpc(cid)
		return true
	end

	-- Custom message matching callback function for greeting messages.
	function FocusModule.messageMatcher(keywords, message)
		local spectators = getSpectators(getCreaturePosition(getNpcId()), 7, 7)
		for i, word in pairs(keywords) do
			if(type(word) == 'string') then
				if(string.find(message, word) and not string.find(message, '[%w+]' .. word) and not string.find(message, word .. '[%w+]')) then
					if(string.find(message, getCreatureName(getNpcId()))) then
						return true
					end

					for i, uid in ipairs(spectators) do
						if(string.find(message, getCreatureName(uid))) then
							return false
						end
					end

					return true
				end
			end
		end

		return false
	end

	KeywordModule = {
		npcHandler = nil
	}
	-- Add it to the parseable module list.
	Modules.parseableModules['module_keywords'] = KeywordModule

	function KeywordModule:new()
		local obj = {}
		setmetatable(obj, self)
		self.__index = self
		return obj
	end

	function KeywordModule:init(handler)
		self.npcHandler = handler
	end

	-- Parses all known parameters.
	function KeywordModule:parseParameters()
		local ret = NpcSystem.getParameter('keywords')
		if(ret ~= nil) then
			self:parseKeywords(ret)
		end
	end

	function KeywordModule:parseKeywords(data)
		local n = 1
		for keys in string.gmatch(data, '[^;]+') do
			local i = 1

			local keywords = {}
			for temp in string.gmatch(keys, '[^,]+') do
				table.insert(keywords, temp)
				i = i + 1
			end

			if(i ~= 1) then
				local reply = NpcSystem.getParameter('keyword_reply' .. n)
				if(reply ~= nil) then
					self:addKeyword(keywords, reply)
				else
					print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Parameter \'' .. 'keyword_reply' .. n .. '\' missing. Skipping...')
				end
			else
				print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'No keywords found for keyword set #' .. n .. '. Skipping...')
			end

			n = n + 1
		end
	end

	function KeywordModule:addKeyword(keywords, reply)
		self.npcHandler.keywordHandler:addKeyword(keywords, StdModule.say, {npcHandler = self.npcHandler, onlyFocus = true, text = reply, reset = true})
	end

	TravelModule = {
		npcHandler = nil,
		destinations = nil,
		yesNode = nil,
		noNode = nil,
	}
	-- Add it to the parseable module list.
	Modules.parseableModules['module_travel'] = TravelModule

	function TravelModule:new()
		local obj = {}
		setmetatable(obj, self)
		self.__index = self
		return obj
	end

	function TravelModule:init(handler)
		self.npcHandler = handler
		self.yesNode = KeywordNode:new(SHOP_YESWORD, TravelModule.onConfirm, {module = self})
		self.noNode = KeywordNode:new(SHOP_NOWORD, TravelModule.onDecline, {module = self})

		self.destinations = {}
	end

	-- Parses all known parameters.
	function TravelModule:parseParameters()
		local ret = NpcSystem.getParameter('travel_destinations')
		if(ret ~= nil) then
			self:parseDestinations(ret)
			for _, word in ipairs({'destination', 'list', 'where', 'travel'}) do
				self.npcHandler.keywordHandler:addKeyword({word}, TravelModule.listDestinations, {module = self})
			end
		end
	end

	function TravelModule:parseDestinations(data)
		for destination in string.gmatch(data, '[^;]+') do
			local i, name, pos, cost, premium, level, storage = 1, nil, {x = nil, y = nil, z = nil}, nil, false
			for tmp in string.gmatch(destination, '[^,]+') do
				if(i == 1) then
					name = tmp
				elseif(i == 2) then
					pos.x = tonumber(tmp)
				elseif(i == 3) then
					pos.y = tonumber(tmp)
				elseif(i == 4) then
					pos.z = tonumber(tmp)
				elseif(i == 5) then
					cost = tonumber(tmp)
				elseif(i == 6) then
					premium = getBooleanFromString(tmp)
				else
					print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Unknown parameter found in travel destination parameter.', tmp, destination)
				end

				i = i + 1
			end

			if(name ~= nil and pos.x ~= nil and pos.y ~= nil and pos.z ~= nil and cost ~= nil) then
				self:addDestination(name, pos, cost, premium)
			else
				print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Parameter(s) missing for travel destination:', name, pos, cost, premium)
			end
		end
	end

	function TravelModule:addDestination(name, position, price, premium)
		table.insert(self.destinations, name)
		local parameters = {
			cost = price,
			destination = position,
			premium = premium,
			module = self
		}

		local keywords, bringWords = {}, {}
		table.insert(keywords, name)

		table.insert(bringWords, 'bring me to ' .. name)
		self.npcHandler.keywordHandler:addKeyword(bringWords, TravelModule.bring, parameters)

		local node = self.npcHandler.keywordHandler:addKeyword(keywords, TravelModule.travel, parameters)
		node:addChildKeywordNode(self.yesNode)
		node:addChildKeywordNode(self.noNode)
	end

	function TravelModule.travel(cid, message, keywords, parameters, node)
		local module = parameters.module
		if(not module.npcHandler:isFocused(cid)) then
			return false
		end

		module.npcHandler:say('Do you want to travel to ' .. keywords[1] .. ' for ' .. parameters.cost .. ' gold coins?', cid)
		return true
	end

	function TravelModule.onConfirm(cid, message, keywords, parameters, node)
		local module = parameters.module
		if(not module.npcHandler:isFocused(cid)) then
			return false
		end

		local parent = node:getParent():getParameters()
		if(isPremium(cid) or not parent.premium) then
			if(not isPlayerPzLocked(cid)) then
				if(doPlayerRemoveMoney(cid, parent.cost)) then
					module.npcHandler:say('Set the sails!', cid)
					module.npcHandler:releaseFocus(cid)

					doTeleportThing(cid, parent.destination, true)
					doSendMagicEffect(parent.destination, CONST_ME_TELEPORT)
				else
					module.npcHandler:say('You don\'t have enough money.', cid)
				end
			else
				module.npcHandler:say('First get rid of those blood stains! You are not going to ruin my vehicle!', cid)
			end
		else
			module.npcHandler:say('I\'m sorry, but you need a premium account in order to travel onboard our ships.', cid)
		end

		module.npcHandler:resetNpc(cid)
		return true
	end

	-- onDecline keyword callback function. Generally called when the player sais 'no' after wanting to buy an item.
	function TravelModule.onDecline(cid, message, keywords, parameters, node)
		local module = parameters.module
		if(not module.npcHandler:isFocused(cid)) then
			return false
		end

		module.npcHandler:say(module.npcHandler:parseMessage(module.npcHandler:getMessage(MESSAGE_DECLINE), {[TAG_PLAYERNAME] = getCreatureName(cid)}), cid)
		module.npcHandler:resetNpc(cid)
		return true
	end

	function TravelModule.bring(cid, message, keywords, parameters, node)
		local module = parameters.module
		if(not module.npcHandler:isFocused(cid)) then
			return false
		end

		if((isPremium(cid) or not parameters.premium) and not isPlayerPzLocked(cid) and doPlayerRemoveMoney(cid, parameters.cost)) then
			module.npcHandler:say('Set the sails!', cid)
			module.npcHandler:releaseFocus(cid)

			doTeleportThing(cid, parameters.destination, false)
			doSendMagicEffect(parameters.destination, CONST_ME_TELEPORT)
		end

		module.npcHandler:releaseFocus(cid)
		return true
	end

	function TravelModule.listDestinations(cid, message, keywords, parameters, node)
		local module = parameters.module
		if(not module.npcHandler:isFocused(cid)) then
			return false
		end

		local msg = nil
		for _, destination in ipairs(module.destinations) do
			if(msg ~= nil) then
				msg = msg .. ", "
			else
				msg = ""
			end

			msg = msg .. "{" .. destination .. "}"
		end

		module.npcHandler:say(msg .. ".", cid)
		module.npcHandler:resetNpc(cid)
		return true
	end

	OutfitModule = {
		npcHandler = nil,
		outfits = nil,
		yesNode = nil,
		noNode = nil,
	}
	-- Add it to the parseable module list.
	Modules.parseableModules['module_outfit'] = OutfitModule

	function OutfitModule:new()
		if(OUTFITMODULE_FUNCTION[1] == nil or OUTFITMODULE_FUNCTION[2] == nil) then
			return nil
		end

		local obj = {}
		setmetatable(obj, self)
		self.__index = self
		return obj
	end

	function OutfitModule:init(handler)
		self.npcHandler = handler
		self.yesNode = KeywordNode:new(SHOP_YESWORD, OutfitModule.onConfirm, {module = self})
		self.noNode = KeywordNode:new(SHOP_NOWORD, OutfitModule.onDecline, {module = self})

		self.outfits = {}
	end

	-- Parses all known parameters.
	function OutfitModule:parseParameters()
		local ret = NpcSystem.getParameter('outfits')
		if(ret ~= nil) then
			self:parseKeywords(ret)
			for _, word in ipairs({'outfits', 'addons'}) do
				self.npcHandler.keywordHandler:addKeyword({word}, OutfitModule.listOutfits, {module = self})
			end
		end
	end

	function OutfitModule:parseKeywords(data)
		local n = 1
		for outfit in string.gmatch(data, '[^;]+') do
			local i, keywords = 1, {}
			for tmp in string.gmatch(outfit, '[^,]+') do
				table.insert(keywords, tmp)
				i = i + 1
			end

			if(i > 0) then
				local ret = NpcSystem.getParameter('outfit' .. n)
				if(ret ~= nil) then
					self:parseList(keywords, ret)
				else
					print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Missing \'outfit' .. n .. '\' parameter, skipping...')
				end
			else
				print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'No keywords found for outfit set #' .. n .. ', skipping...')
			end

			n = n + 1
		end
	end

	function OutfitModule:parseList(keywords, data)
		local outfit, items = nil, {}
		for list in string.gmatch(data, '[^;]+') do
			local a, b, c, d, e = nil, nil, nil, nil, 1
			for tmp in string.gmatch(list, '[^,]+') do
				if(e == 1) then
					a = tmp
				elseif(e == 2) then
					b = tmp
				elseif(e == 3) then
					c = tmp
				elseif(e == 4) then
					d = tmp
				else
					print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Unknown parameter found in outfit list while parsing ' .. (outfit == nil and 'outfit' or 'item') .. '.', tmp, list)
				end

				e = e + 1
			end

			if(outfit == nil) then
				outfit = {tonumber(a), tonumber(b), getBooleanFromString(c), d}
			elseif(a ~= nil) then
				local tmp = tonumber(a)
				if((tmp ~= nil or tostring(a) == "money") and b ~= nil and c ~= nil) then
					a = tmp or 20000
					tmp = tonumber(d)
					if(tmp == nil) then
						tmp = -1
					end

					items[a] = {b, tmp, c}
				else
					print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Missing parameter(s) for outfit items.', b, c, d)
				end
			else
				print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Missing base parameter for outfit items.', a)
			end
		end

		if(type(outfit) == 'table') then
			local tmp = true
			for i = 1, 2 do
				if(outfit[i] == nil) then
					tmp = false
					break
				end
			end

			if(tmp and table.maxn(items) > 0) then
				self:addOutfit(keywords, outfit, items)
			else
				print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Invalid outfit, addon or empty items pool.', data)
			end
		end
	end

	function OutfitModule:addOutfit(keywords, outfit, items)
		table.insert(self.outfits, keywords[1])
		local parameters = {
			outfit = outfit[1],
			addon = outfit[2],
			premium = outfit[3],
			gender = nil,
			items = items,
			module = self
		}

		if(outfit[4] ~= nil) then
			local tmp = string.lower(tostring(outfit[5]))
			if(tmp == 'male' or tmp == '1') then
				parameters.gender = 1
			elseif(tmp == 'female' or tmp == '0') then
				parameters.gender = 0
			end
		end

		for i, name in pairs(keywords) do
			local words = {}
			table.insert(words, name)

			local node = self.npcHandler.keywordHandler:addKeyword(words, OutfitModule.obtain, parameters)
			node:addChildKeywordNode(self.yesNode)
			node:addChildKeywordNode(self.noNode)
		end
	end

	function OutfitModule.obtain(cid, message, keywords, parameters, node)
		local module = parameters.module
		if(not module.npcHandler:isFocused(cid)) then
			return false
		end

		local i, items, size = 0, nil, table.maxn(parameters.items)
		for k, v in pairs(parameters.items) do
			if(v[1] ~= "storageset") then
				i = i + 1
				if(items ~= nil) then
					if(i == size) then
						items = items .. " and "
					else
						items = items .. ", "
					end
				else
					items = ""
				end

				if(tonumber(v[1]) ~= nil and tonumber(v[1]) > 1) then
					items = items .. v[1] .. " "
				end

				items = items .. v[3]
			end
		end

		module.npcHandler:say('Do you want ' .. keywords[1] .. ' ' .. (addon == 0 and "outfit" or "addon") .. ' for ' .. items .. '?', cid)
		return true

	end

	function OutfitModule.onConfirm(cid, message, keywords, parameters, node)
		local module = parameters.module
		if(not module.npcHandler:isFocused(cid)) then
			return false
		end

		local parent = node:getParent():getParameters()
		if(isPremium(cid) or not parent.premium) then
			if(not OUTFITMODULE_FUNCTION[2](cid, parent.outfit, parent.addon)) then
				if(parent.addon == 0 or OUTFITMODULE_FUNCTION[2](cid, parent.outfit)) then
					if(parent.gender == nil or parent.gender == getPlayerSex(cid)) then
						local found = true
						for k, v in pairs(parent.items) do
							local tmp = tonumber(v[1])
							if(tmp == nil) then
								if(v[1] == "storagecheck") then
									if(getCreatureStorage(cid, k) < v[2]) then
										found = false
									end
								elseif(v[1] == "outfitid") then
									if(not canPlayerWearOutfitId(cid, k, v[2])) then
										found = false
									end
								elseif(v[1] == "outfit") then
									if(not canPlayerWearOutfit(cid, k, v[2])) then
										found = false
									end
								else
									found = false
								end
							elseif(k == 20000) then
								if(getPlayerMoney(cid) < tmp) then
									found = false
								end
							elseif(getPlayerItemCount(cid, k, v[2]) < tmp) then
								found = false
							end

							if(not found) then
								break
							end
						end

						if(found) then
							for k, v in pairs(parent.items) do
								if(tonumber(v[1]) ~= nil) then
									if(k == 20000) then
										doPlayerRemoveMoney(cid, v[1])
									else
										doPlayerRemoveItem(cid, k, v[1], v[2])
									end
								elseif(v[1] == "storageset") then
									doCreatureSetStorage(cid, k, v[2])
								end
							end

							module.npcHandler:say('It was a pleasure to dress you.', cid)
							OUTFITMODULE_FUNCTION[1](cid, parent.outfit, parent.addon)
							doPlayerSetStorageValue(cid, parent.storageId, storage)
						else
							module.npcHandler:say('You don\'t have these items!', cid)
						end
					else
						module.npcHandler:say('Sorry, this ' .. (parent.addon == 0 and 'outfit' or 'addon') .. ' is not for your gender.', cid)
					end
				else
					module.npcHandler:say('I will not dress you with addon of outfit you cannot wear!', cid)
				end
			else
				module.npcHandler:say('You already have this ' .. (parent.addon == 0 and 'outfit' or 'addon') .. '!', cid)
			end
		else
			module.npcHandler:say('Sorry, I dress only premium players.', cid)
		end

		module.npcHandler:resetNpc(cid)
		return true
	end

	-- onDecline keyword callback function. Generally called when the player sais 'no' after wanting to buy an item.
	function OutfitModule.onDecline(cid, message, keywords, parameters, node)
		local module = parameters.module
		if(not module.npcHandler:isFocused(cid)) then
			return false
		end

		module.npcHandler:say(module.npcHandler:parseMessage(module.npcHandler:getMessage(MESSAGE_DECLINE), {[TAG_PLAYERNAME] = getCreatureName(cid)}), cid)
		module.npcHandler:resetNpc(cid)
		return true
	end

	function OutfitModule.listOutfits(cid, message, keywords, parameters, node)
		local module = parameters.module
		if(not module.npcHandler:isFocused(cid)) then
			return false
		end

		local msg, size = nil, table.maxn(module.outfits)
		if(size > 0) then
			for i, outfit in ipairs(module.outfits) do
				if(msg ~= nil) then
					if(i == size) then
						msg = msg .. " and "
					else
						msg = msg .. ", "
					end
				else
					msg = "I can dress you into "
				end

				msg = msg .. "{" .. outfit .. "}"
			end
		else
			msg = "Sorry, I have nothing to offer right now."
		end

		module.npcHandler:say(msg .. ".", cid)
		module.npcHandler:resetNpc(cid)
		return true
	end

	ShopModule = {
		npcHandler = nil,
		yesNode = nil,
		noNode = nil,
		noText = '',
		maxCount = 100,
		amount = 0
	}

	-- Add it to the parseable module list.
	Modules.parseableModules['module_shop'] = ShopModule

	-- Creates a new instance of ShopModule
	function ShopModule:new()
		local obj = {}
		setmetatable(obj, self)
		self.__index = self
		return obj
	end

	-- Parses all known parameters.
	function ShopModule:parseParameters()
		local ret = NpcSystem.getParameter('shop_buyable')
		if(ret ~= nil) then
			self:parseBuyable(ret)
		end

		local ret = NpcSystem.getParameter('shop_sellable')
		if(ret ~= nil) then
			self:parseSellable(ret)
		end

		local ret = NpcSystem.getParameter('shop_buyable_containers')
		if(ret ~= nil) then
			self:parseBuyableContainers(ret)
		end
	end

	-- Parse a string contaning a set of buyable items.
	function ShopModule:parseBuyable(data)
		for item in string.gmatch(data, '[^;]+') do
			local i, name, itemid, cost, subType, realName = 1, nil, nil, nil, nil, nil
			for tmp in string.gmatch(item, '[^,]+') do
				if(i == 1) then
					name = tmp
				elseif(i == 2) then
					itemid = tonumber(tmp)
				elseif(i == 3) then
					cost = tonumber(tmp)
				elseif(i == 4) then
					subType = tonumber(tmp)
				elseif(i == 5) then
					realName = tmp
				else
					print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Unknown parameter found in buyable items parameter.', tmp, item)
				end

				i = i + 1
			end

			if(SHOPMODULE_MODE == SHOPMODULE_MODE_TRADE) then
				if(itemid ~= nil and cost ~= nil) then
					if(isItemFluidContainer(itemid) and subType == nil) then
						print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'SubType missing for parameter item:', item)
					else
						self:addBuyableItem(nil, itemid, cost, subType, realName)
					end
				else
					print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Parameter(s) missing for item:', itemid, cost)
				end
			elseif(name ~= nil and itemid ~= nil and cost ~= nil) then
				if(isItemFluidContainer(itemid) and subType == nil) then
					print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'SubType missing for parameter item:', item)
				else
					local names = {}
					table.insert(names, name)
					self:addBuyableItem(names, itemid, cost, subType, realName)
				end
			else
				print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Parameter(s) missing for item:', name, itemid, cost)
			end
		end
	end

	-- Parse a string contaning a set of sellable items.
	function ShopModule:parseSellable(data)
		for item in string.gmatch(data, '[^;]+') do
			local i, name, itemid, cost, realName = 1, nil, nil, nil, nil
			for temp in string.gmatch(item, '[^,]+') do
				if(i == 1) then
					name = temp
				elseif(i == 2) then
					itemid = tonumber(temp)
				elseif(i == 3) then
					cost = tonumber(temp)
				elseif(i == 4) then
					realName = temp
				else
					print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Unknown parameter found in sellable items parameter.', temp, item)
				end
				i = i + 1
			end

			if(SHOPMODULE_MODE == SHOPMODULE_MODE_TRADE) then
				if(itemid ~= nil and cost ~= nil) then
					self:addSellableItem(nil, itemid, cost, realName)
				else
					print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Parameter(s) missing for item:', itemid, cost)
				end
			elseif(name ~= nil and itemid ~= nil and cost ~= nil) then
				local names = {}
				table.insert(names, name)
				self:addSellableItem(names, itemid, cost, realName)
			else
				print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Parameter(s) missing for item:', name, itemid, cost)
			end
		end
	end

	-- Parse a string contaning a set of buyable items.
	function ShopModule:parseBuyableContainers(data)
		for item in string.gmatch(data, '[^;]+') do
			local i, name, container, itemid, cost, subType, realName = 1, nil, nil, nil, nil, nil, nil
			for temp in string.gmatch(item, '[^,]+') do
				if(i == 1) then
					name = temp
				elseif(i == 2) then
					itemid = tonumber(temp)
				elseif(i == 3) then
					itemid = tonumber(temp)
				elseif(i == 4) then
					cost = tonumber(temp)
				elseif(i == 5) then
					subType = tonumber(temp)
				elseif(i == 6) then
					realName = temp
				else
					print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Unknown parameter found in buyable items parameter.', temp, item)
				end
				i = i + 1
			end

			if(name ~= nil and container ~= nil and itemid ~= nil and cost ~= nil) then
				if(isItemFluidContainer(itemid) and subType == nil) then
					print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'SubType missing for parameter item:', item)
				else
					local names = {}
					table.insert(names, name)
					self:addBuyableItemContainer(names, container, itemid, cost, subType, realName)
				end
			else
				print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'Parameter(s) missing for item:', name, container, itemid, cost)
			end
		end
	end

	-- Initializes the module and associates handler to it.
	function ShopModule:init(handler)
		self.npcHandler = handler
		self.yesNode = KeywordNode:new(SHOP_YESWORD, ShopModule.onConfirm, {module = self})
		self.noNode = KeywordNode:new(SHOP_NOWORD, ShopModule.onDecline, {module = self})

		self.noText = handler:getMessage(MESSAGE_DECLINE)
		if(SHOPMODULE_MODE ~= SHOPMODULE_MODE_TALK) then
			for i, word in pairs(SHOP_TRADEREQUEST) do
				local obj = {}
				table.insert(obj, word)

				obj.callback = SHOP_TRADEREQUEST.callback or ShopModule.messageMatcher
				handler.keywordHandler:addKeyword(obj, ShopModule.requestTrade, {module = self})
			end
		end
	end

	-- Custom message matching callback function for requesting trade messages.
	function ShopModule.messageMatcher(keywords, message)
		for i, word in pairs(keywords) do
			if(type(word) == 'string' and string.find(message, word) and not string.find(message, '[%w+]' .. word) and not string.find(message, word .. '[%w+]')) then
				return true
			end
		end

		return false
	end

	-- Resets the module-specific variables.
	function ShopModule:reset()
		self.amount = 0
	end

	-- Function used to match a number value from a string.
	function ShopModule:getCount(message)
		local ret, b, e = 1, string.find(message, PATTERN_COUNT)
		if(b ~= nil and e ~= nil) then
			ret = tonumber(string.sub(message, b, e))
		end

		return math.max(1, math.min(self.maxCount, ret))
	end

	-- Adds a new buyable item.
	--	names = A table containing one or more strings of alternative names to this item. Used only for old buy/sell system.
	--	itemid = The itemid of the buyable item
	--	cost = The price of one single item
	--	subType - The subType of each rune or fluidcontainer item. Can be left out if it is not a rune/fluidcontainer. Default value is 0 and 1 (depending on shop mode)
	--	realName - The real, full name for the item. Will be used as ITEMNAME in MESSAGE_ONBUY and MESSAGE_ONSELL if defined. Default value is nil (getItemNameById will be used)
	function ShopModule:addBuyableItem(names, itemid, cost, subType, realName)
		if(type(subType) == 'string' and realName == nil) then
			realName = subType
			subType = nil
		end

		local v = getItemInfo(itemid)
		if(SHOPMODULE_MODE ~= SHOPMODULE_MODE_TALK) then
			local item = {
				id = itemid,
				buy = cost,
				sell = -1,
				subType = tonumber(subType) or (v.charges > 0 and v.charges or 0),
				name = realName or v.name
			}

			for i, shopItem in ipairs(self.npcHandler.shopItems) do
				if(shopItem.id == item.id and (shopItem.subType == item.subType or shopItem.subType == 0)) then
					if(item.sell ~= shopItem.sell) then
						item.sell = shopItem.sell
					end

					self.npcHandler.shopItems[i] = item
					item = nil
					break
				end
			end

			if(item ~= nil) then
				table.insert(self.npcHandler.shopItems, item)
			end
		end

		if(names ~= nil and SHOPMODULE_MODE ~= SHOPMODULE_MODE_TRADE) then
			local parameters = {
				itemid = itemid,
				cost = cost,
				eventType = SHOPMODULE_BUY_ITEM,
				module = self,
				realName = realName or v.name,
				subType = tonumber(subType) or (v.charges > 0 and v.charges or 1)
			}

			for i, name in pairs(names) do
				local keywords = {}
				table.insert(keywords, 'buy')
				table.insert(keywords, name)

				local node = self.npcHandler.keywordHandler:addKeyword(keywords, ShopModule.tradeItem, parameters)
				node:addChildKeywordNode(self.yesNode)
				node:addChildKeywordNode(self.noNode)
			end
		end
	end

	-- Adds a new buyable container of items.
	--	names = A table containing one or more strings of alternative names to this item.
	--	container = Backpack, bag or any other itemid of container where bought items will be stored
	--	itemid = The itemid of the buyable item
	--	cost = The price of one single item
	--	subType - The subType of each rune or fluidcontainer item. Can be left out if it is not a rune/fluidcontainer. Default value is 1.
	--	realName - The real, full name for the item. Will be used as ITEMNAME in MESSAGE_ONBUY and MESSAGE_ONSELL if defined. Default value is nil (getItemNameById will be used)
	function ShopModule:addBuyableItemContainer(names, container, itemid, cost, subType, realName)
		if(names ~= nil) then
			local v = getItemInfo(itemid)
			local parameters = {
				container = container,
				itemid = itemid,
				cost = cost,
				eventType = SHOPMODULE_BUY_ITEM_CONTAINER,
				module = self,
				realName = realName or v.name,
				subType = tonumber(subType) or (v.charges > 0 and v.charges or 1)
			}

			for i, name in pairs(names) do
				local keywords = {}
				table.insert(keywords, 'buy')
				table.insert(keywords, name)

				local node = self.npcHandler.keywordHandler:addKeyword(keywords, ShopModule.tradeItem, parameters)
				node:addChildKeywordNode(self.yesNode)
				node:addChildKeywordNode(self.noNode)
			end
		end
	end

	-- Adds a new sellable item.
	--	names = A table containing one or more strings of alternative names to this item. Used only by old buy/sell system.
	--	itemid = The itemid of the sellable item
	--	cost = The price of one single item
	--	realName - The real, full name for the item. Will be used as ITEMNAME in MESSAGE_ONBUY and MESSAGE_ONSELL if defined. Default value is nil (getItemNameById will be used)
	function ShopModule:addSellableItem(names, itemid, cost, realName)
		local v = getItemInfo(itemid)
		if(SHOPMODULE_MODE ~= SHOPMODULE_MODE_TALK) then
			local item = {
				id = itemid,
				buy = -1,
				sell = cost,
				subType = ((v.charges > 0 and v.stackable) and v.charges or 0),
				name = realName or v.name
			}

			for i, shopItem in ipairs(self.npcHandler.shopItems) do
				if(shopItem.id == item.id and shopItem.subType == item.subType) then
					if(item.buy ~= shopItem.buy) then
						item.buy = shopItem.buy
					end

					self.npcHandler.shopItems[i] = item
					item = nil
					break
				end
			end

			if(item ~= nil) then
				table.insert(self.npcHandler.shopItems, item)
			end
		end

		if(names ~= nil and SHOPMODULE_MODE ~= SHOPMODULE_MODE_TRADE) then
			local parameters = {
				itemid = itemid,
				cost = cost,
				eventType = SHOPMODULE_SELL_ITEM,
				module = self,
				realName = realName or v.name
			}

			for i, name in pairs(names) do
				local keywords = {}
				table.insert(keywords, 'sell')
				table.insert(keywords, name)

				local node = self.npcHandler.keywordHandler:addKeyword(keywords, ShopModule.tradeItem, parameters)
				node:addChildKeywordNode(self.yesNode)
				node:addChildKeywordNode(self.noNode)
			end
		end
	end

	-- onModuleReset callback function. Calls ShopModule:reset()
	function ShopModule:callbackOnModuleReset()
		self:reset()
		return true
	end

	-- Callback onBuy() function. If you wish, you can change certain Npc to use your onBuy().
	function ShopModule:callbackOnBuy(cid, itemid, subType, amount, ignoreCap, inBackpacks)
		local shopItem = nil
		for _, item in ipairs(self.npcHandler.shopItems) do
			if(item.id == itemid and item.subType == subType) then
				shopItem = item
				break
			end
		end

		if(shopItem == nil) then
			print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'ShopModule.onBuy - Item not found on shopItems list')
			return false
		end

		if(shopItem.buy == -1) then
			print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'ShopModule.onBuy - Attempt to purchase an item which only sellable')
			return false
		end

		if(amount <= 0) then
			print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'ShopModule.onBuy - Attempt to purchase ' .. amount .. ' items')
			return false
		end

		local subType, count = shopItem.subType or 0, amount
		local backpack, backpackPrice, totalCost = 1988, 20, amount * shopItem.buy
		if(inBackpacks) then
			totalCost = totalCost + (math.max(1, math.floor(count / getContainerCapById(backpack))) * backpackPrice)
		end

		local parseInfo = {
			[TAG_PLAYERNAME] = getPlayerName(cid),
			[TAG_ITEMCOUNT] = amount,
			[TAG_TOTALCOST] = totalCost,
			[TAG_ITEMNAME] = shopItem.name
		}
		if(getPlayerMoney(cid) < totalCost) then
			local msg = self.npcHandler:getMessage(MESSAGE_NEEDMONEY)
			doPlayerSendCancel(cid, self.npcHandler:parseMessage(msg, parseInfo))
			return false
		end

		local a, b = doNpcSellItem(cid, itemid, count, subType, ignoreCap, inBackpacks, backpack)
		if(a < amount) then
			local msgId = MESSAGE_NEEDMORESPACE
			if(a == 0) then
				msgId = MESSAGE_NEEDSPACE
			end

			local msg = self.npcHandler:getMessage(msgId)
			parseInfo[TAG_ITEMCOUNT] = a

			doPlayerSendCancel(cid, self.npcHandler:parseMessage(msg, parseInfo))
			if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
				self.npcHandler.talkStart[cid] = os.time()
			else
				self.npcHandler.talkStart = os.time()
			end

			if(a > 0) then
				doPlayerRemoveMoney(cid, ((a * shopItem.buy) + (b * backpackPrice)))
				return true
			end

			return false
		end

		local msg = self.npcHandler:getMessage(MESSAGE_BOUGHT)
		doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, self.npcHandler:parseMessage(msg, parseInfo))

		doPlayerRemoveMoney(cid, totalCost)
		if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
			self.npcHandler.talkStart[cid] = os.time()
		else
			self.npcHandler.talkStart = os.time()
		end

		return true
	end

	-- Callback onSell() function. If you wish, you can change certain Npc to use your onSell().
	function ShopModule:callbackOnSell(cid, itemid, subType, amount, ignoreEquipped, dummy)
		local shopItem = nil
		for _, item in ipairs(self.npcHandler.shopItems) do
			if(item.id == itemid and item.subType == subType) then
				shopItem = item
				break
			end
		end

		if(shopItem == nil) then
			print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'ShopModule.onSell - Item not found on shopItems list')
			return false
		end

		if(shopItem.sell == -1) then
			print('[Warning - ' .. getCreatureName(getNpcId()) .. '] NpcSystem:', 'ShopModule.onSell - Attempt to sell an item which is only buyable')
			return false
		end

		local parseInfo = {
			[TAG_PLAYERNAME] = getPlayerName(cid),
			[TAG_ITEMCOUNT] = amount,
			[TAG_TOTALCOST] = amount * shopItem.sell,
			[TAG_ITEMNAME] = shopItem.name
		}

		if(subType < 1 or getItemInfo(itemid).stackable) then
			subType = -1
		end

		if(doPlayerRemoveItem(cid, itemid, amount, subType, ignoreEquipped)) then
			local msg = self.npcHandler:getMessage(MESSAGE_SOLD)
			doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, self.npcHandler:parseMessage(msg, parseInfo))

			doPlayerAddMoney(cid, amount * shopItem.sell)
			if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
				self.npcHandler.talkStart[cid] = os.time()
			else
				self.npcHandler.talkStart = os.time()
			end

			return true
		end

		local msg = self.npcHandler:getMessage(MESSAGE_NEEDITEM)
		doPlayerSendCancel(cid, self.npcHandler:parseMessage(msg, parseInfo))
		if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
			self.npcHandler.talkStart[cid] = os.time()
		else
			self.npcHandler.talkStart = os.time()
		end

		return false
	end

	-- Callback for requesting a trade window with the NPC.
	function ShopModule.requestTrade(cid, message, keywords, parameters, node)
		local module = parameters.module
		if(not module.npcHandler:isFocused(cid)) then
			return false
		end

		local shop = getShopOwner(cid)
		if(shop and shop == getNpcId()) then
			return true
		end

		if(table.maxn(module.npcHandler.shopItems) == 0) then
			local parseInfo = { [TAG_PLAYERNAME] = getPlayerName(cid) }
			local msg = module.npcHandler:parseMessage(module.npcHandler:getMessage(MESSAGE_NOSHOP), parseInfo)

			module.npcHandler:say(msg, cid)
			return true
		end

		local parseInfo = { [TAG_PLAYERNAME] = getPlayerName(cid) }
		local msg = module.npcHandler:parseMessage(module.npcHandler:getMessage(MESSAGE_SENDTRADE), parseInfo)
		addEvent(openShopWindow, 100, cid, module.npcHandler.shopItems,
			function(cid, itemid, subType, amount, ignoreCap, inBackpacks)
				module.npcHandler:onBuy(cid, itemid, subType, amount, ignoreCap, inBackpacks)
			end,
			function(cid, itemid, subType, amount, ignoreCap, inBackpacks)
				module.npcHandler:onSell(cid, itemid, subType, amount, ignoreCap, inBackpacks)
			end
		)

		module.npcHandler:say(msg, cid)
		return true
	end

	-- onConfirm keyword callback function. Sells/buys the actual item.
	function ShopModule.onConfirm(cid, message, keywords, parameters, node)
		local module = parameters.module
		if(not module.npcHandler:isFocused(cid)) then
			return false
		end

		local parentParameters = node:getParent():getParameters()
		local parseInfo = {
			[TAG_PLAYERNAME] = getPlayerName(cid),
			[TAG_ITEMCOUNT] = module.amount,
			[TAG_TOTALCOST] = parentParameters.cost * module.amount,
			[TAG_ITEMNAME] = parentParameters.realName
		}

		if(parentParameters.eventType == SHOPMODULE_SELL_ITEM) then
			local ret = doPlayerSellItem(cid, parentParameters.itemid, module.amount, parentParameters.cost * module.amount)
			if(ret) then
				local msg = module.npcHandler:getMessage(MESSAGE_ONSELL)
				msg = module.npcHandler:parseMessage(msg, parseInfo)
				module.npcHandler:say(msg, cid)
			else
				local msg = module.npcHandler:getMessage(MESSAGE_MISSINGITEM)
				msg = module.npcHandler:parseMessage(msg, parseInfo)
				module.npcHandler:say(msg, cid)
			end
		elseif(parentParameters.eventType == SHOPMODULE_BUY_ITEM) then
			local ret = doPlayerBuyItem(cid, parentParameters.itemid, module.amount, parentParameters.cost * module.amount, parentParameters.subType)
			if(ret) then
				if parentParameters.itemid == ITEM_PARCEL then
					doPlayerBuyItem(cid, ITEM_LABEL, module.amount, 0, parentParameters.subType)
				end
				local msg = module.npcHandler:getMessage(MESSAGE_ONBUY)
				msg = module.npcHandler:parseMessage(msg, parseInfo)
				module.npcHandler:say(msg, cid)
			else
				local msg = module.npcHandler:getMessage(MESSAGE_MISSINGMONEY)
				msg = module.npcHandler:parseMessage(msg, parseInfo)
				module.npcHandler:say(msg, cid)
			end
		elseif(parentParameters.eventType == SHOPMODULE_BUY_ITEM_CONTAINER) then
			local ret = doPlayerBuyItemContainer(cid, parentParameters.container, parentParameters.itemid, module.amount, parentParameters.cost * module.amount, parentParameters.subType)
			if(ret) then
				local msg = module.npcHandler:getMessage(MESSAGE_ONBUY)
				msg = module.npcHandler:parseMessage(msg, parseInfo)
				module.npcHandler:say(msg, cid)
			else
				local msg = module.npcHandler:getMessage(MESSAGE_MISSINGMONEY)
				msg = module.npcHandler:parseMessage(msg, parseInfo)
				module.npcHandler:say(msg, cid)
			end
		end

		module.npcHandler:resetNpc(cid)
		return true
	end

	-- onDecliune keyword callback function. Generally called when the player sais 'no' after wanting to buy an item.
	function ShopModule.onDecline(cid, message, keywords, parameters, node)
		local module = parameters.module
		if(not module.npcHandler:isFocused(cid)) then
			return false
		end

		local parentParameters = node:getParent():getParameters()
		local parseInfo = {
			[TAG_PLAYERNAME] = getPlayerName(cid),
			[TAG_ITEMCOUNT] = module.amount,
			[TAG_TOTALCOST] = parentParameters.cost * module.amount,
			[TAG_ITEMNAME] = parentParameters.realName
		}

		local msg = module.npcHandler:parseMessage(module.noText, parseInfo)
		module.npcHandler:say(msg, cid)
		module.npcHandler:resetNpc(cid)
		return true
	end

	-- tradeItem callback function. Makes the npc say the message defined by MESSAGE_BUY or MESSAGE_SELL
	function ShopModule.tradeItem(cid, message, keywords, parameters, node)
		local module = parameters.module
		if(not module.npcHandler:isFocused(cid)) then
			return false
		end

		local count = module:getCount(message)
		module.amount = count
		local parseInfo = {
			[TAG_PLAYERNAME] = getPlayerName(cid),
			[TAG_ITEMCOUNT] = module.amount,
			[TAG_TOTALCOST] = parameters.cost * module.amount,
			[TAG_ITEMNAME] = parameters.realName
		}

		if(parameters.eventType == SHOPMODULE_SELL_ITEM) then
			local msg = module.npcHandler:getMessage(MESSAGE_SELL)
			msg = module.npcHandler:parseMessage(msg, parseInfo)
			module.npcHandler:say(msg, cid)
		elseif(parameters.eventType == SHOPMODULE_BUY_ITEM) then
			local msg = module.npcHandler:getMessage(MESSAGE_BUY)
			msg = module.npcHandler:parseMessage(msg, parseInfo)
			module.npcHandler:say(msg, cid)
		elseif(parameters.eventType == SHOPMODULE_BUY_ITEM_CONTAINER) then
			local msg = module.npcHandler:getMessage(MESSAGE_BUY)
			msg = module.npcHandler:parseMessage(msg, parseInfo)
			module.npcHandler:say(msg, cid)
		end

		return true
	end
end

 

 

Alesar.lua

Spoiler

local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)
-- local npcHandlerfocus = NPCHANDLER_CONVBEHAVIOR == CONVERSATION_DEFAULT and 0 or cid
NpcSystem.parseParameters(npcHandler)

npcHandler:setMessage(MESSAGE_GREET, "What do you want from me, |PLAYERNAME|?")
npcHandler:setMessage(MESSAGE_PLACEDINQUEUE, "It might have escaped your limited human perception, but I am already talking to somebody else.")
npcHandler:setMessage(MESSAGE_WALKAWAY, "Farewell, human.")
npcHandler:setMessage(MESSAGE_FAREWELL, "Farewell, human. When I have taken my rightful place I shall remember those who served me well. Even if they are only humans.")

-- OTServ event handling functions start
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


-- OTServ event handling functions end


function AlesarSayCallback (cid, type, msg)

	
	if (getPlayerStorageValue(cid, 1029) ~= 1) then
	   return 0
	end

	if (msgcontains(msg:lower(),"djanni'hah")) then
		 npcHandler:say('What do you want from me, '.. getPlayerName(cid) ..'?')
		 npcHandler.focus = cid
		 npcHandlerfocus = 0
	elseif (msgcontains(msg:lower(),"mission") and npcHandlerfocus == 0 and getPlayerStorageValue(cid, 8131) ~= 1) then
			npcHandler:say("So Baa'leal thinks you are up to do a mission for us? ...")
			npcHandler:say("I think he is getting old, entrusting human scum such as you are with an important mission like that. ...", cid, 3000)
			npcHandler:say("Personally, I don't understand why you haven't been slaughtered right at the gates. ...", cid, 5000)
			npcHandler:say("Anyway. Are you prepared to embark on a dangerous mission for us?", cid, 7000)
			npcHandlerfocus = 1
	elseif (msgcontains(msg:lower(),"yes") and npcHandlerfocus == 1) then
				setPlayerStorageValue(cid, 8131, 1)
				npcHandler:say("All right then, human. Have you ever heard of the 'Tears of Daraman'? ...")
				npcHandler:say("They are precious gemstones made of some unknown blue mineral and possess enormous magical power. ...", cid, 3000)
				npcHandler:say("If you want to learn more about these gemstones don't forget to visit our library. ...", cid, 5000)
				npcHandler:say("Anyway, one of them is enough to create thousands of our mighty djinn blades. ...", cid, 7000)
				npcHandler:say("Unfortunately my last gemstone broke and therefore I'm not able to create new blades anymore. ...", cid, 9000)
				npcHandler:say("To my knowledge there is only one place where you can find these gemstones - I know for a fact that the Marid have at least one of them. ...", cid, 11000)
				npcHandler:say("Well... to cut a long story short, your mission is to sneak into Ashta'daramai and to steal it. ...", cid, 13000)
				npcHandler:say("Needless to say, the Marid won't be too eager to part with it. Try not to get killed until you have delivered the stone to me.", cid, 15000)
				npcHandler.focus = cid
				npcHandlerfocus = 4
	elseif (msgcontains(msg:lower(),"no") and npcHandlerfocus == 1) then
				npcHandler:say("I wouldn't expect anything different from a human.")
				npcHandler.focus = cid
				npcHandlerfocus = 0
	elseif (msgcontains(msg:lower(),"mission") and getPlayerStorageValue(cid, 8131) == 1 and getPlayerStorageValue(cid, 10229) ~= 1) then
			npcHandler:say("You still haven't gotten the item I asked for. Go to the blue djinn fortress and bring her back.")
			npcHandler.focus = cid
			npcHandlerfocus = 0
			
	elseif (msgcontains(msg:lower(),"mission") and getPlayerStorageValue(cid, 10229) == 1 and getPlayerStorageValue(cid, 10230) ~= 1) then 		
			npcHandler:say('Did you find the tear of Daraman?')
			npcHandler.focus = cid
			npcHandlerfocus = 2
	elseif (msgcontains(msg:lower(),"yes") and npcHandlerfocus == 2) then
			if getPlayerItemCount(cid, 2346) >= 1 then	
				npcHandler:say("So you have made it? You have really managed to steal a Tear of Daraman? ...")
				npcHandler:say("Amazing how you humans are just impossible to get rid of. Incidentally, you have this character trait in common with many insects and with other vermin. ...", cid, 2000)
				npcHandler:say("Nevermind. I hate to say it, but it you have done us a favour, human. That gemstone will serve us well. ...", cid, 4000)
				npcHandler:say("Baa'leal, wants you to talk to Malor concerning some new mission. ...", cid, 6000)
				npcHandler:say("Looks like you have managed to extended your life expectancy - for just a bit longer.", cid, 8000)
				setPlayerStorageValue(cid, 1032, 1)
				setPlayerStorageValue(cid, 10230, 1)
				doPlayerRemoveItem(cid,2346,1)
				npcHandler.focus = cid
				npcHandlerfocus = 3
			elseif (msgcontains(msg:lower(),"no") and npcHandlerfocus == 2) then
				npcHandler:say("You do not have the Tear of Daraman.")
				npcHandler.focus = cid
				npcHandlerfocus = 0
			end
	elseif (msgcontains(msg:lower(),"mission") and getPlayerStorageValue(cid, 1032) == 1 and getPlayerStorageValue(cid, 10230) == 1) then 
			npcHandler:say("I have no more missions for you. See if Malor has something for you, he's at the top of the tower.")
			npcHandler.focus = cid
			npcHandlerfocus = 0			
	end		
return 1
end


if getPlayerStorageValue(cid, 1038) == 1 then
			local shopModule = ShopModule:new()
				npcHandler:addModule(shopModule)
				npcHandler:addModule(ShopModule:new({'scimitar'}, 2419, 150, 'scimitar'))				
				addSellableItem({'giant sword'}, 2393, 17000, 'giant sword')
				addSellableItem({'serpent sword'}, 2409, 900, 'serpent sword')
				addSellableItem({'poison dagger'}, 2411, 50, 'poison dagger')
				addSellableItem({'knight axe'}, 2430, 2000, 'knight axe')
				addSellableItem({'dragon hammer'}, 2434, 2000, 'dragon hammer')
				addSellableItem({'skull staff'}, 2436, 6000, 'skull staff')
				addSellableItem({'dark armor'}, 2489, 400, 'dark armor')
				addSellableItem({'knight armor'}, 2476, 5000, 'knight armor')
				addSellableItem({'dark helmet'}, 2490, 250, 'dark helmet')
				addSellableItem({'warrior helmet'}, 2475, 5000, 'warrior helmet')
				addSellableItem({'strange helmet'}, 2479, 500, 'strange helmet')
				addSellableItem({'mystic turban'}, 2663, 150, 'mystic turban')
				addSellableItem({'knight legs'}, 2477, 5000, 'knight legs')
				addSellableItem({'tower shield'}, 2528, 8000, 'tower shield')
				addSellableItem({'black shield'}, 2529, 800, 'black shield')
				addSellableItem({'ancient shield'}, 2532, 900, 'ancient shield')
				addSellableItem({'vampire shield'}, 2534, 15000, 'vampire shield')
				addBuyableItem({'ice rapier'}, 2396, 5000, 'ice rapier')
				addBuyableItem({'serpent sword'}, 2409, 6000, 'serpent sword')
				addBuyableItem({'dark armor'}, 2489, 1500, 'dark armor')
				addBuyableItem({'dark helmet'}, 2490, 1000, 'dark helmet')
				addBuyableItem({'ancient shield'}, 2532, 5000, 'ancient shield')	
end	


-- npcHandler:setCallback(SHOPMODULE_MODE_TALK, buysellmodule)
npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, AlesarSayCallback)
-- npcHandler:addModule(FocusModule:new())
npcHandler:addModulealesar(FocusModule:new())

 

 

npchandler.luamodules.lua

alesar.lua

Editado por willks123 (veja o histórico de edições)

Participe da conversa

Você pode postar agora e se cadastrar mais tarde. Se você tem uma conta, faça o login para postar com sua conta.

Visitante
Responder

Quem Está Navegando 0

  • Nenhum usuário registrado visualizando esta página.

Conteúdo Similar

Estatísticas dos Fóruns

  • Tópicos 96.9k
  • Posts 519.7k

Informação Importante

Confirmação de Termo