• 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!

Lua Npcs, is this possible?

Delvire

°£°
Joined
Feb 24, 2008
Messages
236
Reaction score
9
It's a simple question, I just want to know, if is possible to have more than 1 trading window option in the NPCs, just like in the global Tibia.

For example:

Player: Hi
NPC: Hello, what do you want? Runes or potions?

Then, if the player says "runes", a trading window with runes will be opened else, if he says "potions", only potions will be shown in the trading window

Is this possible?

Thanks
 
Lua:
<?xml version="1.0" encoding="UTF-8"?>
<npc name="Mage Seller" script="data/npc/scripts/runes.lua" walkinterval="2000" floorchange="0">
	<health now="100" max="100"/>
	<look type="133" head="94" body="114" legs="94" feet="94" addons="3"/>
	<parameters>
		<parameter key="message_greet" value="Hello! |PLAYERNAME|. Do you need to buy any {runes} or {potions}. please {trade}."/>
		<parameter key="message_decline" value="Is |TOTALCOST| gold coins too much for you? Get out of here!"/>
	</parameters>
</npc>
 
Lua:
<?xml version="1.0" encoding="UTF-8"?>
<npc name="Mage Seller" script="data/npc/scripts/runes.lua" walkinterval="2000" floorchange="0">
	<health now="100" max="100"/>
	<look type="133" head="94" body="114" legs="94" feet="94" addons="3"/>
	<parameters>
		<parameter key="message_greet" value="Hello! |PLAYERNAME|. Do you need to buy any {runes} or {potions}. please {trade}."/>
		<parameter key="message_decline" value="Is |TOTALCOST| gold coins too much for you? Get out of here!"/>
	</parameters>
</npc>

This is not the problem, Djivar.

I want to know if it's possible to have each trade window for each keyword, for exemple, if I say runes

a trade window is oppened containing only runes, and the same for potions

:|
 
Aawh, okey. i didnt understand the question (A)
note that this is not tested and made in a few mins :p
And im not a good npc scripter :p
Lua:
local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)
NpcSystem.parseParameters(npcHandler)
local talkState = {}

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


local shopModule = ShopModule:new()
npcHandler:addModule(shopModule)

npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)

