Trade: Add function to store trade offers on NPC data based on the trading status.

Add support to avoid flipping sold items out of stock to buy immediately.
This commit is contained in:
zorman2000 2017-02-01 11:36:20 -05:00
parent b3b9bf393f
commit d8b90d95c3
2 changed files with 102 additions and 50 deletions

48
npc.lua
View File

@ -381,16 +381,16 @@ local function choose_spawn_items(self)
minetest.log("Initial inventory: "..dump(self.inventory)) minetest.log("Initial inventory: "..dump(self.inventory))
end end
-- Creates new single buy and sell offers for NPCs that -- -- Creates new single buy and sell offers for NPCs that
-- trade casually. -- -- trade casually.
local function select_casual_trade_offers(self) -- local function select_casual_trade_offers(self)
self.trader_data.buy_offers = { -- self.trader_data.buy_offers = {
[1] = npc.trade.get_casual_trade_offer(self, npc.trade.OFFER_BUY) -- [1] = npc.trade.get_casual_trade_offer(self, npc.trade.OFFER_BUY)
} -- }
self.trader_data.sell_offers = { -- self.trader_data.sell_offers = {
[1] = npc.trade.get_casual_trade_offer(self, npc.trade.OFFER_SELL) -- [1] = npc.trade.get_casual_trade_offer(self, npc.trade.OFFER_SELL)
} -- }
end -- end
-- Spawn function. Initializes all variables that the -- Spawn function. Initializes all variables that the
-- NPC will have and choose random, starting values -- NPC will have and choose random, starting values
@ -464,13 +464,18 @@ local function npc_spawn(self, pos)
-- It is mostly related to its occupation. -- It is mostly related to its occupation.
-- If empty, the NPC will revert to casual trading -- If empty, the NPC will revert to casual trading
-- If not, it will try to sell those that it have, and buy the ones it not. -- If not, it will try to sell those that it have, and buy the ones it not.
trade_list = {} trade_list = {
sell = {},
buy = {},
both = {}
}
} }
-- Initialize trading offers if NPC is casual trader -- Initialize trading offers for NPC
if ent.trader_data.trader_status == npc.trade.CASUAL then --npc.trade.generate_trade_offers_by_status(ent)
select_casual_trade_offers(ent) -- if ent.trader_data.trader_status == npc.trade.CASUAL then
end -- select_casual_trade_offers(ent)
-- end
-- Actions data -- Actions data
ent.actions = { ent.actions = {
@ -526,14 +531,13 @@ local function npc_spawn(self, pos)
end end
-- Dedicated trade test -- Dedicated trade test
ent.trader_data.trade_list = { ent.trader_data.trade_list.both = {
"default:tree", ["default:tree"] = {},
"default:cobble", ["default:cobble"] = {},
"default:wood" ["default:wood"] = {}
} }
local trade_offers = npc.trade.get_trade_offers_for_dedicated_trader(ent) npc.trade.generate_trade_offers_by_status(ent)
minetest.log("Trade offers: "..dump(trade_offers))
-- npc.add_action(ent, npc.action.stand, {self = ent}) -- npc.add_action(ent, npc.action.stand, {self = ent})
-- npc.add_action(ent, npc.action.stand, {self = ent}) -- npc.add_action(ent, npc.action.stand, {self = ent})

View File

@ -22,7 +22,7 @@ npc.trade.CASUAL_TRADE_BUY_DIALOGUE = {
casual_trade_type = npc.trade.OFFER_BUY, casual_trade_type = npc.trade.OFFER_BUY,
responses = { responses = {
[1] = { [1] = {
text = "Yes, let's see what you are looking for", text = "Sell",
action_type = "function", action_type = "function",
response_id = 1, response_id = 1,
action = function(self, player) action = function(self, player)
@ -38,7 +38,7 @@ npc.trade.CASUAL_TRADE_SELL_DIALOGUE = {
casual_trade_type = npc.trade.OFFER_SELL, casual_trade_type = npc.trade.OFFER_SELL,
responses = { responses = {
[1] = { [1] = {
text = "Yes, let's see what you have", text = "Buy",
action_type = "function", action_type = "function",
response_id = 1, response_id = 1,
action = function(self, player) action = function(self, player)
@ -122,6 +122,38 @@ function npc.trade.get_random_trade_status()
end end
end end
-- This function generates and stores on the NPC data trade
-- offers depending on the trader status.
function npc.trade.generate_trade_offers_by_status(self)
-- Get trader status
local status = self.trader_data.trader_status
-- Check what is the trader status
if status == npc.trade.NONE then
-- For none, clear all offers
self.trader_data.buy_offers = {}
self.trader_data.sell_offers = {}
elseif status == npc.trade.CASUAL then
-- For casual, generate one buy and one sell offer
self.trader_data.buy_offers = {
[1] = npc.trade.get_casual_trade_offer(self, npc.trade.OFFER_BUY)
}
self.trader_data.sell_offers = {
[1] = npc.trade.get_casual_trade_offer(self, npc.trade.OFFER_SELL)
}
elseif status == npc.trade.TRADER then
-- Get trade offers for a dedicated trader
local offers = npc.trade.get_dedicated_trade_offers(self)
-- Store buy offers
for i = 1, #offers.buy do
table.insert(self.trader_data.buy_offers, offers.buy[i])
end
-- Store sell offers
for i = 1, #offers.sell do
table.insert(self.trader_data.sell_offers, offers.sell[i])
end
end
end
-- Convenience method that retrieves all the currency -- Convenience method that retrieves all the currency
-- items that a NPC has on his/her inventory -- items that a NPC has on his/her inventory
function npc.trade.get_currencies_in_inventory(self) function npc.trade.get_currencies_in_inventory(self)
@ -198,43 +230,59 @@ end
-- based on the trader list and the source of items. Initially, it will only -- based on the trader list and the source of items. Initially, it will only
-- be NPC inventories. In the future, it should support both NPC and chest -- be NPC inventories. In the future, it should support both NPC and chest
-- inventories, -- inventories,
function npc.trade.get_trade_offers_for_dedicated_trader(self) function npc.trade.get_dedicated_trade_offers(self)
local offers = { local offers = {
for_sell = {}, sell = {},
to_buy = {} buy = {}
} }
for i = 1, #self.trader_data.trade_list do local trade_list = self.trader_data.trade_list.both
for item_name, trade_info in pairs(trade_list) do
-- For each item on the trader list, check if it is in the NPC inventory. -- For each item on the trader list, check if it is in the NPC inventory.
-- If it is, create a sell offer, else create a buy offer if possible. -- If it is, create a sell offer, else create a buy offer if possible.
local item = npc.inventory_contains(self, self.trader_data.trade_list[i]) local item = npc.inventory_contains(self, item_name)
if item ~= nil then if item ~= nil then
-- Create sell offer for this item. Currently, traders will offer to sell only -- Create sell offer for this item. Currently, traders will offer to sell only
-- of their items to allow the fine control for players to buy what they want. -- of their items to allow the fine control for players to buy what they want.
-- This requires, however, that the trade offers are re-generated everytime a -- This requires, however, that the trade offers are re-generated everytime a
-- sell is made. -- sell is made.
table.insert(offers.for_sell, npc.trade.create_offer(npc.trade.OFFER_SELL, self.trader_data.trade_list[i], nil, nil, 1)) table.insert(offers.sell, npc.trade.create_offer(
npc.trade.OFFER_SELL,
item_name,
nil,
nil,
1)
)
-- Set last offer type
trade_info.last_offer_type = npc.trade.OFFER_SELL
else else
-- Create buy offer for this item -- Avoid flipping an item to the buy side if the stock was just depleted
-- Only do if the NPC can actually afford the items. if trade_info.last_offer_type ~= npc.trade.OFFER_SELL then
local currencies = npc.trade.get_currencies_in_inventory(self) -- Create buy offer for this item
-- Choose a random currency -- Only do if the NPC can actually afford the items.
local chosen_tier = currencies[math.random(#currencies)] local currencies = npc.trade.get_currencies_in_inventory(self)
-- Get items for this currency -- Choose a random currency
local buyable_items = local chosen_tier = currencies[math.random(#currencies)]
npc.trade.prices.get_items_for_currency_count(chosen_tier.name, chosen_tier.count, 0.5) -- Get items for this currency
-- Check if the item from trader list is present in the buyable items list local buyable_items =
for buyable_item, price_info in pairs(buyable_items) do npc.trade.prices.get_items_for_currency_count(chosen_tier.name, chosen_tier.count, 0.5)
if buyable_item == self.trader_data.trade_list[i] then -- Check if the item from trader list is present in the buyable items list
-- If item found, create a buy offer for this item for buyable_item, price_info in pairs(buyable_items) do
-- Again, offers are created for one item only. Buy offers should be removed if buyable_item == item_name then
-- after the NPC has bought a certain quantity, say, 5 items. -- If item found, create a buy offer for this item
table.insert(offers.to_buy, npc.trade.create_offer( -- Again, offers are created for one item only. Buy offers should be removed
npc.trade.OFFER_BUY, -- after the NPC has bought a certain quantity, say, 5 items.
self.trader_data.trade_list[i], table.insert(offers.buy, npc.trade.create_offer(
price_info.price, npc.trade.OFFER_BUY,
price_info.min_buyable_item_price, item_name,
1)) price_info.price,
price_info.min_buyable_item_price,
price_info.min_buyable_item_count)
)
-- Set last offer type
trade_info.last_offer_type = npc.trade.OFFER_BUY
end
end end
end end
end end