added yl_speak_up.get_fs_add_trade_simple; trades are now always stored in dialog.trades instead of as results of options of dialogs

This commit is contained in:
Sokomine 2021-05-30 01:43:46 +02:00
parent 7c8ccd066f
commit 0c9d547401
2 changed files with 162 additions and 211 deletions

View File

@ -24,7 +24,7 @@ yl_speak_up.npc_was_changed = {}
-- format: yl_speak_up.npc_owner[ npc_id ] = owner_name
yl_speak_up.npc_owner = {}
-- store the current trade between player and npc
-- store the current trade between player and npc in case it gets edited in the meantime
yl_speak_up.trade = {}
function yl_speak_up.init_mob_table()
@ -847,7 +847,6 @@ yl_speak_up.get_fs_edit_option_dialog = function(player, n_id, d_id, o_id)
-- and build the list of effects
local list_of_effects = ""
local results = d_option.o_results
local has_trade = false
if(results) then
for k, v in pairs(results) do
if v.r_type == "dialog" and dialog.n_dialogs[v.r_value] ~= nil then
@ -858,24 +857,27 @@ yl_speak_up.get_fs_edit_option_dialog = function(player, n_id, d_id, o_id)
minetest.formspec_escape(v.r_id)..",#FFFF00,"..
minetest.formspec_escape(v.r_type)..","..
minetest.formspec_escape(v.r_value)..","
if(v.r_type == "trade") then
has_trade = v
end
end
end
end
-- trade is one of the very few effects players can set
local button_add_edit_trade = ""
if(has_trade) then
if(dialog and dialog.trades and dialog.trades[ tostring(d_id).." "..tostring(o_id)]) then
button_add_edit_trade = ""..
"button[14.8,10;2.0,0.9;effect_show_trade;Show trade]"..
"tooltip[effect_show_trade;Show and edit the trade that starts "..
"when selectiong this option.]"
"when selecting this option.]"
-- show the trade in the result/effects list
list_of_effects = list_of_effects..
",#FFFF00,trade,"..
-- show a reasonable overview of what is traded for what
minetest.formspec_escape("TODO")..","
else
button_add_edit_trade = ""..
"button[14.8,10;2.0,0.9;effect_add_trade;Add trade]"..
"tooltip[effect_add_trade;Add a trade that will start "..
"when selectiong this option.]"
"when selecting this option.]"
end
-- if no target dialog has been selected: default is to go to the dialog with d_sort 0
@ -2713,65 +2715,31 @@ yl_speak_up.input_edit_option_dialog = function(player, formname, fields)
yl_speak_up.get_fs_edit_option_dialog(player, n_id, d_id, o_found))
return
elseif(fields.effect_add_trade
or fields.effect_show_trade) then
local r_id = yl_speak_up.get_result_id_by_type(dialog, d_id, fields.o_id, "trade")
local data = dialog.n_dialogs[d_id].d_options[fields.o_id].o_results[r_id]
-- which dialog shall be shown in case of a successful trade?
local target_d_id = yl_speak_up.get_result_id_by_type(dialog, d_id, fields.o_id, "dialog")
-- we are dealing with a new trade
if(not(r_id) or not(data) or not(data.r_trade_type)) then
yl_speak_up.trade[pname] = {
-- we start with the simple trade
trade_type = "trade_simple",
-- we will create a new trade
player_gives = nil,
npc_gives = nil,
-- 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
o_id = fields.o_id,
r_id = r_id,
edit_trade = true,
target_dialog = target_d_id,
}
-- show the trade config dialog
-- add or edit the trade associated with this dialog and option
elseif(fields.effect_add_trade) then
-- remember which option was selected
yl_speak_up.speak_to[pname].o_id = o_id
-- do not switch target dialog (we are in edit mode)
yl_speak_up.speak_to[pname].target_d_id = nil
-- create a new trade for this dialog and option - with ID "<d_id> <o_id>"
minetest.show_formspec(pname, "yl_speak_up:add_trade_simple",
yl_speak_up.get_fs_trade_simple(player))
yl_speak_up.get_fs_add_trade_simple(player,
tostring(d_id).." "..tostring(o_id)))
return
end
-- identify the right result and trade items
-- TODO: this may not be a simple trade but instead a more complex one
yl_speak_up.trade[pname] = {
-- trade_simple is a fallback
trade_type = data.r_trade_type,
-- we will create a new trade
player_gives = data.r_player_gives,
npc_gives = data.r_npc_gives,
-- 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
o_id = fields.o_id,
r_id = r_id,
target_dialog = target_d_id,
}
-- show the trade dialog
-- show the trade associated with this dialog and option
elseif(fields.effect_show_trade) then
-- remember which option was selected
yl_speak_up.speak_to[pname].o_id = o_id
-- do not switch target dialog (we are in edit mode)
yl_speak_up.speak_to[pname].target_d_id = nil
-- show the trade with ID "<d_id> <o_id>"
minetest.show_formspec(pname, "yl_speak_up:do_trade_simple",
yl_speak_up.get_fs_trade_simple(player))
yl_speak_up.get_fs_trade_simple(player,
tostring(d_id).." "..tostring(o_id)))
return
end
--minetest.chat_send_player(pname, "Fields: "..minetest.serialize(fields))
-- if ESC is pressed or anything else unpredicted happens: go back to the main dialog edit window
-- reason: don't loose any unsaved changes to the dialog
minetest.show_formspec(pname, "yl_speak_up:talk",
@ -3098,8 +3066,6 @@ yl_speak_up.input_talk = function(player, formname, fields)
-- which dialog do we have to show next? default: keep this one
local target_dialog = d_id
-- currently not trading; but a new trade may be started here
yl_speak_up.trade[pname] = nil
-- Let's do something if results exist
if d_option.o_results ~= nil then
@ -3230,38 +3196,18 @@ yl_speak_up.input_talk = function(player, formname, fields)
if v.r_type == "auto" then
say("auto forward")
end
if v.r_type == "trade" then
-- prepare a trade
-- TODO: this may not be a simple trade but instead a more complex one
yl_speak_up.trade[pname] = {
-- trade_simple is a fallback
trade_type = v.r_trade_type,
-- we will create a new trade
player_gives = v.r_player_gives,
npc_gives = v.r_npc_gives,
-- 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
o_id = o,
-- we are iterateing over the results right now; the key k is what we need
r_id = k,
-- we do not know yet which target dialog to choose; it may have
-- shown up already or come later on in this loop
target_dialog = d_id,
}
end
end -- end of loop over d_option.o_results
-- if there is a trade in the results/effects, show that trade now
if(yl_speak_up.trade[pname]) then
-- we now know the right arget dialog for this trade
yl_speak_up.trade[pname].target_dialog = target_dialog
-- if there is a trade associated with this dialog and option, show that trade now
local trade_id = tostring(d_id).." "..tostring(o_id)
if(dialog.trades and dialog.trades[ trade_id ]) then
-- remember which option was selected
yl_speak_up.speak_to[pname].o_id = o_id
-- which dialog shall be shown in case of a successful trade?
yl_speak_up.speak_to[pname].target_d_id = target_dialog
-- show the trade dialog
minetest.show_formspec(pname, "yl_speak_up:do_trade_simple",
yl_speak_up.get_fs_trade_simple(player))
yl_speak_up.get_fs_trade_simple(player, trade_id))
return
end