local node1 = keywordHandler:addKeyword({'potions'},)
shopModule:addBuyableItemContainer({'bp intense healing'}, 2000, 2265, 1900, 25, 'backpack of intense healing rune')
shopModule:addBuyableItemContainer({'bp blank rune'}, 2000, 2260, 200, 25, 'backpack of blank rune')
shopModule:addBuyableItemContainer({'bp mana rune'}, 2000, 2276, 50000, 25, 'backpack of mana rune')
shopModule:addBuyableItemContainer({'bp ultimate healing'}, 2000, 2273, 3500, 25, 'backpack of ultimate healing rune')
shopModule:addBuyableItemContainer({'bp magic wall'}, 2000, 2293, 7000, 25, 'backpack of magic wall rune')
shopModule:addBuyableItemContainer({'bp destroy field'}, 2000, 2261, 900, 25, 'backpack of destroy field rune')
shopModule:addBuyableItemContainer({'bp light magic missile'}, 2000, 2287, 800, 25, 'backpack of light magic missile rune')
shopModule:addBuyableItemContainer({'bp heavy magic missile'}, 2000, 2311, 2400, 25, 'backpack of heavy magic missile rune')
shopModule:addBuyableItemContainer({'bp great fireball'}, 2000, 2304, 3600, 25, 'backpack of great fireball rune')
shopModule:addBuyableItemContainer({'bp explosion'}, 2000, 2313, 5000, 25, 'backpack of explosion rune')
shopModule:addBuyableItemContainer({'bp sudden death'}, 2000, 2268, 6500, 25, 'backpack of sudden death rune')
shopModule:addBuyableItemContainer({'bp mage sd'}, 2000, 2263, 2000000, 100, 'backpack of mage sd rune')
shopModule:addBuyableItemContainer({'bp paralyze'}, 2000, 2278, 14000, 25, 'backpack of paralyze rune')
shopModule:addBuyableItemContainer({'bp animate dead'}, 2000, 2316, 6500, 25, 'backpack of animate dead rune')
shopModule:addBuyableItemContainer({'bp convince creature'}, 2000, 2290, 1600, 25, 'backpack of convince creature rune')
shopModule:addBuyableItemContainer({'bp chameleon'}, 2000, 2291, 4200, 25, 'backpack of chameleon rune')
shopModule:addBuyableItemContainer({'bp desintegrate'}, 2000, 2310, 1600, 25, 'backpack of desintegreate rune')
shopModule:addBuyableItemContainer({'bp icicle'}, 2000, 2271, 2000, 25, 'backpack of icicle rune')
shopModule:addBuyableItemContainer({'bp stalagmite'}, 2000, 2292, 2000, 25, 'backpack of stalagmite rune')
shopModule:addBuyableItemContainer({'bp avalanche'}, 2000, 2274, 2000, 25, 'backpack of avalanche rune')
shopModule:addBuyableItemContainer({'bp stone shower'}, 2000, 2288, 2000, 25, 'backpack of stone shower rune')
shopModule:addBuyableItem({'instense healing'}, 2265, 95, 25, 'intense healing rune')
shopModule:addBuyableItem({'blank rune'}, 2260, 10, 1, 'blank rune')
shopModule:addBuyableItem({'mana rune'}, 2300, 1500, 3, 'mana rune')
shopModule:addBuyableItem({'master mana rune'}, 2276, 2500, 40, 'master mana rune')
shopModule:addBuyableItem({'ultimate healing'}, 2273, 175, 25, 'ultimate healing rune')
shopModule:addBuyableItem({'magic wall'}, 2293, 350, 25, 'magic wall rune')
shopModule:addBuyableItem({'destroy field'}, 2261, 45, 25, 'destroy field rune')
shopModule:addBuyableItem({'light magic missile'}, 2287, 40, 25, 'light magic missile rune')
shopModule:addBuyableItem({'heavy magic missile'}, 2311, 120, 25, 'heavy magic missile rune')
shopModule:addBuyableItem({'great fireball'}, 2304, 180, 25, 'great fireball rune')
shopModule:addBuyableItem({'explosion'}, 2313, 250, 25, 'explosion rune')
shopModule:addBuyableItem({'sudden death'}, 2268, 350, 25, 'sudden death rune')
shopModule:addBuyableItem({'mage sd'}, 2263, 100000, 100, 'mage sd rune')
shopModule:addBuyableItem({'creat bomb'}, 2264, 100000, 25, 'creat bomb rune')
shopModule:addBuyableItem({'paralyze'}, 2278, 700, 25, 'paralyze rune')
shopModule:addBuyableItem({'animate dead'}, 2316, 375, 25, 'animate dead rune')
shopModule:addBuyableItem({'convince creature'}, 2290, 80, 25, 'convince creature rune')
shopModule:addBuyableItem({'chameleon'}, 2291, 210, 25, 'chameleon rune')
shopModule:addBuyableItem({'desintegrate'}, 2310, 80,  25, 'desintegreate rune')
shopModule:addBuyableItem({'icicle'}, 2271, 100,  25, 'icicle rune')
shopModule:addBuyableItem({'stalagmite'}, 2292, 100,  25, 'stalagmite rune')
shopModule:addBuyableItem({'avalanche'}, 2274, 100,  25, 'avalanche rune')
shopModule:addBuyableItem({'stone shower'}, 2288, 100,  25, 'stone shower rune')
 
 
local node2 = keywordHandler:addKeyword({'runes'},)

