From 661caaff4ed9da662803e7bdf9cb1f022c7d3328 Mon Sep 17 00:00:00 2001 From: Sokomine Date: Sun, 27 Jun 2021 04:33:14 +0200 Subject: [PATCH] removed yl_speak_up.save_changes_and_switch_to_other_dialog; handled now by show_fs.lua and the new fs_save_or_discard_or_back.lua --- fs_save_or_discard_or_back.lua | 123 ++++++++++++++++++++++ functions.lua | 179 ++------------------------------- init.lua | 2 + show_fs.lua | 89 +++++++++++++++- 4 files changed, 217 insertions(+), 176 deletions(-) create mode 100644 fs_save_or_discard_or_back.lua diff --git a/fs_save_or_discard_or_back.lua b/fs_save_or_discard_or_back.lua new file mode 100644 index 0000000..4d4619e --- /dev/null +++ b/fs_save_or_discard_or_back.lua @@ -0,0 +1,123 @@ + +-- when the player is editing the NPC and has changed it without having +-- saved the changes yet: ask what shall be done (save? discard? back?) +yl_speak_up.input_save_or_discard_changes = function(player, formname, fields) + local pname = player:get_player_name() + -- if the player is not even talking to this particular npc + if(not(yl_speak_up.speak_to[pname])) then + return + end + + local target_dialog = yl_speak_up.speak_to[pname].target_dialog + if(not(target_dialog)) then + target_dialog = "" + end + + local edit_mode = (yl_speak_up.edit_mode[pname] == yl_speak_up.speak_to[pname].n_id) + 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 = yl_speak_up.speak_to[pname].o_id + + -- the player decided to go back and continue editing the current dialog + if(edit_mode and fields.back_to_dialog_changes) then + -- do NOT clear the list of changes; just show the old dialog again + yl_speak_up.show_fs(player, "show_last_fs", {}) + return + + -- save changes and continue on to the next dialog + elseif(edit_mode and fields.save_dialog_changes) then + -- actually save the dialog (the one the NPC currently has) + yl_speak_up.save_dialog(n_id, yl_speak_up.speak_to[pname].dialog) + -- log all the changes + for i, c in ipairs(yl_speak_up.npc_was_changed[ n_id ]) do + yl_speak_up.log_change(pname, n_id, c) + end + -- clear list of changes + yl_speak_up.npc_was_changed[ n_id ] = {} + + -- discard changes and continue on to the next dialog + elseif(edit_mode and fields.discard_dialog_changes) then + -- the current dialog and the one we want to show next may both be new dialogs; + -- if we just reload the old state, they would both get lost + local target_dialog_data = yl_speak_up.speak_to[pname].dialog.n_dialogs[ target_dialog ] + -- actually restore the old state and discard the changes by loading the dialog anew + yl_speak_up.speak_to[pname].dialog = yl_speak_up.load_dialog(n_id) + -- clear list of changes + yl_speak_up.npc_was_changed[ n_id ] = {} + local dialog = yl_speak_up.speak_to[pname].dialog + -- do we have to save again after restoring current and target dialog? + local need_to_save = false + -- if the current dialog was a new one, it will be gone now - restore it + if(d_id and d_id ~= "" and not(dialog.n_dialogs[ d_id ])) then + -- we can't just restore the current dialog - after all the player wanted + -- to discard the changes; but we can recreate the current dialog so that it + -- is in the "new dialog" state again + local next_id = tonumber(string.sub( d_id, 3)) + yl_speak_up.add_new_dialog(dialog, pname, next_id) + yl_speak_up.log_change(pname, n_id, "Saved new dialog "..tostring( d_id )..".") + need_to_save = true + end + if(target_dialog and target_dialog ~= "" and not(dialog.n_dialogs[ target_dialog ])) then + -- restore the new target dialog + dialog.n_dialogs[ target_dialog ] = target_dialog_data + yl_speak_up.log_change(pname, n_id, "Saved new dialog "..tostring( target_dialog )..".") + need_to_save = true + end + if(need_to_save) then + yl_speak_up.save_dialog(n_id, dialog) + end + end + + -- are there any changes which might be saved or discarded? + if(edit_mode + and yl_speak_up.npc_was_changed[ n_id ] + and #yl_speak_up.npc_was_changed[ n_id ] > 0) then + + yl_speak_up.show_fs(player, "save_or_discard_changes", {}) + return + end + + yl_speak_up.show_fs(player, "proceed_after_save", {}) +end + + +yl_speak_up.get_fs_save_or_discard_changes = function(player, param) + local pname = player:get_player_name() + local n_id = yl_speak_up.speak_to[pname].n_id + -- TODO + local target_name = "quit" + if(target_dialog and target_dialog ~= "") then + target_name = "go on to dialog "..minetest.formspec_escape(target_dialog) + if(target_dialog == "edit_option_dialog") then + target_name = "edit option \"".. + minetest.formspec_escape(tostring(o_id)).."\" of dialog \"".. + minetest.formspec_escape(tostring(d_id)).."\"" + end + end + + yl_speak_up.speak_to[pname].target_dialog = target_dialog + local d_id = yl_speak_up.speak_to[pname].d_id + -- reverse the order of the changes in the log so that newest are topmost + local text = "" + for i,t in ipairs(yl_speak_up.npc_was_changed[ n_id ]) do + text = minetest.formspec_escape(t).."\n"..text + end + -- build a formspec showing the changes to this dialog and ask for save + return "formspec_version[3]".. + "size[14,6.2]".. + "bgcolor[#00000000;false]".. + -- TODO: make this more flexible + "label[0.2,0.2;You are about to leave dialog "..minetest.formspec_escape(d_id).. + " and "..target_name..".]".. + "label[0.2,0.65;These changes have been applied to dialog ".. + minetest.formspec_escape(d_id)..":]".. + "hypertext[0.2,1;13.5,4;list_of_changes;".. + minetest.formspec_escape(text) .. "\n".."]".. + "button[1.2,5.2;3,0.9;discard_dialog_changes;Discard changes]".. + "button[5.7,5.2;3,0.9;back_to_dialog_changes;Back]".. + "button[10.2,5.2;3,0.9;save_dialog_changes;Save changes]".. + "tooltip[save_dialog_changes;Save all changes to this dialog and "..target_name..".]".. + "tooltip[discard_dialog_changes;Undo all changes and "..target_name..".]".. + "tooltip[back_to_dialog_changes;Go back to dialog ".. + minetest.formspec_escape(d_id).." and continue editing it.]" +end diff --git a/functions.lua b/functions.lua index 07a912d..c5e8fcb 100644 --- a/functions.lua +++ b/functions.lua @@ -1722,154 +1722,6 @@ yl_speak_up.get_result_id_by_type = function(dialog, d_id, o_id, result_type) end --- this is always called when switching to a new dialog; but only in edit_mode does --- it show a formspec asking for change/back/discard -yl_speak_up.save_changes_and_switch_to_other_dialog = function(player, fields, target_dialog) - local pname = player:get_player_name() - -- if the player is not even talking to this particular npc - if(not(yl_speak_up.speak_to[pname])) then - return - end - - if(not(target_dialog)) then - target_dialog = yl_speak_up.speak_to[pname].target_dialog - if(not(target_dialog)) then - target_dialog = "" - end - end - - local edit_mode = (yl_speak_up.edit_mode[pname] == yl_speak_up.speak_to[pname].n_id) - 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 = yl_speak_up.speak_to[pname].o_id - - -- the player decided to go back and continue editing the current dialog - if(edit_mode and fields.back_to_dialog_changes) then - -- do NOT clear the list of changes; just show the old dialog again - yl_speak_up.show_fs(player, "talk", {n_id = n_id, d_id = d_id}) - return - - -- save changes and continue on to the next dialog - elseif(edit_mode and fields.save_dialog_changes) then - -- actually save the dialog (the one the NPC currently has) - yl_speak_up.save_dialog(n_id, yl_speak_up.speak_to[pname].dialog) - -- log all the changes - for i, c in ipairs(yl_speak_up.npc_was_changed[ n_id ]) do - yl_speak_up.log_change(pname, n_id, c) - end - -- clear list of changes - yl_speak_up.npc_was_changed[ n_id ] = {} - - -- discard changes and continue on to the next dialog - elseif(edit_mode and fields.discard_dialog_changes) then - -- the current dialog and the one we want to show next may both be new dialogs; - -- if we just reload the old state, they would both get lost - local target_dialog_data = yl_speak_up.speak_to[pname].dialog.n_dialogs[ target_dialog ] - -- actually restore the old state and discard the changes by loading the dialog anew - yl_speak_up.speak_to[pname].dialog = yl_speak_up.load_dialog(n_id) - -- clear list of changes - yl_speak_up.npc_was_changed[ n_id ] = {} - local dialog = yl_speak_up.speak_to[pname].dialog - -- do we have to save again after restoring current and target dialog? - local need_to_save = false - -- if the current dialog was a new one, it will be gone now - restore it - if(not(dialog.n_dialogs[ d_id ])) then - -- we can't just restore the current dialog - after all the player wanted - -- to discard the changes; but we can recreate the current dialog so that it - -- is in the "new dialog" state again - local next_id = tonumber(string.sub( d_id, 3)) - yl_speak_up.add_new_dialog(dialog, pname, next_id) - yl_speak_up.log_change(pname, n_id, "Saved new dialog "..tostring( d_id )..".") - need_to_save = true - end - if(not(dialog.n_dialogs[ target_dialog ])) then - -- restore the new target dialog - dialog.n_dialogs[ target_dialog ] = target_dialog_data - yl_speak_up.log_change(pname, n_id, "Saved new dialog "..tostring( target_dialog )..".") - need_to_save = true - end - if(need_to_save) then - yl_speak_up.save_dialog(n_id, dialog) - end - end - - -- are there any changes which might be saved or discarded? - if(edit_mode - and yl_speak_up.npc_was_changed[ n_id ] - and #yl_speak_up.npc_was_changed[ n_id ] > 0) then - - local target_name = "quit" - if(target_dialog and target_dialog ~= "") then - target_name = "go on to dialog "..minetest.formspec_escape(target_dialog) - if(target_dialog == "edit_option_dialog") then - target_name = "edit option \"".. - minetest.formspec_escape(tostring(o_id)).."\" of dialog \"".. - minetest.formspec_escape(tostring(d_id)).."\"" - end - end - - yl_speak_up.speak_to[pname].target_dialog = target_dialog - local d_id = yl_speak_up.speak_to[pname].d_id - -- reverse the order of the changes in the log so that newest are topmost - local text = "" - for i,t in ipairs(yl_speak_up.npc_was_changed[ n_id ]) do - text = minetest.formspec_escape(t).."\n"..text - end - -- build a formspec showing the changes to this dialog and ask for save - local formspec = - "formspec_version[3]".. - "size[14,6.2]".. - "bgcolor[#00000000;false]".. - "label[0.2,0.2;You are about to leave dialog "..minetest.formspec_escape(d_id).. - " and "..target_name..".]".. - "label[0.2,0.65;These changes have been applied to dialog ".. - minetest.formspec_escape(d_id)..":]".. - "hypertext[0.2,1;13.5,4;list_of_changes;".. - minetest.formspec_escape(text) .. "\n".."]".. - "button[1.2,5.2;3,0.9;discard_dialog_changes;Discard changes]".. - "button[5.7,5.2;3,0.9;back_to_dialog_changes;Back]".. - "button[10.2,5.2;3,0.9;save_dialog_changes;Save changes]".. - "tooltip[save_dialog_changes;Save all changes to this dialog and "..target_name..".]".. - "tooltip[discard_dialog_changes;Undo all changes and "..target_name..".]".. - "tooltip[back_to_dialog_changes;Go back to dialog ".. - minetest.formspec_escape(d_id).." and continue editing it.]" - -- actaully show the formspec to the player - yl_speak_up.show_fs(player, "msg", {input_to = "yl_speak_up:confirm_save", - formspec = formspec}) - return - end - -- if there is nothing that needs to be saved or discarded: allow quit/exit - if fields.quit or fields.button_exit then - yl_speak_up.edit_mode[pname] = nil - -- Formspec was quit - yl_speak_up.speak_to[pname] = nil - return - end - -- end edit mode and start a new chat - but this time in normal mode - if not(target_dialog) or target_dialog == "" then - yl_speak_up.edit_mode[pname] = nil - target_dialog = nil - end - - -- the trade list is not really a dialog... - if(target_dialog == "trade_list") then - yl_speak_up.speak_to[pname].target_dialog = nil - yl_speak_up.show_fs(player, "trade_list") - return - -- edit an option - elseif(target_dialog == "edit_option_dialog" and o_id and d_id) then - yl_speak_up.speak_to[pname].target_dialog = nil - yl_speak_up.show_fs(player, "edit_option_dialog", - {n_id = n_id, d_id = d_id, o_id = o_id, caller= "confirm_save"}) - return - end - yl_speak_up.speak_to[pname].target_dialog = nil - -- move on to the target dialog - yl_speak_up.speak_to[pname].d_id = target_dialog - yl_speak_up.show_fs(player, "talk", {n_id = n_id, d_id = target_dialog}) -end - - -- helper function for sorting options/answers using options[o_id].o_sort -- (or dialogs by d_sort) yl_speak_up.get_sorted_options = function(options, sort_by) @@ -2279,14 +2131,6 @@ end -- end of yl_speak_up.edit_mode_apply_changes -yl_speak_up.input_confirm_save = function(player, formname, fields) - if formname ~= "yl_speak_up:confirm_save" then - return - end - yl_speak_up.save_changes_and_switch_to_other_dialog(player, fields, fields.goto_target_dialog) -end - - -- identify multiple results that lead to target dialogs yl_speak_up.check_for_disambigous_results = function(n_id, pname) @@ -2398,13 +2242,13 @@ yl_speak_up.input_talk = function(player, formname, fields) -- end edit mode (does not require the priv; will only switch back to normal behaviour) elseif fields.button_end_edit_mode then -- if there are any changes done: ask first and don't end edit mode yet - yl_speak_up.save_changes_and_switch_to_other_dialog(player, fields, nil) + yl_speak_up.show_fs(player, "quit", nil) return end if fields.quit or fields.button_exit then -- if there are any changes done: ask first and don't quit yet - yl_speak_up.save_changes_and_switch_to_other_dialog(player, fields, nil) + yl_speak_up.show_fs(player, "quit", nil) return end @@ -2429,11 +2273,7 @@ yl_speak_up.input_talk = function(player, formname, fields) -- the player wants to see the trade list if(fields.show_trade_list) then - if(edit_mode) then - yl_speak_up.save_changes_and_switch_to_other_dialog(player, fields, "trade_list") - return - end - yl_speak_up.show_fs(player, "trade_list") + yl_speak_up.show_fs(player, "trade_list", nil) return end @@ -2497,8 +2337,9 @@ yl_speak_up.input_talk = function(player, formname, fields) -- store which option we want to edit yl_speak_up.speak_to[pname].o_id = o_id -- if something was changed: ask for confirmation - yl_speak_up.save_changes_and_switch_to_other_dialog( - player, fields, "edit_option_dialog") + yl_speak_up.show_fs(player, "edit_option_dialog", + {n_id = yl_speak_up.speak_to[pname].n_id, + d_id = d_id, o_id = o_id, caller="button"}) return end end @@ -2534,13 +2375,7 @@ yl_speak_up.input_talk = function(player, formname, fields) end end end - -- if there are any changes done: ask first and don't switch to the new dialog yet - if(show_dialog ~= d_id) then - yl_speak_up.save_changes_and_switch_to_other_dialog(player, fields, show_dialog) - -- show the same dialog again - else - yl_speak_up.show_fs(player, "talk", {n_id = n_id, d_id = d_id}) - end + yl_speak_up.show_fs(player, "talk", {n_id = n_id, d_id = show_dialog}) -- no option was selected - so we need to end this here return end diff --git a/init.lua b/init.lua index a35b103..96961c8 100644 --- a/init.lua +++ b/init.lua @@ -19,6 +19,8 @@ dofile(modpath .. "config.lua") dofile(modpath .. "privs.lua") -- handle on_player_receive_fields and showing of formspecs dofile(modpath .. "show_fs.lua") +-- ask if the player wants to save, discard or go back in edit mode +dofile(modpath .. "fs_save_or_discard_or_back.lua") -- common functions for editing preconditions and effects dofile(modpath .. "fs_edit_general.lua") -- edit preconditions (can be reached through edit options dialog) diff --git a/show_fs.lua b/show_fs.lua index 16c041f..d6287a6 100644 --- a/show_fs.lua +++ b/show_fs.lua @@ -8,8 +8,9 @@ minetest.register_on_player_receive_fields( function(player, formname, fields) elseif formname == "yl_speak_up:setdialog" then yl_speak_up.input_setdialog(player, formname, fields) return true - elseif formname == "yl_speak_up:confirm_save" then - yl_speak_up.input_confirm_save(player, formname, fields) + -- handled in fs_save_or_discard_or_back.lua + elseif formname == "yl_speak_up:save_or_discard_changes" then + yl_speak_up.input_save_or_discard_changes(player, formname, fields) return true -- handled in fs_edit_options_dialog.lua elseif formname == "yl_speak_up:edit_option_dialog" then @@ -82,6 +83,84 @@ yl_speak_up.show_fs = function(player, fs_name, param) end local pname = player:get_player_name() + local last_fs = yl_speak_up.speak_to[pname].last_fs + -- show the save or discard changes dialog + if(fs_name and fs_name == "save_or_discard_changes") then + minetest.show_formspec(pname, "yl_speak_up:save_or_discard_changes", + yl_speak_up.get_fs_save_or_discard_changes(player, param)) + return + + -- the player either saved or discarded; we may proceed now + elseif(fs_name and fs_name == "proceed_after_save") then + fs_name = yl_speak_up.speak_to[pname].next_fs + param = yl_speak_up.speak_to[pname].next_fs_param + yl_speak_up.speak_to[pname].next_fs = nil + yl_speak_up.speak_to[pname].next_fs_param = nil + yl_speak_up.speak_to[pname].last_fs = fs_name + yl_speak_up.speak_to[pname].last_fs_param = param + + -- the player clicked on "back" in the above dialog + elseif(fs_name and fs_name == "show_last_fs") then + -- call the last formspec again - and with the same parameters + fs_name = yl_speak_up.speak_to[pname].last_fs + param = yl_speak_up.speak_to[pname].last_fs_param + + -- do we need to check if there is something that needs saving? + elseif(fs_name + -- msg is just a loop for displaying (mostly error) messages + and fs_name ~= "msg" + -- is the player editing the NPC? that is: might there be any changes? + and (yl_speak_up.edit_mode[pname] == yl_speak_up.speak_to[pname].n_id)) then + local last_fs = yl_speak_up.speak_to[pname].last_fs + local d_id = yl_speak_up.speak_to[pname].d_id + local o_id = yl_speak_up.speak_to[pname].o_id + -- only these two formspecs need to ask specificly if the data ought to be saved + if(last_fs == "talk" or last_fs == "edit_option_dialog" or fs_name == "quit") then + local last_param = yl_speak_up.speak_to[pname].last_fs_param + local show_save_fs = false + if(not(param)) then + param = {} + end + -- set the target dialog + yl_speak_up.speak_to[pname].target_dialog = param.d_id + -- if we are switching from one dialog to another: is it the same? + if(last_fs == "talk" and fs_name == last_fs + and param and param.d_id and param.d_id ~= d_id) then + -- diffrent parameters: save (if needed) + show_save_fs = true + -- leaving a dialog: save! + elseif(last_fs == "talk" and fs_name ~= last_fs) then + show_save_fs = true + -- clicking on "save" in an edit option dialog: save! + elseif(last_fs == "edit_option_dialog" and fs_name == last_fs + and param and param.caller and param.caller == "save_option") then + show_save_fs = true + -- leaving editing an option: save! + elseif(last_fs == "edit_option_dialog" and fs_name ~= last_fs) then + show_save_fs = true + -- quitting: save! + elseif(fs_name == "quit") then + yl_speak_up.speak_to[pname].target_dialog = nil + show_save_fs = true + end + -- show the save or discard dialog + if(show_save_fs) then + yl_speak_up.speak_to[pname].next_fs = fs_name + yl_speak_up.speak_to[pname].next_fs_param = param + -- check first if it's necessary to ask for save or discard + yl_speak_up.input_save_or_discard_changes(player, "", {}) + return + end + end + -- store the new formspec + yl_speak_up.speak_to[pname].last_fs = fs_name + -- and its parameter + yl_speak_up.speak_to[pname].last_fs_param = param + elseif(fs_name == "quit") then + -- player wanted to quit + return + end + -- this is here mostly to fascilitate debugging - so that really all calls to -- minetest.show_formspec are routed through here if(fs_name == "msg") then @@ -91,6 +170,9 @@ yl_speak_up.show_fs = function(player, fs_name, param) minetest.show_formspec(pname, param.input_to, param.formspec) + elseif(fs_name == "quit") then + return + -- staff-based editing elseif(fs_name == "optiondialog") then if(not(param)) then @@ -106,13 +188,12 @@ yl_speak_up.show_fs = function(player, fs_name, param) minetest.show_formspec(pname, "yl_speak_up:setdialog", yl_speak_up.get_fs_setdialog(player, param.n_id, param.d_id)) - -- "confirm_save" does not have its own option here; doesn't have a get_fs_-function either - elseif(fs_name == "edit_option_dialog") then -- the optional "caller" parameter can be used for debugging if(not(param)) then param = {} end + yl_speak_up.speak_to[pname].o_id = param.o_id minetest.show_formspec(pname, "yl_speak_up:edit_option_dialog", yl_speak_up.get_fs_edit_option_dialog(player, param.n_id, param.d_id, param.o_id))