Below is a new items.lua for lua_modules.
This supports stacked items and quests that require multiples of the same item (stacked or unstacked). It changes the check_turn_in call syntax slightly to support this, but gives full support for clients handing in a mix of stacked and unstacked items and properly crediting the quest results.
Example code using this module:
Code:
function event_trade(e)
local item_lib = require("items")
local pfaction = e.other:GetFaction(e.self)
while item_lib.check_turn_in(e.trade, {[13717] = 1}) do -- Rat Head
e.self:QuestSay(e.other, "Thank you for helping reduce the rat population! Here is your reward...")
if (pfaction < 5) then -- only give money to friendly folks
e.other:GiveCash(math.random(10),math.random(2),0,0)
end -- everyone gets faction hits and XP though
e.other:Faction(1,1,0)
e.other:Faction(2,-1,0)
e.other:AddEXP(35)
end
item_lib.return_items(e.self, e.other, e.trade)
end
Code:
local items = {}
function items.check_turn_in(trade, trade_check)
--create trade_return table == trade
--shallow copy
local trade_return = {};
for key, value in pairs(trade) do
trade_return[key] = value;
end
-- trade_check contains item_id => qty mapping
-- for each item handed to us, check if it is in trade_check
for i = 1, 4 do
local inst = trade_return["item" .. i] -- get an item instance that was handed to us
if(inst.valid and trade_check[inst:GetID()] > 0) then -- we have a valid item and it's ID is in the trade_check map
if (inst:IsStackable()) then
while (trade_check[inst:GetID()] > 0 and inst:GetCharges() >= trade_check[inst:GetID()]) do
inst:SetCharges(inst:GetCharges() - 1) -- remove one item from the stack
trade_check[inst:GetID()] = trade_check[inst:GetID()] - 1 -- decrement the count of required items in trade_check
end
if (inst:GetCharges() > 0) then -- still have items in the stack, return the remainder
trade_return["item" .. i] = inst
else
trade_return["item" .. i] = ItemInst() -- stack empty, return nothing
end
else
trade_return["item" .. i] = ItemInst() -- remove this item from our return queue
trade_check[inst:GetID()] = trade_check[inst:GetID()] - 1 -- decrement the count of required items in trade_check
end
end
end
local items_left = 0;
for key,value in pairs(trade_check) do
if (key ~= "platinum" and key ~= "gold" and key ~= "silver" and key ~= "copper" and value > 0) then
items_left = items_left + value
end
end
if (items_left > 0) then return false end -- we didn't find all of our items
--convert our money into copper then check that we have enough then convert change back
local trade_check_money = 0;
local return_money = 0;
if(trade_check["platinum"] ~= nil and trade_check["platinum"] ~= 0) then
trade_check_money = trade_check_money + (trade_check["platinum"] * 1000);
end
if(trade_check["gold"] ~= nil and trade_check["gold"] ~= 0) then
trade_check_money = trade_check_money + (trade_check["gold"] * 100);
end
if(trade_check["silver"] ~= nil and trade_check["silver"] ~= 0) then
trade_check_money = trade_check_money + (trade_check["silver"] * 10);
end
if(trade_check["copper"] ~= nil and trade_check["copper"] ~= 0) then
trade_check_money = trade_check_money + trade_check["copper"];
end
return_money = return_money + trade_return["platinum"] * 1000 + trade_return["gold"] * 100;
return_money = return_money + trade_return["silver"] * 10 + trade_return["copper"];
if(return_money < trade_check_money) then
return false;
else
return_money = return_money - trade_check_money;
end
--replace trade with trade_return
trade.item1 = trade_return.item1
trade.item2 = trade_return.item2
trade.item3 = trade_return.item3
trade.item4 = trade_return.item4
trade.platinum = math.floor(return_money / 1000)
return_money = return_money - (trade.platinum * 1000)
trade.gold = math.floor(return_money / 100)
return_money = return_money - (trade.gold * 100)
trade.silver = math.floor(return_money / 10)
return_money = return_money - (trade.silver * 10)
trade.copper = return_money
return true
end
function items.return_items(npc, client, trade, text)
text = text or true
local returned = false
for i = 1, 4 do
local inst = trade["item" .. i]
if(inst.valid) then
if(eq.is_disc_tome(inst:GetID()) and npc:GetClass() > 19 and npc:GetClass() < 36) then
if(client:GetClass() == npc:GetClass() - 19) then
client:TrainDisc(inst:GetID())
else
npc:Say(string.format("You are not a member of my guild. I will not train you!"))
client:PushItemOnCursor(inst)
returned = true
end
else
client:PushItemOnCursor(inst)
if(text == true) then
npc:Say(string.format("I have no need for this %s, you can have it back.", client:GetCleanName()))
end
returned = true
end
end
end
local money = false
if(trade.platinum ~= 0) then
returned = true
money = true
end
if(trade.gold ~= 0) then
returned = true
money = true
end
if(trade.silver ~= 0) then
returned = true
money = true
end
if(trade.copper ~= 0) then
returned = true
money = true
end
if(money == true) then
client:AddMoneyToPP(trade.copper, trade.silver, trade.gold, trade.platinum, true)
end
return returned
end
return items