diff --git a/functions.lua b/functions.lua index 00a3cd7..8d7c83d 100644 --- a/functions.lua +++ b/functions.lua @@ -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 - minetest.show_formspec(pname, "yl_speak_up:add_trade_simple", - yl_speak_up.get_fs_trade_simple(player)) - return - end + -- 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 " " + minetest.show_formspec(pname, "yl_speak_up:add_trade_simple", + yl_speak_up.get_fs_add_trade_simple(player, + tostring(d_id).." "..tostring(o_id))) + return - -- 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 " " 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 diff --git a/trade_simple.lua b/trade_simple.lua index 18328c6..fd4b567 100644 --- a/trade_simple.lua +++ b/trade_simple.lua @@ -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 + -- 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 - minetest.show_formspec(pname, "yl_speak_up:talk", - yl_speak_up.get_fs_talkdialog(player, n_id, d_id)) - return + 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 " " 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 - - -- 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 - -- 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 - end + -- adding a new trade via the trade list? + if(not(trade_id) and fields.store_trade_simple) then + trade_id = "new" 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 + 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((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) + and not(trade_id == "new" and yl_speak_up.may_edit_npc(player, n_id))) then + return + end -- 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? + -- 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 - -- 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 + -- 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(r_id).." added to option ".. + "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 - -- 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! - error_msg = nil end -- show error message (that leads back to this formspec) if(error_msg) then @@ -258,26 +296,20 @@ 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 ".. + -- record this as a change + table.insert(yl_speak_up.npc_was_changed[ n_id ], + "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 - -- do not return yet - the items still need to be given back! - end + -- delete the trade type result + dialog.trades[ trade_id ] = nil + -- do not return yet - the items still need to be given back! end -- give the items back to the player (he took them from his inventory and had no @@ -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