• 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 Help modifying NPC lib

Dankoo

Active Member
Joined
Sep 4, 2010
Messages
1,007
Reaction score
27
I'm trying to make as players with storage id X have a discount on certains items

I know how to do the storage stuff, but I need to know how can I set an array for items ID, like:

Code:
array = {1,2,3}

if getPlayerStorageValue(cid, 12551) == 1 and item.id is in array then
do something

U know?

LUA:
	-- 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("[ShopModule.onBuy]", "Item not found on shopItems list")
			return false
		end

		if(shopItem.buy == -1) then
			print("[ShopModule.onSell]", "Attempt to purchase an item which only sellable")
			return false
		end

		if(amount <= 0) then
			print("[ShopModule.onSell]", "Attempt to purchase " .. amount .. " items")
			return false
		end

		local backpack, totalCost = 1988, amount * shopItem.buy
		if(inBackpacks) then
			totalCost = totalCost + (math.max(1, math.floor(amount / getContainerCapById(backpack))) * 20)
		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 subType = shopItem.subType 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

			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 * 20)))
				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)
		end
		if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
			self.npcHandler.talkStart[cid] = os.time()
		else
			self.npcHandler.talkStart = os.time()
		end

		return true
	end
 
Last edited:
I'm using 0.4 DEV as distro (My donation time expired), if that's what you'r asking.

PS: While you're helping me I'll refresh my topic twice a second

PS 2: If I'm not mistaken, REV 3884
 
Last edited:
add this at the end of data/lib/npc.lua
LUA:
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
example usage, taken from an NPC script
LUA:
local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)
NpcSystem.parseParameters(npcHandler)
local Topic = {}

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)
	local talkUser = NPCHANDLER_CONVBEHAVIOR == CONVERSATION_DEFAULT and 0 or cid
	if (msgcontains(msg, "hello") or msgcontains(msg, "hi")) and (not npcHandler:isFocused(cid)) then
		npcHandler:say("Hello, ".. getCreatureName(cid) .." and welcome to my little forge.", cid, TRUE)
		npcHandler:addFocus(cid)
	elseif(not npcHandler:isFocused(cid)) then
		return false
	elseif msgcontains(msg, "bye") or msgcontains(msg, "farewell") then
		npcHandler:say("Bye.", cid, TRUE)
		npcHandler:releaseFocus(cid)
	elseif msgcontains(msg, "trade") then
		local items = {
			{name="axe", id=2386, buy=20, sell=7},
			{name="battle hammer", id=2417, buy=350},
			{name="brass armor", id=2465, buy=450, sell=150},
			{name="chain armor", id=2464, buy=200, sell=70},
			{name="chain helmet", id=2458, buy=52, sell=17},
			{name="chain legs", id=2648, buy=80, sell=25},
			{name="dagger", id=2351, buy=5},
			{name="hand axe", id=2380, buy=8, sell=4},
			{name="leather armor", id=2467, buy=35, sell=12},
			{name="leather helmet", id=2461, buy=12},
			{name="mace", id=2398, buy=90, sell=30},
			{name="rapier", id=2384, buy=15, sell=5},
			{name="sabre", id=2385, buy=35, sell=12},
			{name="spear", id=2389, buy=10, sell=3},
			{name="steel shield", id=2509, buy=240, sell=80},
			{name="sword", id=2376, buy=85, sell=25},
			{name="throwing knife", id=2410, buy=25},
			{name="wooden shield", id=2512, buy=15, sell=3},
			{name="battle axe", id=2378, sell=80},
			{name="battle shield", id=2513, sell=95},
			{name="halberd", id=2381, sell=400},
			{name="morning star", id=2394, sell=90},
			{name="plate armor", id=2463, sell=400},
			{name="steel helmet", id=2457, sell=190},
			{name="two handed sword", id=2377, sell=450},
			{name="warmaster's wristguards", id=11316, sell=200}
		}
		if getPlayerStorageValue(cid, 85300) >= 3 then
			table.insert(items, {name="lizard weapon rack kit", id=11120, buy=500})
		end
		if getPlayerStorageValue(cid, 85300) >= 9 then
			table.insert(items, {name="twin hooks", id=11303, buy=1100, sell=500})
			table.insert(items, {name="zaoan halberd", id=11317, buy=1200, sell=500})
			table.insert(items, {name="bone shoulderplate", id=11315, sell=150})
			table.insert(items, {name="broken halberd", id=11329, sell=100})
			table.insert(items, {name="cursed shoulder spikes", id=11321, sell=320})
			table.insert(items, {name="drachaku", id=11302, sell=10000})
			table.insert(items, {name="drakinata", id=11299, sell=10000})
			table.insert(items, {name="draken boots", id=12621, sell=40000})
			table.insert(items, {name="guardian boots", id=11234, sell=35000})
			table.insert(items, {name="high guard's shoulderplates", id=11327, sell=130})
			table.insert(items, {name="legionnaire flags", id=11328, sell=500})
			table.insert(items, {name="sais", id=11300, sell=16500})
			table.insert(items, {name="spiked iron ball", id=11319, sell=100})
			table.insert(items, {name="trashed draken boots", id=12607, sell=40000})
			table.insert(items, {name="twiceslicer", id=12574, sell=28000})
			table.insert(items, {name="wailing widow's necklace", id=11323, sell=3000})
			table.insert(items, {name="zaoan armor", id=11295, sell=14000})
			table.insert(items, {name="zaoan helmet", id=11296, sell=45000})
			table.insert(items, {name="zaoan legs", id=11298, sell=14000})
			table.insert(items, {name="zaoan shoes", id=11297, sell=5000})
			table.insert(items, {name="zaoan sword", id=11301, sell=30000})
			table.insert(items, {name="zaogun's shoulderplates", id=11325, sell=150})
		end
		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, items)
			end
		)
		npcHandler:say("Of course, just browse through my wares.", cid)
	end
	return TRUE