View File

@ -85,30 +85,31 @@ yl_speak_up.input_do_trade_simple = function(player, formname, fields)
-- go back to the main dialog
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
minetest.show_formspec(pname, "yl_speak_up:edit_option_dialog",
yl_speak_up.get_fs_edit_option_dialog(player, n_id, d_id, trade.o_id))
return
end
local d_id = yl_speak_up.speak_to[pname].d_id
local o_id = yl_speak_up.speak_to[pname].o_id
local target_dialog = d_id
-- if at least one successful trade has happened: show the target dialog
-- (else show the current dialog again)
if(trade.trade_done > 0) then
d_id = trade.target_dialog
if(trade and trade.trade_done > 0 and yl_speak_up.speak_to[pname].target_d_id) then
target_dialog = yl_speak_up.speak_to[pname].target_d_id
end
-- show either the current or the target dialog
minetest.show_formspec(pname, "yl_speak_up:talk",
yl_speak_up.get_fs_talkdialog(player, n_id, d_id))
-- done trading
yl_speak_up.speak_to[pname].target_d_id = nil
yl_speak_up.speak_to[pname].trade_id = nil
-- if in edit mode: go back to the edit options dialog
if(yl_speak_up.edit_mode[pname] == n_id and n_id and o_id) then
-- go to the edit options dialog
minetest.show_formspec(pname, "yl_speak_up:edit_option_dialog",
yl_speak_up.get_fs_edit_option_dialog(player, n_id, d_id, o_id))
return
-- show either the current or the target dialog
elseif(target_dialog) then
minetest.show_formspec(pname, "yl_speak_up:talk",
yl_speak_up.get_fs_talkdialog(player, n_id, target_dialog))
return
end
end
-- show this formspec again
@ -117,6 +118,56 @@ yl_speak_up.input_do_trade_simple = function(player, formname, fields)
end
-- simple trade: add a new trade or edit existing one (by storing a new one);
-- set trade_id to "new" if it shall be a new trade added to the trade list;
-- set trade_id to "<d_id> <o_id>" if it shall be a result/effect of a dialog option;
yl_speak_up.get_fs_add_trade_simple = function(player, trade_id)
if(not(player)) then
return yl_speak_up.trade_fail_fs
end
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
-- is this player allowed to edit the NPC and his trades? If not abort.
if(not(yl_speak_up.may_edit_npc(player, n_id)) or not(dialog) or not(dialog.n_npc)) then
return formspec..
"label[2.0,1.8;Ups! Something went wrong.]"..
"button[6.2,1.6;2.0,0.9;abort_trade_simple;Back]"
end
-- store the trade_id (so that it doesn't have to be transfered in a hidden field)
yl_speak_up.speak_to[pname].trade_id = trade_id
local delete_button =
"button[0.2,2.6;1.0,0.9;delete_trade_simple;Delete]"..
"tooltip[delete_trade_simple;Delete this trade.]"
-- no point in deleting a new trade - it doesn't exist yet
if(trade_id and trade_id == "new") then
delete_button = ""
end
return "size[8.5,8]"..
"label[4.35,0.7;"..minetest.formspec_escape(dialog.n_npc).." sells:]"..
"list[current_player;main;0.2,3.85;8,1;]"..
"list[current_player;main;0.2,5.08;8,3;8]"..
-- show the second slot of the setup inventory in the detached player's inv
"list[detached:yl_speak_up_player_"..pname..";setup;2,1.5;1,1;]"..
-- show the second slot of said inventory
"list[detached:yl_speak_up_player_"..pname..";setup;5,1.5;1,1;1]"..
"label[2.5,0.0;Configure trade with "..minetest.formspec_escape(dialog.n_npc)..":]"..
"label[1.5,0.8;The customer pays:]"..
"label[1.5,2.8;Put items in the two slots and click on \"Store trade\".]"..
"label[1.5,3.2;You will get your items back when storing the trade.]"..
"button[0.2,1.6;1.0,0.9;abort_trade_simple;Abort]"..
delete_button..
"button[6.2,1.6;2.0,0.9;store_trade_simple;Store trade]"..
"tooltip[store_trade_simple;Click here to store this as a new trade. Your\n"..
"items will be returned to you and the trade will\n"..
"will be shown the way the customer can see it.]"..
"tooltip[abort_trade_simple;Abort setting up this new trade.]"
end
-- the player wants to add a simple trade; handle formspec input
-- possible inputs:
-- fields.back_from_error_msg show this formspec here again
@ -136,40 +187,39 @@ yl_speak_up.input_add_trade_simple = function(player, formname, fields)
-- a chat message while viewing a formspec; thus, we showed a formspec message)
if(fields.back_from_error_msg) then
minetest.show_formspec(pname, "yl_speak_up:add_trade_simple",
yl_speak_up.get_fs_trade_simple(player))
yl_speak_up.get_fs_add_trade_simple(player))
return
end
-- which trade are we talking about?
local trade = yl_speak_up.trade[pname]
local trade_id = yl_speak_up.speak_to[pname].trade_id
-- clicking on abort here when adding a new trade via the trade list
-- goes back to the trade list (does not require special privs)
if(fields.abort_trade_simple and trade and trade.trade_id and trade.trade_id == "new") then
-- we are no longer trading
yl_speak_up.trade[pname] = nil
if(fields.abort_trade_simple and trade_id == "new") then
-- we are no longer doing a particular trade
yl_speak_up.speak_to[pname].trade_id = 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
end
-- adding a new trade via the trade list?
if(not(trade_id) and fields.store_trade_simple) then
trade_id = "new"
end
local n_id = yl_speak_up.speak_to[pname].n_id
local d_id = yl_speak_up.speak_to[pname].d_id
local o_id = yl_speak_up.speak_to[pname].o_id
-- the trade can only be changed in edit mode
if(yl_speak_up.edit_mode[pname] ~= yl_speak_up.speak_to[pname].n_id
or not(yl_speak_up.speak_to[pname].n_id)) then
local dialog = yl_speak_up.speak_to[pname].dialog
if((not(n_id) or yl_speak_up.edit_mode[pname] ~= n_id)
-- exception: when adding a new trade via the trade list
-- (that is allowed without having to be in edit mode)
if(not(yl_speak_up.may_edit_npc(player, trade.n_id))
or not(dialog) or not(dialog.trades)
or not(trade.trade_id) or trade.trade_id ~= "new") then
return 0
and not(trade_id == "new" and yl_speak_up.may_edit_npc(player, n_id))) then
return
end
end
local d_id = yl_speak_up.speak_to[pname].d_id
local n_id = yl_speak_up.speak_to[pname].n_id
local o_id = trade.o_id
-- this also contains the inventory list "setup" where the player placed the items
local trade_inv = minetest.get_inventory({type="detached", name="yl_speak_up_player_"..pname})
@ -202,52 +252,40 @@ yl_speak_up.input_add_trade_simple = function(player, formname, fields)
-- 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 or trade.trade_id == "new") then
-- or do we have to create a new trade ID?
if(trade_id == "new") then
-- if the player adds the same trade again, the ID is reused; other
-- than that, the ID is uniq
trade.trade_id = "trade "..ps.." for "..bs
trade_id = "trade "..ps.." for "..bs
-- log the change
yl_speak_up.log_change(pname, n_id,
"Trade: Added offer "..tostring(trade.trade_id)..".")
"Trade: Added offer "..tostring(trade_id)..".")
-- add this new trade
dialog.trades[ trade.trade_id ] = {pay={ps},buy={bs}}
dialog.trades[ trade_id ] = {pay={ps},buy={bs}}
-- actually save the dialog to disk
yl_speak_up.save_dialog(n_id, dialog)
-- 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 = 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 = ps
trade.npc_gives = bs
-- finished editing
trade.edit_trade = nil
-- do not return yet - the items still need to be given back!
-- store the newly created trade_id
yl_speak_up.speak_to[pname].trade_id = trade_id
-- all ok so far
error_msg = nil
-- storing trades that are associated with particular dialogs and options
-- requires d_id and o_id to be set
elseif(trade_id ~= "new" and (not(d_id) or not(o_id))) then
error_msg = "Internal error. o_id was not set."
else
-- record this as a change, but do not save do disk yet
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": Trade "..tostring(trade_id).." added to option "..
tostring(o_id)..".")
-- add this new trade - complete with information to which dialog and
-- to which option the trade belongs
dialog.trades[ trade_id ] = {pay={ps},buy={bs}, d_id = d_id, o_id = o_id}
-- all ok so far
error_msg = nil
end
-- do not return yet - the items still need to be given back!
end
-- show error message (that leads back to this formspec)
if(error_msg) then
@ -258,27 +296,21 @@ yl_speak_up.input_add_trade_simple = function(player, formname, fields)
return
end
-- we need a way of deleting trades as well
-- we need a way of deleting trades as well;
-- this affects only trades that are associated with dialogs and options;
-- trades from the trade list are deleted more directly
elseif(fields.delete_trade_simple) then
-- delete this result (if it exists)
-- 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
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 "..
"Dialog "..d_id..": Trade "..tostring(trade_id).." deleted from option "..
tostring(o_id)..".")
-- delete the trade type result
dialog.n_dialogs[d_id].d_options[trade.o_id].o_results[trade.r_id] = nil
dialog.trades[ trade_id ] = nil
-- do not return yet - the items still need to be given back!
end
end
-- give the items back to the player (he took them from his inventory and had no
-- real chance to put them elsewhere - so there really ought to be room enough)
@ -292,23 +324,24 @@ yl_speak_up.input_add_trade_simple = function(player, formname, fields)
trade_inv:set_stack("setup", 2, "")
end
if(fields.store_trade_simple) then
local dialog = yl_speak_up.speak_to[pname].dialog
if(dialog.trades[ trade_id ] and dialog.trades[ trade_id ].d_id) then
-- tell the player that the new trade has been added
minetest.show_formspec(pname, "yl_speak_up:do_trade_simple",
"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
elseif(not(o_id)) then
-- we are no longer trading
yl_speak_up.trade[pname] = nil
yl_speak_up.speak_to[pname].trade_id = 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
yl_speak_up.speak_to[pname].trade_id = nil
-- ..else go back to the edit options formspec
minetest.show_formspec(pname, "yl_speak_up:edit_option_dialog",
yl_speak_up.get_fs_edit_option_dialog(player, n_id, d_id, o_id))
@ -450,35 +483,7 @@ yl_speak_up.get_fs_trade_simple = function(player, trade_id)
-- configuration of a new trade happens here
if(not(trade.player_gives) or not(trade.npc_gives) or trade.edit_trade) then
-- is this player allowed to edit the NPC and his trades? If not abort.
if(not(yl_speak_up.may_edit_npc(player, trade.n_id))) then
return formspec..
"label[2.0,1.8;Ups! Something went wrong.]"..
"button[6.2,1.6;2.0,0.9;abort_trade_simple;Back]"
end
local delete_button =
"button[0.2,2.6;1.0,0.9;delete_trade_simple;Delete]"..
"tooltip[delete_trade_simple;Delete this trade.]"
-- no point in deleting a new trade - it doesn't exist yet
if(trade_id and trade_id == "new") then
delete_button = ""
end
return formspec..
-- show the second slot of the setup inventory in the detached player's inv
"list[detached:yl_speak_up_player_"..pname..";setup;2,1.5;1,1;]"..
-- show the second slot of said inventory
"list[detached:yl_speak_up_player_"..pname..";setup;5,1.5;1,1;1]"..
"label[2.5,0.0;Configure trade with "..minetest.formspec_escape(trade.npc_name)..":]"..
"label[1.5,0.8;The customer pays:]"..
"label[1.5,2.8;Put items in the two slots and click on \"Store trade\".]"..
"label[1.5,3.2;You will get your items back when storing the trade.]"..
"button[0.2,1.6;1.0,0.9;abort_trade_simple;Abort]"..
delete_button..
"button[6.2,1.6;2.0,0.9;store_trade_simple;Store trade]"..
"tooltip[store_trade_simple;Click here to store this as a new trade. Your "..
"items will be returned to you and the trade will be shown the way "..
"the customer can see it.]"..
"tooltip[abort_trade_simple;Abort setting up this new trade.]"
return yl_speak_up.get_fs_add_trade_simple(player, trade_id)
end
-- view for the customer when actually trading