shopModule:addBuyableItemContainer({'bp slhp'}, 2000, 8704, 400, 1, 'backpack of small health potions')
shopModule:addBuyableItemContainer({'bp hp'}, 2000, 7618, 900, 1, 'backpack of health potions')
shopModule:addBuyableItemContainer({'bp mp'}, 2001, 7620, 1000, 1, 'backpack of mana potions')
shopModule:addBuyableItemContainer({'bp shp'}, 2000, 7588, 2000, 1, 'backpack of strong health potions')
shopModule:addBuyableItemContainer({'bp smp'}, 2001, 7589, 1600, 1, 'backpack of strong mana potions')
shopModule:addBuyableItemContainer({'bp ghp'}, 2000, 7591, 6800, 1, 'backpack of great health potions')
shopModule:addBuyableItemContainer({'bp gmp'}, 2001, 7590, 6800, 1, 'backpack of great mana potions')
shopModule:addBuyableItemContainer({'bp gsp'}, 1999, 8472, 6800, 1, 'backpack of great spirit potions')
shopModule:addBuyableItemContainer({'bp uhp'}, 2000, 8473, 6200, 1, 'backpack of ultimate health potions')
shopModule:addBuyableItemContainer({'bp ap'}, 2002, 8474, 2000, 1, 'backpack of antidote potions')
shopModule:addBuyableItem({'small health'}, 8704, 20, 1, 'small health potion')
shopModule:addBuyableItem({'health potion'}, 7618, 45, 1, 'health potion')
shopModule:addBuyableItem({'mana potion'}, 7620, 50, 1, 'mana potion')
shopModule:addBuyableItem({'strong health'}, 7588, 100, 1, 'strong health potion')
shopModule:addBuyableItem({'strong mana'}, 7589, 80, 1, 'strong mana potion')
shopModule:addBuyableItem({'great health'}, 7591, 190, 1, 'great health potion')
shopModule:addBuyableItem({'great mana'}, 7590, 120, 1, 'great mana potion')
shopModule:addBuyableItem({'great spirit'}, 8472, 190, 1, 'great spirit potion')
shopModule:addBuyableItem({'ultimate health'}, 8473, 310, 1, 'ultimate health potion')
shopModule:addBuyableItem({'antidote potion'}, 8474, 50, 1, 'antidote potion')
shopModule:addSellableItem({'normal potion flask', 'normal flask'}, 7636, 5, 'empty small potion flask')
shopModule:addSellableItem({'strong potion flask', 'strong flask'}, 7634, 10, 'empty strong potion flask')
shopModule:addSellableItem({'great potion flask', 'great flask'}, 7635, 15, 'empty great potion flask') 
 

 
npcHandler:addModule(FocusModule:new())
 
Code:
local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)
NpcSystem.parseParameters(npcHandler)

local Topic = {}
local windows = {
	['potions'] = {
		{name="letter",	id=2597, buy=8}
	}
}
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 creatureSayCallback(cid, type, msg)
	if (msgcontains(msg, "hello") or msgcontains(msg, "hi")) and (not npcHandler:isFocused(cid)) then
		npcHandler:say("Oh, please come in, " .. getCreatureName(cid) .. ". If you need magical equipment such as runes or wands, just ask me for a {trade}.", cid)
		Topic[cid] = 0
		npcHandler:addFocus(cid)
	elseif(not npcHandler:isFocused(cid)) then
		return false
	elseif msgcontains(msg, "bye") or msgcontains(msg, "farewell") then
		npcHandler:say("Good bye and come again.", cid, TRUE)
		Topic[cid] = nil
		npcHandler:releaseFocus(cid)
	elseif msgcontains(msg, "trade") then
		local items = {{name="parcel", id=2595, buy=15}}
		openShopWindow(cid, items,
			function(cid, itemid, subType, amount, ignoreCap, inBackpacks)
				customCallbackOnBuy(cid, itemid, subType, amount, ignoreCap, inBackpacks, items)
			end,
			function(cid, itemid, subType, amount, ignoreCap, inBackpacks)
				customCallbackOnSell(cid, itemid, subType, amount, ignoreCap, inBackpacks)
			end
		)
		npcHandler:say("Of course, just browse through my wares. Or do you want to look only at {potions}, {wands} or {runes}?", cid)
		Topic[cid] = 1
	elseif Topic[cid] == 1 then
		if msgcontains(msg, 'potions') then
			local items = windows['potions']
			openShopWindow(cid, items,
			function(cid, itemid, subType, amount, ignoreCap, inBackpacks)
				customCallbackOnBuy(cid, itemid, subType, amount, ignoreCap, inBackpacks, items)
			end,
			function(cid, itemid, subType, amount, ignoreCap, inBackpacks)
				customCallbackOnSell(cid, itemid, subType, amount, ignoreCap, inBackpacks)
			end
			)
			npcHandler:say("Have a look. You can also look at {wands} or {runes}.", cid)
		end
	end
	return TRUE
end