end

npcHandler:setMessage(MESSAGE_WALKAWAY, "Bye.")
npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
no, i asked because thunderion already has the first thing
 
Cyk, I don't know if you got me right.

Here's an example:

LUA:
		if getPlayerStorageValue(cid, XXXX) == -1 and item.id isinarray == TRUE then
		doPlayerRemoveMoney(cid, totalCost )
                elseif getPlayerStorageValue(cid, XXXX) == -1 and item.id isinarray == FALSE then
		doPlayerRemoveMoney(cid, totalCost)
                elseif getPlayerStorageValue(cid, XXXX) == 1 and item.id isinarray == TRUE then
		doPlayerRemoveMoney(cid, totalCost * 0.80)
                elseif getPlayerStorageValue(cid, XXXX) == 1 and item.id isinarray == FALSE then
		doPlayerRemoveMoney(cid, totalCost)
		end
(I've added 4 entries just to be sure it wouldn't bug)
--

I want the player with storage X have discount on all items with ID XXXX sold in every NPC, you got it?

- edit - well, it seems you've gonna sleep, so do I... I'll check the topic tomorrow
 
Last edited:
By editing npc\lib\npcsystem\modules.lua

More precisely, this function I've posted in first topic:

LUA:
 -- 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("[ShopModule.onBuy]", "Item not found on shopItems list")
			return false
		end
 
		if(shopItem.buy == -1) then
			print("[ShopModule.onSell]", "Attempt to purchase an item which only sellable")
			return false
		end
 
		if(amount <= 0) then
			print("[ShopModule.onSell]", "Attempt to purchase " .. amount .. " items")
			return false
		end
 
		local backpack, totalCost = 1988, amount * shopItem.buy
		if(inBackpacks) then
			totalCost = totalCost + (math.max(1, math.floor(amount / getContainerCapById(backpack))) * 20)
		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 subType = shopItem.subType 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
 
			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 * 20)))
				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)
		end
		if(NPCHANDLER_CONVBEHAVIOR ~= CONVERSATION_DEFAULT) then
			self.npcHandler.talkStart[cid] = os.time()
		else
			self.npcHandler.talkStart = os.time()
		end
 
		return true
	end

didn't get it?

-- edit --

Go to the final lines of the script, here's an example:

Instead of:

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

I could use:

LUA:
		local msg = self.npcHandler:getMessage(MESSAGE_BOUGHT)
		local msg_discount = self.npcHandler:getMessage(MESSAGE_BOUGHT_DISCOUNT)
		if getPlayerStorageValue(cid, 12551) == -1 then
		doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, self.npcHandler:parseMessage(msg, parseInfo))
		doPlayerRemoveMoney(cid, totalCost)
		elseif getPlayerStorageValue(cid, 12551) == 1 then
		doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, self.npcHandler:parseMessage(msg_discount, parseInfo))
		doPlayerRemoveMoney(cid, totalCost * 0.80)
		end

But I want to do this with specific items, not every item, got it..?
 
Last edited:
I'll use a example of what Dankoo wants to explain it to you Cyko:

Players who have completed the "postman quest" will be able to buy apple and meat for 20% cheaper.

Apple and meat will be in array.
Players with storage XXX (postman quest completed) will buy those itens in array for 0.80 total coast (20% cheaper)
Players without storage XXX (postman not completed) will buy those itens in array for 1.00 total coast (normal price).
 
Last edited:
I'll use a example of what Dankoo wants to explain it for you Cyko:

Players who have completed the "postman quest" will be able to buy apple and meat for 20% cheaper.

Apple and meat will be in array.
Players with storage XXX (postman quest completed) will buy those itens in array for 0.80 total coast (20% cheaper)
Players without storage XXX (postman not completed) will buy those itens in array for 1.00 total coast (normal price).

You nailed it.
 
Back
Top