added trade list

This commit is contained in:
Sokomine 2021-05-29 03:55:36 +02:00
parent 0652cf7f5a
commit d75b94c99d
6 changed files with 277 additions and 44 deletions

View File

@ -25,3 +25,7 @@ yl_speak_up.infotext = "Rightclick to talk"
yl_speak_up.max_number_of_buttons = 7
-- how many buttons can be added to one dialog?
yl_speak_up.max_number_of_options_per_dialog = 15
-- how many rows and cols shall be used for the trade overview list?
yl_speak_up.trade_max_rows = 10
yl_speak_up.trade_max_cols = 4

View File

@ -1744,6 +1744,9 @@ minetest.register_on_player_receive_fields( function(player, formname, fields)
elseif formname == "yl_speak_up:inventory" then
yl_speak_up.input_inventory(player, formname, fields)
return true
elseif formname == "yl_speak_up:trade_list" then
yl_speak_up.input_trade_list(player, formname, fields)
return true
elseif formname == "yl_speak_up:do_trade_simple" then
yl_speak_up.input_do_trade_simple(player, formname, fields)
return true
@ -1762,6 +1765,12 @@ yl_speak_up.input_inventory = function(player, formname, fields)
-- after closing the inventory formspec:
-- ..save the (very probably) modified inventory
yl_speak_up.save_npc_inventory(n_id)
-- show the trade list?
if(fields.inventory_show_tradelist) then
minetest.show_formspec(pname, "yl_speak_up:trade_list",
yl_speak_up.get_fs_trade_list(player))
return
end
-- ..and go back to the normal talk formspec
minetest.show_formspec(pname, "yl_speak_up:talk",
yl_speak_up.get_fs_talkdialog(player, n_id, d_id))

View File

@ -21,6 +21,8 @@ dofile(modpath .. "privs.lua")
dofile(modpath .. "inventory.lua")
-- trade one item(stack) against one other item(stack)
dofile(modpath .. "trade_simple.lua")
-- easily accessible list of all trades the NPC offers
dofile(modpath .. "trade_list.lua")
-- the main functionality of the mod
dofile(modpath .. "functions.lua")
-- the staffs (requires npc_master priv)

View File

@ -48,11 +48,12 @@ yl_speak_up.get_fs_inventory = function(player)
"label[2,-0.2;Inventory of "..minetest.formspec_escape(dialog.n_npc)..
" (ID: "..tostring(n_id).."):]"..
"list[detached:yl_speak_up_npc_"..tostring(n_id)..";npc_main;0,0.3;12,6;]" ..
"list[current_player;main;2,6.85;8,1;]" ..
"list[current_player;main;2,8.08;8,3;8]" ..
"list[current_player;main;2,7.05;8,1;]" ..
"list[current_player;main;2,8.28;8,3;8]" ..
"listring[detached:yl_speak_up_npc_"..tostring(n_id)..";npc_main]" ..
"listring[current_player;main]" ..
"button[10.0,10.2;2,0.9;back_from_inventory;Back]"
"button[4.5,6.35;3,0.6;inventory_show_tradelist;Show all trades]"..
"button[10.0,10.4;2,0.9;back_from_inventory;Back]"
end

129
trade_list.lua Normal file
View File

@ -0,0 +1,129 @@
-- show a list of all trades
-- the player is accessing the trade list
yl_speak_up.input_trade_list = function(player, formname, fields)
local pname = player:get_player_name()
local d_id = yl_speak_up.speak_to[pname].d_id
local n_id = yl_speak_up.speak_to[pname].n_id
local dialog = yl_speak_up.speak_to[pname].dialog
if(not(dialog.trades)) then
dialog.trades = {}
end
-- the player wants to add a new trade
if(fields.trade_list_add_trade) then
-- show the trade config dialog for a new trade
minetest.show_formspec(pname, "yl_speak_up:add_trade_simple",
yl_speak_up.get_fs_trade_simple(player, "new"))
return
end
-- go back to the main dialog
if(fields.finished_trading) then
minetest.show_formspec(pname, "yl_speak_up:talk",
yl_speak_up.get_fs_talkdialog(player, n_id, d_id))
return
end
-- normal mode: the player wants to see a particular trade
for k,v in pairs(dialog.trades) do
if(fields[ k ]) then
minetest.show_formspec(pname, "yl_speak_up:do_trade_simple",
yl_speak_up.get_fs_trade_simple(player, k))
return
end
end
-- TODO: and otherwise?
end
-- show a list of all trades the NPC has to offer
yl_speak_up.get_fs_trade_list = function(player)
if(not(player)) then
return ""
end
local pname = player:get_player_name()
-- which NPC is the player talking to?
local n_id = yl_speak_up.speak_to[pname].n_id
local dialog = yl_speak_up.speak_to[pname].dialog
-- do we have all the necessary data?
if(not(n_id) or not(dialog.n_npc)) then
return "size[6,2]"..
"label[0.2,0.5;Ups! This NPC lacks ID or name.]"..
"button_exit[2,1.5;1,0.9;exit;Exit]"
end
-- make sure the NPC has that table defined
if(not(dialog.trades)) then
dialog.trades = {}
end
yl_speak_up.load_npc_inventory(n_id)
local npc_inv = minetest.get_inventory({type="detached", name="yl_speak_up_npc_"..tostring(n_id)})
local formspec = {}
-- arrange the offers in yl_speak_up.trade_max_cols columns horizontally
-- and yl_speak_up.trade_max_rows row vertically
local row = 0
local col = 0
local anz_trades = 0
-- TODO: handle multiple pages?
for k, v in pairs(dialog.trades) do
if(col < yl_speak_up.trade_max_cols
and v.pay and v.pay[1] and v.pay[1] ~= "" and v.buy and v.buy[1] and v.buy[1] ~= "") then
local pay_stack = ItemStack(v.pay[1])
local buy_stack = ItemStack(v.buy[1])
-- do not show trades with nonexistant items
if( not(minetest.registered_items[ pay_stack:get_name() ])
or not(minetest.registered_items[ buy_stack:get_name() ])) then
break
end
anz_trades = anz_trades + 1
local kstr = tostring(minetest.formspec_escape(k))
table.insert(formspec,
"item_image_button["..tostring(1+(col*4))..","..tostring(1+row)..";1,1;"..
tostring(v.pay[1])..";"..kstr..";]"..
"image_button["..tostring(1.8+(col*4))..","..tostring(1+row)..";1,1;"..
"gui_furnace_arrow_bg.png^[transformR270;"..kstr..";]"..
"item_image_button["..tostring(2.6+(col*4))..","..tostring(1+row)..";1,1;"..
tostring(v.buy[1])..";"..kstr..";]")
row = row + 1
if(row > yl_speak_up.trade_max_rows) then
row = 0
col = col + 1
end
if(not(npc_inv:contains_item("npc_main", buy_stack))) then
table.insert(formspec,
"label["..tostring(1.7+(col*4))..","..tostring(0.2+row)..";Sold out]")
end
end
end
-- if there are no trades, at least print a hint that there could be some here
-- (a mostly empty formspec looks too boring and could irritate players)
if(anz_trades == 0) then
table.insert(formspec,
"label[1,1;Sorry. There are currently no offers available.]")
end
-- button "add trade" for those who can edit the NPC
if((yl_speak_up.edit_mode[pname] == yl_speak_up.speak_to[pname].n_id)
and (yl_speak_up.speak_to[pname].n_id)) then
table.insert(formspec,
"button["..tostring(yl_speak_up.trade_max_cols * 4 - 2.2)..
",0.2;2.0,0.9;trade_list_add_trade;Add trade]")
end
return "size["..
tostring(yl_speak_up.trade_max_cols * 4)..","..
tostring(yl_speak_up.trade_max_rows + 2).."]"..
"button[0.2,0.0;2.0,0.9;finished_trading;Back to talk]"..
"label[3.0,0.2;"..tostring(dialog.n_npc).." offers you these trades:]"..
table.concat(formspec, "")
end

View File

@ -22,6 +22,13 @@ yl_speak_up.input_do_trade_simple = function(player, formname, fields)
-- which trade are we talking about?
local trade = yl_speak_up.trade[pname]
-- show the trade list
if(fields.back_to_trade_list) then
minetest.show_formspec(pname, "yl_speak_up:trade_list",
yl_speak_up.get_fs_trade_list(player))
return
end
-- can the player edit this trade?
if(fields.edit_trade_simple
and (yl_speak_up.edit_mode[pname] == yl_speak_up.speak_to[pname].n_id
@ -52,6 +59,11 @@ yl_speak_up.input_do_trade_simple = function(player, formname, fields)
if(fields.abort_trade_simple or fields.quit or fields.finished_trading) then
local d_id = yl_speak_up.speak_to[pname].d_id
local n_id = yl_speak_up.speak_to[pname].n_id
if(trade.trade_is_trade_list) then
minetest.show_formspec(pname, "yl_speak_up:talk",
yl_speak_up.get_fs_talkdialog(player, n_id, d_id))
return
end
-- if in edit mode: go back to the edit options dialog
if(yl_speak_up.edit_mode[pname] == yl_speak_up.speak_to[pname].n_id
and (yl_speak_up.speak_to[pname].n_id)) then
@ -138,39 +150,51 @@ yl_speak_up.input_add_trade_simple = function(player, formname, fields)
else
-- get the necessary dialog data
local dialog = yl_speak_up.speak_to[pname].dialog
-- does this option have a trade result already?
local r_id = yl_speak_up.get_result_id_by_type(dialog, d_id, o_id, "trade")
-- no trade stored for that option yet? -> create new result
if(not(r_id)) then
r_id = yl_speak_up.add_new_result(dialog, d_id, o_id)
end
-- construct the text information for r_value
local trade_text = "npc_gives: \""..
buy:get_name().." "..tostring(buy:get_count())..
"\" player_gives: \""..
pay:get_name().." "..tostring(pay:get_count())..
"\""
-- player_gives (pay stack):
local ps = pay:get_name().." "..tostring(pay:get_count())
-- npc_gives (buy stack):
local bs = buy:get_name().." "..tostring(buy:get_count())
local r_id = "?"
-- is this a trade attached to the trade list?
if(trade.trade_is_trade_list) then
-- if the player adds the same trade again, the ID is reused; other
-- than that, the ID is uniq
local trade_id = "trade "..ps.." for "..bs
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Trade: Added offer "..tostring(trade_id)..".")
dialog.trades[ trade_id ] = {pay={ps},buy={bs}}
-- is this a trade stored as a result of an option?
else
-- does this option have a trade result already?
r_id = yl_speak_up.get_result_id_by_type(dialog, d_id, o_id, "trade")
-- no trade stored for that option yet? -> create new result
if(not(r_id)) then
r_id = yl_speak_up.add_new_result(dialog, d_id, o_id)
end
-- construct the text information for r_value
local trade_text = "npc_gives: \""..bs.."\" player_gives: \""..ps.."\""
-- store the new result
dialog.n_dialogs[d_id].d_options[o_id].o_results[r_id] = {
r_id = r_id,
r_type = "trade",
r_value = trade_text,
-- additional data for easier parsing of the trade
r_player_gives = pay:get_name().." "..tostring(pay:get_count()),
r_npc_gives = buy:get_name().." "..tostring(buy:get_count()),
r_trade_type = "trade_simple",
}
-- store the new result
dialog.n_dialogs[d_id].d_options[o_id].o_results[r_id] = {
r_id = r_id,
r_type = "trade",
r_value = trade_text,
-- additional data for easier parsing of the trade
r_player_gives = ps,
r_npc_gives = bs,
r_trade_type = "trade_simple",
}
-- record this as a change
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": Trade "..tostring(r_id).." added to option "..
tostring(o_id)..".")
end
-- update temporal trade information
trade.trade_type = "trade_simple"
trade.player_gives = pay:get_name().." "..tostring(pay:get_count())
trade.npc_gives = buy:get_name().." "..tostring(buy:get_count())
trade.player_gives = ps
trade.npc_gives = bs
-- finished editing
trade.edit_trade = nil
-- record this as a change
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": Trade "..tostring(r_id).." added to option "..
tostring(o_id)..".")
-- do not return yet - the items still need to be given back!
error_msg = nil
end
@ -186,9 +210,15 @@ yl_speak_up.input_add_trade_simple = function(player, formname, fields)
-- we need a way of deleting trades as well
elseif(fields.delete_trade_simple) then
-- delete this result (if it exists)
if(trade.r_id) then
-- get the necessary dialog data
local dialog = yl_speak_up.speak_to[pname].dialog
-- get the necessary dialog data
local dialog = yl_speak_up.speak_to[pname].dialog
if(trade.trade_type == "trade_list" and trade.trade_id) then
-- record this as a change
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Trade: Deleted offer "..tostring(trade.trade_id)..".")
-- delete this particular trade and update the IDs in the array
dialog.trades[ trade.trade_id ] = nil
elseif(trade.r_id) then
-- record this as a change
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": Trade "..tostring(r_id).." deleted from option "..
@ -217,6 +247,14 @@ yl_speak_up.input_add_trade_simple = function(player, formname, fields)
"size[6,2]"..
"label[0.2,0.5;The new trade has been configured successfully.]"..
"button[1.5,1.5;2,0.9;trade_simple_stored;Show trade]")
-- return back to trade list
elseif(not(trade.o_id)) then
-- we are no longer trading
yl_speak_up.trade[pname] = nil
-- ..else go back to the edit options formspec
minetest.show_formspec(pname, "yl_speak_up:trade_list",
yl_speak_up.get_fs_trade_list(player))
return
else
-- we are no longer trading
yl_speak_up.trade[pname] = nil
@ -313,13 +351,40 @@ end
-- simple trade: one item(stack) for another
-- handles configuration of new trades and showing the formspec for trades;
-- checks if payment and buying is possible
yl_speak_up.get_fs_trade_simple = function(player)
yl_speak_up.get_fs_trade_simple = function(player, trade_id)
if(not(player)) then
return yl_speak_up.trade_fail_fs
end
local pname = player:get_player_name()
-- which trade are we talking about?
local trade = yl_speak_up.trade[pname]
if(trade_id) then
local d_id = yl_speak_up.speak_to[pname].d_id
local n_id = yl_speak_up.speak_to[pname].n_id
local dialog = yl_speak_up.speak_to[pname].dialog
trade = {
-- we start with the simple trade
trade_type = "trade_simple",
-- can be determined from other variables, but it is easier to store it here
n_id = n_id,
npc_name = dialog.n_npc,
-- for statistics and in order to determine which dialog to show next
trade_done = 0,
-- we need to know which option this is
target_dialog = d_id,
trade_is_trade_list = true
}
if(dialog.trades[ trade_id ]) then
trade.player_gives = dialog.trades[ trade_id ].pay[1]
trade.npc_gives = dialog.trades[ trade_id ].buy[1]
else
trade.edit_trade = true
end
yl_speak_up.trade[pname] = trade
end
-- do we have all the necessary data?
if(not(trade) or trade.trade_type ~= "trade_simple") then
return yl_speak_up.trade_fail_fs
@ -370,10 +435,20 @@ yl_speak_up.get_fs_trade_simple = function(player)
-- show edit button for the owner if in edit_mode
if(yl_speak_up.may_edit_npc(player, trade.n_id)
and (yl_speak_up.edit_mode[pname] == yl_speak_up.speak_to[pname].n_id)) then
formspec = formspec..
"button[0.2,1.6;0.8,0.9;edit_trade_simple;Edit]"..
"tooltip[edit_trade_simple;Edit this trade. You can do so only "..
"if you can edit the NPC as such (i.e. own it).]"
-- for trades as part of the results/effects: allow edit
if(not(trade.trade_is_trade_list)) then
formspec = formspec..
"button[0.2,1.6;1.0,0.9;edit_trade_simple;Edit]"..
"tooltip[edit_trade_simple;Edit this trade. You can do so only "..
"if you can edit the NPC as such (i.e. own it).]"
-- for trades in trade list: allow delete (new trades can easily be added)
else
-- TODO: make this button work
formspec = formspec..
"button[0.2,1.6;1.2,0.9;delete_trade_simple;Delete]"..
"tooltip[delete_trade_simple;Delete this trade. You can do so only "..
"if you can edit the NPC as such (i.e. own it).]"
end
end
local trade_possible_msg = "Status of trade: Unknown."
@ -425,6 +500,23 @@ yl_speak_up.get_fs_trade_simple = function(player)
"free inventory space to store your purchase.]"
end
-- the functionality of the back button depends on context
if(not(trade.trade_is_trade_list)) then
-- go back to the right dialog (or forward to the next one)
formspec = formspec..
-- "button[6.2,1.6;2.0,0.9;finished_trading;Back to talk]"..
"button[0.2,0.0;2.0,0.9;finished_trading;Back to talk]"..
"tooltip[finished_trading;Click here once you've traded enough with this "..
"NPC and want to get back to talking.]"
else
-- go back to the trade list
-- TODO: make this button work
formspec = formspec..
"button[0.2,0.0;2.0,0.9;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.]"
end
return formspec..
"label[2.5,0.0;Trading with "..minetest.formspec_escape(trade.npc_name).."]"..
"label[1.5,0.7;You pay:]"..
@ -438,11 +530,7 @@ yl_speak_up.get_fs_trade_simple = function(player)
"list[detached:yl_speak_up_player_"..pname..";pay;2,2.0;1,1;]" ..
-- show the buy slot from the same inventory
"list[detached:yl_speak_up_player_"..pname..";buy;5,2.0;1,1;]" ..
"label[1.5,3.0;"..trade_possible_msg.."]"..
"button[0.2,0.0;2.0,0.9;finished_trading;Back to talk]"..
-- "button[6.2,1.6;2.0,0.9;finished_trading;Back to talk]"..
"tooltip[finished_trading;Click here once you've traded enough with this "..
"NPC and want to get back to talking.]"
"label[1.5,3.0;"..trade_possible_msg.."]"
end