npcHandler:setMessage(MESSAGE_WALKAWAY, "Good bye.")
npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
This goes in data/npc/lib/npc.lua:
Code:
	function customCallbackOnBuy(cid, itemid, subType, amount, ignoreCap, inBackpacks, shopWindow)
		local shopItem, npcHandler = nil, NpcHandler
		for _, item in ipairs(shopWindow) do
			if not item.subType then
				item.subType = (isItemFluidContainer(item.id) == TRUE or isItemStackable(item.id) == TRUE) and 0 or 1
			end
			if(item.id == itemid and (item.subType == subType)) then
				shopItem = item
				break
			end
		end

		if(shopItem == nil) then
			error("[ShopModule.onBuy]", "Item not found on shopItems list")
			return false
		end

		if(shopItem.buy < 0) then
			error("[ShopModule.onSell]", "Attempt to purchase an item which is only sellable")
			return false
		end

		local backpack, totalCost = 1988, amount * shopItem.buy
		if(inBackpacks) then
			totalCost = isItemStackable(itemid) == TRUE and totalCost + 20 or totalCost + (math.max(1, math.floor(amount / getContainerCapById(backpack))) * 20)
		end

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

		local subType = shopItem.subType or isItemFluidContainer(itemid) == TRUE and 0 or 1
		local a, b = doNpcSellItem(cid, itemid, amount, subType, ignoreCap, inBackpacks, backpack)
		if(a < amount) then
			local msgId = MESSAGE_NEEDMORESPACE
			if(a == 0) then
				msgId = MESSAGE_NEEDSPACE
			end

			doPlayerSendCancel(cid, npcHandler:parseMessage(npcHandler:getMessage(msgId), {[TAG_PLAYERNAME] = getPlayerName(cid), [TAG_ITEMCOUNT] = amount, [TAG_TOTALCOST] = totalCost, [TAG_ITEMNAME] = shopItem.name, [TAG_ITEMCOUNT] = a}))

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

			return false
		end
		doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, npcHandler:parseMessage(npcHandler:getMessage(MESSAGE_BOUGHT), {[TAG_PLAYERNAME] = getPlayerName(cid), [TAG_ITEMCOUNT] = amount, [TAG_TOTALCOST] = totalCost, [TAG_ITEMNAME] = shopItem.name}))
		doPlayerRemoveMoney(cid, totalCost)

		return true
	end
	
	function customCallbackOnSell(cid, itemid, subType, amount, ignoreCap, inBackpacks, shopWindow)
		local shopItem, npcHandler, subType = nil, NpcHandler, subType or 0
		for _, item in ipairs(shopWindow) do
			item.subType = not item.subType and 0 or item.subType
			if(item.id == itemid and (isItemFluidContainer(itemid) == FALSE or isItemFluidContainer(itemid) == TRUE and item.subType == subType)) then
				shopItem = item
				break
			end
		end

		if(shopItem == nil) then
			error("[ShopModule.onBuy]", "Item not found on shopItems list")
			return false
		end

		if(shopItem.sell < 0) then
			error("[ShopModule.onSell]", "Attempt to sell an item which is only buyable")
			return false
		end

		if(doPlayerRemoveItem(cid, itemid, amount, isItemFluidContainer(itemid) == TRUE and subType or isItemStackable(itemid) == TRUE and amount or 1) == TRUE) then
			doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, npcHandler:parseMessage(npcHandler:getMessage(MESSAGE_SOLD), {[TAG_PLAYERNAME] = getPlayerName(cid), [TAG_ITEMCOUNT] = amount, [TAG_TOTALCOST] = amount * shopItem.sell, [TAG_ITEMNAME] = shopItem.name}))
			doPlayerAddMoney(cid, amount * shopItem.sell)

			return true
		end
		doPlayerSendCancel(cid, npcHandler:parseMessage(npcHandler:getMessage(MESSAGE_NEEDITEM), {[TAG_PLAYERNAME] = getPlayerName(cid), [TAG_ITEMCOUNT] = amount, [TAG_TOTALCOST] = amount * shopItem.sell, [TAG_ITEMNAME] = shopItem.name}))

		return false
	end
Edit: Ow, this only works on 0.2
Requires source editing on 0.3.x :/ because shop window does not open properly 2nd time.
 
Last edited:
Bump #2

@Cykotitan

I have the 0.3, but anyways, it would be utile for those who use the Mystic Spirit, i think that someone, or maybe you, should make a thread teaching people how to do it :B
 
You have to edit source

Here's a modified 0.3.6pl1:
http://www.speedy*****malware.localhost/files/22512822/TheForgottenServer.rar
how did i know it would be Cykotitan to figure it out :p

Shes got us half fixed guys, keep it rollin!
&
Its not so hard because he is the best of the best? ;O
As a matter of fact, I already had a similar system working.
 
Last edited:
thanks cykotitan, I was testing your script on my 0.3.6pl1, and it was a bit buggy, but working :)

Well, thanks to anyone who helped or tried to help me

Rep ++ to Cykotitan
 
Back
Top