show stock in trade_via_buy_button

This commit is contained in:
Sokomine 2022-09-09 06:30:07 +02:00
parent d5fe15a7c7
commit 7adabf312d
2 changed files with 135 additions and 41 deletions

View File

@ -12,25 +12,57 @@ yl_speak_up.get_trade_item_desc = function(item)
end
-- helper function; returns how often a trade can be done
-- stock_buy how much of the buy stack does the NPC have in storage?
-- stock_pay how much of the price stack does the NPC have in storage?
-- buy_stack stack containing the item the NPC sells
-- pay_stack stack containing the price for said item
-- min_storage how many items of the buy stack items shall the NPC keep?
-- max_storage how many items of the pay stack items can the NPC accept?
yl_speak_up.get_trade_amount_available = function(stock_buy, stock_pay, buy_stack, pay_stack, min_storage, max_storage)
local stock = 0
-- the NPC shall not sell more than this
if(min_storage and min_storage > 0) then
stock_buy = math.max(0, stock_buy - min_storage)
end
stock = math.floor(stock_buy / buy_stack:get_count())
-- the NPC shall not buy more than this
if(max_storage and max_storage < 10000) then
stock_pay = math.min(max_storage - stock_pay, 10000)
stock = math.min(stock, math.floor(stock_pay / pay_stack:get_count()))
end
return stock
end
-- helper function; also used by trade_list.lua
yl_speak_up.get_sorted_trade_id_list = function(dialog)
yl_speak_up.get_sorted_trade_id_list = function(dialog, show_dialog_option_trades)
-- make sure all fields exist
yl_speak_up.setup_trade_limits(dialog)
local keys = {}
for k, v in pairs(dialog.trades) do
if(k ~= "limits" and k ~= "") then
-- structure of the indices: sell name amount for name amount
local parts = string.split(k, " ")
if(parts and #parts == 6 and parts[4] == "for"
and v.pay and v.pay[1] ~= "" and v.pay[1] == parts[5].." "..parts[6]
and v.buy and v.buy[1] ~= "" and v.buy[1] == parts[2].." "..parts[3]
and minetest.registered_items[parts[5]]
and minetest.registered_items[parts[2]]
and tonumber(parts[6]) > 0
and tonumber(parts[3]) > 0) then
if(show_dialog_option_trades) then
for k, v in pairs(dialog.trades) do
if(k ~= "limits" and k ~= "" and v.d_id) then
table.insert(keys, k)
end
end
else
for k, v in pairs(dialog.trades) do
if(k ~= "limits" and k ~= "") then
-- structure of the indices: sell name amount for name amount
local parts = string.split(k, " ")
if(parts and #parts == 6 and parts[4] == "for"
and v.pay and v.pay[1] ~= "" and v.pay[1] == parts[5].." "..parts[6]
and v.buy and v.buy[1] ~= "" and v.buy[1] == parts[2].." "..parts[3]
and minetest.registered_items[parts[5]]
and minetest.registered_items[parts[2]]
and tonumber(parts[6]) > 0
and tonumber(parts[3]) > 0) then
table.insert(keys, k)
end
end
end
end
table.sort(keys)
return keys
@ -42,13 +74,13 @@ yl_speak_up.input_trade_via_buy_button = function(player, formname, fields)
if(fields.buy_directly) then
local trade_id = yl_speak_up.speak_to[pname].trade_id
local error_msg = yl_speak_up.check_trade_via_buy_button(player, trade_id, true)
local res = yl_speak_up.check_trade_via_buy_button(player, trade_id, true)
if(error_msg ~= "OK") then
if(res.msg ~= "OK") then
yl_speak_up.show_fs(player, "msg", {
input_to = "yl_speak_up:trade_via_buy_button",
formspec = "size[6,2.5]"..
"label[0.2,-0.2;"..error_msg.."\nTrade aborted.]"..
"label[0.2,-0.2;"..res.msg.."\nTrade aborted.]"..
"button[2,1.5;1,0.9;back_from_error_msg;Back]"})
return
end
@ -80,8 +112,23 @@ yl_speak_up.input_trade_via_buy_button = function(player, formname, fields)
end
-- TODO: delete button if(fields.delete_trade_via_buy_button) then
-- the owner wants to go back to the trade list from a dialog trade (action) view
if(fields.back_to_trade_list_dialog_trade) then
yl_speak_up.show_fs(player, "trade_list", true)
return
-- a dialog trade (action) was displayed; go back to the corresponding dialog
elseif(fields.back_to_dialog) then
local pname = player:get_player_name()
local n_id = yl_speak_up.speak_to[pname].n_id
local dialog = yl_speak_up.speak_to[pname].dialog
local trade_id = yl_speak_up.speak_to[pname].trade_id
local new_d_id = dialog.trades[ trade_id ].d_id
yl_speak_up.speak_to[pname].d_id = new_d_id
yl_speak_up.speak_to[pname].trade_list = {}
yl_speak_up.show_fs(player, "talk") -- TODO parameters
return
-- show the trade list
if(fields.back_to_trade_list or fields.quit
elseif(fields.back_to_trade_list or fields.quit
or not(yl_speak_up.speak_to[pname].trade_id)) then
yl_speak_up.show_fs(player, "trade_list")
return
@ -96,6 +143,7 @@ end
-- if do_trade is false: check only if the trade would be possible and return
-- error message if not; return "OK" when trade is possible
-- if do_trade is true: if possible, execute the trade; return the same as above
-- also returns how many times the trade could be done (stock= ..)
yl_speak_up.check_trade_via_buy_button = function(player, trade_id, do_trade)
local pname = player:get_player_name()
local n_id = yl_speak_up.speak_to[pname].n_id
@ -108,11 +156,11 @@ yl_speak_up.check_trade_via_buy_button = function(player, trade_id, do_trade)
-- the NPCs' inventory
local npc_inv = minetest.get_inventory({type="detached", name="yl_speak_up_npc_"..tostring(n_id)})
if(not(this_trade)) then
return "Trade not found."
return {msg = "Trade not found.", stock=0}
elseif(not(player_inv)) then
return "Couldn't find player's inventory."
return {msg = "Couldn't find player's inventory.", stock=0}
elseif(not(npc_inv)) then
return "Couldn't find the NPC's inventory."
return {msg = "Couldn't find the NPC's inventory.", stock=0}
end
-- store which trade we're doing
yl_speak_up.speak_to[pname].trade_id = trade_id
@ -125,47 +173,62 @@ yl_speak_up.check_trade_via_buy_button = function(player, trade_id, do_trade)
-- can the NPC provide his part?
if(not(npc_inv:contains_item("npc_main", buy_stack))) then
return "Out of stock" --"Sorry. "..npc_name.." ran out of stock.\nPlease come back later."
return {msg = "Out of stock", stock = 0}
-- return {msg = "Sorry. "..npc_name.." ran out of stock.\nPlease come back later.", stock=0}
-- has the NPC room for the payment?
elseif(not(npc_inv:room_for_item("npc_main", pay_stack))) then
return npc_name.." has no room left!"
return {npc_name.." has no room left!", stock = 0}
-- return "Sorry. "..npc_name.." ran out of inventory space.\n"..
-- "There is no room to store your payment!"
end
local counted_npc_inv = yl_speak_up.count_npc_inv(n_id)
local stock_pay = counted_npc_inv[ pay_stack:get_name() ] or 0
local stock_buy = counted_npc_inv[ buy_stack:get_name() ] or 0
-- are there any limits which we have to take into account?
local min_storage = dialog.trades.limits.sell_if_more[ buy_stack:get_name() ]
local max_storage = dialog.trades.limits.buy_if_less[ pay_stack:get_name() ]
if((min_storage and min_storage > 0)
or (max_storage and max_storage < 10000)) then
local counted_npc_inv = yl_speak_up.count_npc_inv(n_id)
local stock_pay = counted_npc_inv[ pay_stack:get_name() ] or 0
local stock_buy = counted_npc_inv[ buy_stack:get_name() ] or 0
-- trade limit: is enough left after the player buys the item?
if( min_storage and min_storage > stock_buy - buy_stack:get_count()) then
return "Sorry. "..npc_name.." currently does not want to\nsell that much."..
-- return "Stock too low. Only "..tostring(stock_buy)..
-- " left, want to keep "..tostring(min_storage).."."
return {msg = "Sorry. "..npc_name.." currently does not want to\nsell that much."..
" Current stock: "..tostring(stock_buy)..
" (min: "..tostring(min_storage).."). Perhaps later?"
" (min: "..tostring(min_storage).."). Perhaps later?",
stock = 0}
-- trade limit: make sure the bought amount does not exceed the desired maximum
elseif(max_storage and max_storage < stock_pay + pay_stack:get_count()) then
return "Sorry. "..npc_name.." currently does not want to\n"..
return {msg = "Sorry. "..npc_name.." currently does not want to\n"..
"buy that much."..
" Current stock: "..tostring(stock_pay)..
" (max: "..tostring(max_storage).."). Perhaps later?"
" (max: "..tostring(max_storage).."). Perhaps later?",
stock = 0}
end
-- the NPC shall not sell more than this
if(min_storage and min_storage > 0) then
stock_buy = math.max(0, stock_buy - min_storage)
end
end
-- how often can this trade be done?
local stock = yl_speak_up.get_trade_amount_available(
stock_buy, stock_pay,
buy_stack, pay_stack,
min_storage, max_storage)
-- can the player pay?
if(not(player_inv:contains_item("main", pay_stack))) then
-- both slots will remain empty
return "You can't pay the price."
return {msg = "You can't pay the price.", stock = stock}
elseif(not(player_inv:room_for_item("main", buy_stack))) then
-- the player has no room for the sold item; give a warning
return "You don't have enough free inventory\nspace to store your purchase."
return {msg = "You don't have enough free inventory\nspace to store your purchase.",
stock = stock}
end
-- was it a dry run to check if the trade is possible?
if(not(do_trade)) then
return "OK"
return {msg = "OK", stock = stock}
end
-- actually do the trade
@ -177,7 +240,7 @@ yl_speak_up.check_trade_via_buy_button = function(player, trade_id, do_trade)
-- revert the trade
player_inv:add_item("main", payment)
npc_inv:add_item("npc_main", sold)
return "Sorry. "..npc_name.." accepts only undammaged items."
return {msg = "Sorry. "..npc_name.." accepts only undammaged items.", stock = stock}
end
player_inv:add_item("main", sold)
npc_inv:add_item("npc_main", payment)
@ -194,7 +257,7 @@ yl_speak_up.check_trade_via_buy_button = function(player, trade_id, do_trade)
yl_speak_up.log_change(pname, n_id,
"bought "..tostring(pay_stack:to_string())..
" for "..tostring(buy_stack:to_string()))
return "OK"
return {msg = "OK", stock = stock}
end
@ -261,12 +324,37 @@ yl_speak_up.get_fs_trade_via_buy_button = function(player, trade_id)
buy_name,
"]",
"image[3.5,2.0;1,1;gui_furnace_arrow_bg.png^[transformR270]",
-- go back to the trade list
"button[0.2,0.0;8.0,1.0;back_to_trade_list;Back to list]"..
"tooltip[back_to_trade_list;Click here once you've traded enough with this "..
"NPC and want to get back to the trade list.]"
}
if(not(dialog.trades[ trade_id ].d_id)) then
-- go back to the trade list
table.insert(formspec, "button[0.2,0.0;8.0,1.0;back_to_trade_list;Back to trade list]")
table.insert(formspec, "tooltip[back_to_trade_list;"..
"Click here once you've traded enough with this "..
"NPC and want to get back to the trade list.]")
elseif(true) then
-- go back to the trade list
table.insert(formspec, "button[0.2,0.0;3.8,1.0;back_to_trade_list_dialog_trade;Back to trade list]")
table.insert(formspec, "tooltip[back_to_trade_list_dialog_trade;"..
"Click here once you've traded enough with this "..
"NPC and want to get back to the trade list.]")
-- go back to dialog
table.insert(formspec, "button[4.2,0.0;3.8,1.0;back_to_dialog;Back to dialog ")
table.insert(formspec, minetest.formspec_escape(dialog.trades[ trade_id ].d_id))
table.insert(formspec, "]")
table.insert(formspec, "tooltip[back_to_dialog;"..
"Click here once you've traded enough with this "..
"NPC and want to get back to talking with the NPC.]")
else
-- go back to dialog
table.insert(formspec, "button[0.2,0.0;8.0,1.0;back_to_dialog;Back to dialog ")
table.insert(formspec, minetest.formspec_escape(dialog.trades[ trade_id ].d_id))
table.insert(formspec, "]")
table.insert(formspec, "tooltip[back_to_dialog;"..
"Click here once you've traded enough with this "..
"NPC and want to get back to talking with the NPC.]")
end
-- show edit button for the owner if in edit_mode
if(yl_speak_up.may_edit_npc(player, n_id)) then
-- for trades in trade list: allow delete (new trades can easily be added)
@ -280,8 +368,8 @@ yl_speak_up.get_fs_trade_via_buy_button = function(player, trade_id)
end
-- dry-run: test if the trade can be done
local trade_possible = yl_speak_up.check_trade_via_buy_button(player, trade_id, false)
if(trade_possible == "OK") then
local res = yl_speak_up.check_trade_via_buy_button(player, trade_id, false)
if(res.msg == "OK") then
local buy_str = "Buy"
local trade_done = yl_speak_up.speak_to[pname].trade_done
if(trade_done and trade_done > 0) then
@ -297,12 +385,18 @@ yl_speak_up.get_fs_trade_via_buy_button = function(player, trade_id)
table.insert(formspec, "style_type[button;bgcolor=#FF4444]"..
"button[0.2,3.5;8.0,1.0;back_from_error_msg;")
-- table.insert(formspec, "label[0.5,3.5;")
table.insert(formspec, trade_possible)
table.insert(formspec, res.msg)
table.insert(formspec, ']')
-- set the background color for the next buttons back to our normal one
table.insert(formspec, 'style_type[button;bgcolor=#a37e45]')
-- table.insert(formspec, "label[6.5,2.0;Trade not\npossible.]")
end
-- how often can this trade be repeated?
if(res.stock and res.stock > 0) then
table.insert(formspec, "label[6.5,2.0;Trade ")
table.insert(formspec, tostring(res.stock))
table.insert(formspec, " x\navailable]")
end
table.insert(formspec, "container_end[]"..
"real_coordinates[true]"..

View File

@ -109,7 +109,7 @@ yl_speak_up.get_fs_trade_list = function(player, show_dialog_option_trades)
-- the order in which the trades appear shall not change each time;
-- but lua cannot sort the keys of a table by itself...
-- this function can be found in fs_trade_via_button.lua
local sorted_trades = yl_speak_up.get_sorted_trade_id_list(dialog)
local sorted_trades = yl_speak_up.get_sorted_trade_id_list(dialog, show_dialog_option_trades)
yl_speak_up.speak_to[pname].trade_id_list = sorted_trades
for i, k in ipairs(sorted_trades) do