extracted edit_mode_apply_changes.lua from functions.lua into a seperate file

This commit is contained in:
Sokomine 2022-01-07 21:04:55 +01:00
parent 2b402aaefb
commit bd2c8bc4cd
3 changed files with 423 additions and 422 deletions

421
edit_mode_apply_changes.lua Normal file
View File

@ -0,0 +1,421 @@
-- helper function for yl_speak_up.edit_mode_apply_changes;
-- makes sure the new dialog (and a result/effect "dialog" for each option) exist
yl_speak_up.prepare_new_dialog_for_option = function(dialog, pname, n_id, d_id, o_id,target_dialog,o_results)
-- is there a result/effect of the type "dialog" already? else use a fallback
local result = {r_value = "-default-"}
if(o_results) then
for kr, vr in pairs(o_results) do
if( vr.r_type == "dialog" ) then
result = vr
end
end
end
-- this may also point to a new dialog
if(target_dialog == yl_speak_up.text_new_dialog_id) then
-- create a new dialog and show it as new target dialog - but do not display
-- this dialog directly (the player may follow the -> button)
target_dialog = yl_speak_up.add_new_dialog(dialog, pname, nil)
elseif( result.r_value and result.r_value == target_dialog) then
-- no problem - the right dialog is set already
return target_dialog
end
-- store that a new option has been added to this dialog
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": The target dialog for option "..
tostring(o_id).." was changed from "..
tostring(result.r_value or "-default-").." to "..
tostring(target_dialog)..".")
-- does the result/effect of type "dialog" exist already? then we're done
if(result.r_type and result.r_type == "dialog") then
-- actually change the target dialog
result.r_value = target_dialog
return target_dialog
end
-- create a new result (first the id, then the actual result)
local future_r_id = yl_speak_up.add_new_result(dialog, d_id, o_id)
-- actually store the new result
dialog.n_dialogs[d_id].d_options[o_id].o_results[future_r_id] = {
r_id = future_r_id,
r_type = "dialog",
r_value = target_dialog}
return target_dialog
end
-- helper function for formspec "yl_speak_up:talk" *and* formspec "yl_speak_up:edit_option_dialog"
-- when a parameter was changed in edit mode;
-- this is called when the player is in edit_mode (editing the NPC);
-- the function checks if the player has changed any parameters
-- Parameters:
-- pname player name
-- fields the fields returned from the formspec
-- Returns:
-- result table with information about what was added
-- (for now, only result.show_next_option is of intrest in the option edit menu)
yl_speak_up.edit_mode_apply_changes = function(pname, fields)
local n_id = yl_speak_up.edit_mode[pname]
local d_id = yl_speak_up.speak_to[pname].d_id
local dialog = yl_speak_up.speak_to[pname].dialog
-- this way we can store the actual changes and present them to the player for saving
if(not(yl_speak_up.npc_was_changed[ n_id ])) then
yl_speak_up.npc_was_changed[ n_id ] = {}
end
-- nothing to do if that dialog does not exist
if(not(d_id) or not(dialog.n_dialogs) or not(dialog.n_dialogs[ d_id ])) then
return
end
-- allow owner to mute/unmute npc (would be bad if players can already see what is going
-- to happen while the owner creates a long quest)
-- mute/unmute gets logged in the function and does not need extra log entries
local obj = yl_speak_up.speak_to[pname].obj
if(fields.mute_npc and obj) then
yl_speak_up.set_muted(pname, obj, true)
elseif(fields.un_mute_npc and obj) then
yl_speak_up.set_muted(pname, obj, false)
end
-- new options etc. may be added; store these IDs so that we can switch to the right target
local result = {}
-- make this the first dialog shown when starting a conversation
if(fields.make_first_option) then
-- check which dialog(s) previously had the highest priority and change thsoe
for k, v in pairs(dialog.n_dialogs) do
if(v and v.d_sort and (v.d_sort=="0" or v.d_sort==0)) then
-- try to derive a sensible future sort priority from the key:
-- here we make use of the d_<nr> pattern; but even if that fails to yield
-- a number, the sort function will later be able to deal with it anyway
local new_priority = string.sub(k, 3)
dialog.n_dialogs[ k ].d_sort = new_priority
end
end
-- actually make this the chat with the highest priority
dialog.n_dialogs[ d_id ].d_sort = "0"
-- this is not immediately saved, even though the changes to the previous dialog with
-- the highest priority cannot be automaticly undone (but as long as it is not saved,
-- it really does not matter; and when saving, the player has to take some care)
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": Turned into new start dialog.")
end
-- detect changes to d_text: text of the dialog (what the npc is saying)
-- (only happens in dialog edit menu)
if(fields.d_text and dialog.n_dialogs[ d_id ].d_text ~= fields.d_text) then
-- store that there have been changes to this npc
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": d_text (what the NPC says) was changed from \""..
tostring( dialog.n_dialogs[ d_id ].d_text)..
"\" to \""..tostring(fields.d_text).."\".")
-- actually change the text - but do not save to disk yet
dialog.n_dialogs[ d_id ].d_text = fields.d_text
end
-- add a new option/answer
if(fields[ "add_option"]) then
-- count the options/answers so that the limit is not exceeded
local anz_options = 0
local future_o_id = "o_" .. yl_speak_up.find_next_id(dialog.n_dialogs[d_id].d_options)
if dialog.n_dialogs[d_id].d_options == nil then
dialog.n_dialogs[d_id].d_options = {}
else
local sorted_list = yl_speak_up.get_sorted_options(dialog.n_dialogs[d_id].d_options, "o_sort")
anz_options = #sorted_list
end
-- we don't want an infinite amount of answers per dialog
if(anz_options >= yl_speak_up.max_number_of_options_per_dialog) then
-- this is already checked earlier on and the button only shown if
-- options can be added; so this can reamin a chat message
minetest.chat_send_player(pname, "Sorry. Only "..
tostring(yl_speak_up.max_number_of_options_per_dialog)..
" options/answers are allowed per dialog.")
fields.add_option = nil
else
dialog.n_dialogs[d_id].d_options[future_o_id] = {
o_id = future_o_id,
o_hide_when_prerequisites_not_met = "false",
o_grey_when_prerequisites_not_met = "false",
o_sort = -1,
o_text_when_prerequisites_not_met = "",
o_text_when_prerequisites_met = "",
}
-- necessary in order for it to work
local s = yl_speak_up.sanitize_sort(dialog.n_dialogs[d_id].d_options, yl_speak_up.speak_to[pname].o_sort)
dialog.n_dialogs[d_id].d_options[future_o_id].o_sort = s
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": Added new option/answer "..future_o_id..".")
-- if this is selected in the options edit menu, we want to move straight on to the new option
result["show_next_option"] = future_o_id
end
end
if(fields[ "del_option"] and fields.o_id and dialog.n_dialogs[d_id].d_options[fields.o_id]) then
local o_id = fields.o_id
-- which dialog to show instead of the deleted one?
local next_o_id = o_id
local sorted_list = yl_speak_up.get_sorted_options(dialog.n_dialogs[d_id].d_options, "o_sort")
for i, o in ipairs(sorted_list) do
if(o == o_id and sorted_list[ i+1 ]) then
next_o_id = sorted_list[ i+1 ]
elseif(o == o_id and sorted_list[ i-1 ]) then
next_o_id = sorted_list[ i-1 ]
end
end
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": Option "..tostring(o_id).." deleted.")
-- actually delete the dialog
dialog.n_dialogs[d_id].d_options[o_id] = nil
-- the current dialog is deleted; we need to show another one
result["show_next_option"] = next_o_id
-- after deleting the entry, all previous/further changes to it are kind of unintresting
return result
end
-- ignore entries to o_sort if they are not a number
if(fields[ "edit_option_o_sort"]
and tonumber(fields[ "edit_option_o_sort"])
and fields.o_id and dialog.n_dialogs[d_id].d_options[fields.o_id]) then
local o_id = fields.o_id
local new_nr = tonumber(fields[ "edit_option_o_sort"])
local old_nr = tonumber(dialog.n_dialogs[d_id].d_options[o_id].o_sort)
-- if the nr is -1 (do not show) then we are done already: nothing to do
if(old_nr == new_nr) then
-- -1: do not list as option/answer (but still store and keep it)
elseif(new_nr == -1 and old_nr ~= -1) then
dialog.n_dialogs[d_id].d_options[o_id].o_sort = "-1"
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": Option "..tostring(o_id).." was set to -1 (do not list).")
else
-- get the old sorted list
local sorted_list = yl_speak_up.get_sorted_options(dialog.n_dialogs[d_id].d_options, "o_sort")
-- negative numbers are not shown
local entries_shown_list = {}
for i, o in ipairs(sorted_list) do
local n = tonumber(dialog.n_dialogs[d_id].d_options[o].o_sort)
if(n and n > 0 and o ~= o_id) then
table.insert(entries_shown_list, o)
end
end
-- insert the entry at the new position and let lua do the job
table.insert(entries_shown_list, new_nr, o_id)
-- take the indices from that new list as new sort values and store them;
-- this has the side effect that duplicate entries get sorted out as well
for i, o in ipairs(entries_shown_list) do
dialog.n_dialogs[d_id].d_options[o].o_sort = tostring(i)
end
-- store that there was a cahnge
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": Option "..tostring(o_id).." was moved to position "..
tostring(new_nr)..".")
end
end
-- changes to options are not possible if there are none
if(dialog.n_dialogs[ d_id ].d_options) then
-- detect changes to text_option_<o_id>: text for option <o_id>
for k, v in pairs(dialog.n_dialogs[ d_id ].d_options) do
if( fields[ "text_option_"..k ]
and fields[ "text_option_"..k ] ~= v.o_text_when_prerequisites_met ) then
-- store that there have been changes to this npc
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": The text for option "..tostring(k)..
" was changed from \""..tostring(v.o_text_when_prerequisites_met)..
"\" to \""..tostring(fields[ "text_option_"..k]).."\".")
-- actually change the text of the option
dialog.n_dialogs[ d_id ].d_options[ k ].o_text_when_prerequisites_met = fields[ "text_option_"..k ]
end
end
-- detect changes to d_id_<o_id>: target dialog for option <o_id>
for k, v in pairs(dialog.n_dialogs[ d_id ].d_options) do
if(fields[ "d_id_"..k ]) then
local new_target_dialog = yl_speak_up.prepare_new_dialog_for_option(
dialog, pname, n_id, d_id, k, fields[ "d_id_"..k ], v.o_results)
if(new_target_dialog ~= fields[ "d_id_"..k ]) then
fields[ "d_id_"..k ] = new_target_dialog
-- in options edit menu: show this update
result["show_next_option"] = k
end
end
end
end
-- add a new dialog; either via "+" button or "New dialog" in dialog dropdown menu
-- this has to be done after all the other changes because those (text changes etc.) still
-- apply to the *old* dialog
if(fields.show_new_dialog
or(fields["d_id"] and fields["d_id"] == yl_speak_up.text_new_dialog_id)) then
-- create the new dialog and make sure it gets shown
local d_id = yl_speak_up.add_new_dialog(dialog, pname, nil)
-- actually show the new dialog
fields["d_id"] = d_id
fields["show_new_dialog"] = nil
end
-- delete one empty dialog
if(fields.delete_this_empty_dialog) then
local anz_options = 0
-- we need to show a new dialog after this one was deleted
local new_dialog = d_id
local sorted_list = yl_speak_up.get_sorted_options(dialog.n_dialogs, "d_sort")
for i, k in ipairs(sorted_list) do
-- count the options of this dialog
if(k == d_id) then
if(dialog.n_dialogs[d_id].d_options) then
for o, w in pairs(dialog.n_dialogs[d_id].d_options) do
anz_options = anz_options + 1
end
end
if(sorted_list[i+1]) then
new_dialog = sorted_list[i+1]
elseif(sorted_list[i-1]) then
new_dialog = sorted_list[i-1]
end
end
end
-- there needs to be one dialog left after deleting this one,
if(#sorted_list > 1
-- this dialog isn't allowed to hold any more options/answers
and anz_options == 0
-- we really found a new dialog to show
and new_dialog ~= d_id
-- and the text needs to be empty
and dialog.n_dialogs[ d_id ].d_text == "") then
-- actually delete this dialog
dialog.n_dialogs[ d_id ] = nil
-- ..and store it to disk
yl_speak_up.delete_dialog(n_id, d_id)
yl_speak_up.log_change(pname, n_id,
"Deleted dialog "..tostring(d_id)..".")
-- switch to another dialog (this one was deleted after all)
fields["d_id"] = new_dialog
fields["show_new_dialog"] = nil
else
-- deleting is only possible from the talk menu, and there the delete
-- button is only shown if the dialog can be deleted; so this can remain
-- a chat message
minetest.chat_send_player(pname, "Sorry. This dialog cannot be deleted (yet). "..
"It is either the only dialog left or has a non-empty text or has at "..
"least on remaining option/answer.")
end
end
-- not in options edit menu?
local o_id = fields.o_id
if(not(o_id)) then
return result
end
local d_option = dialog.n_dialogs[ d_id ].d_options[ o_id ]
-- change alternate text when preconditions are not met
-- (only happens in options edit menu)
if(fields.option_text_not_met and d_option
and d_option.o_text_when_prerequisites_not_met ~= fields.option_text_not_met) then
-- add change to changelog
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": The alternate text for option "..tostring(o_id)..
" was changed from \""..
tostring(d_option.o_text_when_prerequisites_not_met).."\" to \""..
tostring(fields.option_text_not_met).."\".")
-- actually change the text of the option
d_option.o_text_when_prerequisites_not_met = fields.option_text_not_met
end
-- toggle autoselection/autoclick of an option
if(d_option and fields.option_autoanswer and fields.option_autoanswer ~= "") then
if(d_option.o_autoanswer and d_option.o_autoanswer == 1
and fields.option_autoanswer == "by clicking on it") then
d_option.o_autoanswer = nil
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": The modus for option "..tostring(o_id)..
" was changed from \"automaticly\" to \"by clicking on it\".")
elseif((not(d_option.o_autoanswer) or d_option.o_autoanswer ~= 1)
and fields.option_autoanswer == "automaticly") then
d_option.o_autoanswer = 1
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": The modus for option "..tostring(o_id)..
" was changed from \"by clicking on it\" to \"automaticly\".")
end
end
-- handle hide/grey out/show alternate answer
-- (only happens in options edit menu)
if(fields.hide_or_grey_or_alternate_answer and d_option) then
if(fields.hide_or_grey_or_alternate_answer == "..hide this answer."
and d_option.o_hide_when_prerequisites_not_met ~= "true") then
d_option.o_hide_when_prerequisites_not_met = "true"
d_option.o_grey_when_prerequisites_not_met = "false"
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": If precondition for option "..tostring(o_id)..
" is not met, hide option/answer.")
-- make sure we show this options update next
result["show_next_option"] = o_id
elseif(fields.hide_or_grey_or_alternate_answer == "..grey out the following answer:"
and d_option.o_grey_when_prerequisites_not_met ~= "true") then
d_option.o_hide_when_prerequisites_not_met = "false"
d_option.o_grey_when_prerequisites_not_met = "true"
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": If precondition for option "..tostring(o_id)..
" is not met, grey out option/answer.")
result["show_next_option"] = o_id
elseif(fields.hide_or_grey_or_alternate_answer == "..display the following alternate answer:"
and (d_option.o_hide_when_prerequisites_not_met ~= "false"
or d_option.o_grey_when_prerequisites_not_met) ~= "false") then
d_option.o_hide_when_prerequisites_not_met = "false"
d_option.o_grey_when_prerequisites_not_met = "false"
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": If precondition for option "..tostring(o_id)..
" is not met, show alternate option/answer.")
result["show_next_option"] = o_id
end
end
-- how many times can the player fail to execute the action successfully?
if(fields[ "timer_max_attempts_on_failure"]) then
local field_name = "timer_max_attempts_on_failure"
local timer_name = "timer_on_failure_"..tostring(d_id).."_"..tostring(o_id)
if(not(tonumber(fields[ field_name ]))) then
fields[ field_name ] = 0
end
-- make sure the variable exists
if(yl_speak_up.add_time_based_variable(timer_name)) then
yl_speak_up.set_variable_metadata(timer_name, nil, "parameter", "max_attempts",
fields[ field_name ])
end
end
-- ..and how long has the player to wait in order to try again?
if(fields[ "timer_max_seconds_on_failure"]) then
local field_name = "timer_max_seconds_on_failure"
local timer_name = "timer_on_failure_"..tostring(d_id).."_"..tostring(o_id)
if(not(tonumber(fields[ field_name ]))) then
fields[ field_name ] = 0
end
-- make sure the variable exists
if(yl_speak_up.add_time_based_variable(timer_name)) then
yl_speak_up.set_variable_metadata(timer_name, nil, "parameter", "duration",
fields[ field_name ])
end
end
if(fields[ "timer_max_seconds_on_success"]) then
local field_name = "timer_max_seconds_on_success"
local timer_name = "timer_on_success_"..tostring(d_id).."_"..tostring(o_id)
if(not(tonumber(fields[ field_name ]))) then
fields[ field_name ] = 0
end
-- make sure the variable exists
if(yl_speak_up.add_time_based_variable(timer_name)) then
yl_speak_up.set_variable_metadata(timer_name, nil, "parameter", "duration",
fields[ field_name ])
end
end
-- currently only contains result["show_new_option"] (which is needed for options edit menu)
return result
end
-- end of yl_speak_up.edit_mode_apply_changes

View File

@ -342,428 +342,6 @@ yl_speak_up.sort_keys = function(t, simple)
end
-- helper function for yl_speak_up.edit_mode_apply_changes;
-- makes sure the new dialog (and a result/effect "dialog" for each option) exist
yl_speak_up.prepare_new_dialog_for_option = function(dialog, pname, n_id, d_id, o_id,target_dialog,o_results)
-- is there a result/effect of the type "dialog" already? else use a fallback
local result = {r_value = "-default-"}
if(o_results) then
for kr, vr in pairs(o_results) do
if( vr.r_type == "dialog" ) then
result = vr
end
end
end
-- this may also point to a new dialog
if(target_dialog == yl_speak_up.text_new_dialog_id) then
-- create a new dialog and show it as new target dialog - but do not display
-- this dialog directly (the player may follow the -> button)
target_dialog = yl_speak_up.add_new_dialog(dialog, pname, nil)
elseif( result.r_value and result.r_value == target_dialog) then
-- no problem - the right dialog is set already
return target_dialog
end
-- store that a new option has been added to this dialog
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": The target dialog for option "..
tostring(o_id).." was changed from "..
tostring(result.r_value or "-default-").." to "..
tostring(target_dialog)..".")
-- does the result/effect of type "dialog" exist already? then we're done
if(result.r_type and result.r_type == "dialog") then
-- actually change the target dialog
result.r_value = target_dialog
return target_dialog
end
-- create a new result (first the id, then the actual result)
local future_r_id = yl_speak_up.add_new_result(dialog, d_id, o_id)
-- actually store the new result
dialog.n_dialogs[d_id].d_options[o_id].o_results[future_r_id] = {
r_id = future_r_id,
r_type = "dialog",
r_value = target_dialog}
return target_dialog
end
-- helper function for formspec "yl_speak_up:talk" *and* formspec "yl_speak_up:edit_option_dialog"
-- when a parameter was changed in edit mode;
-- this is called when the player is in edit_mode (editing the NPC);
-- the function checks if the player has changed any parameters
-- Parameters:
-- pname player name
-- fields the fields returned from the formspec
-- Returns:
-- result table with information about what was added
-- (for now, only result.show_next_option is of intrest in the option edit menu)
yl_speak_up.edit_mode_apply_changes = function(pname, fields)
local n_id = yl_speak_up.edit_mode[pname]
local d_id = yl_speak_up.speak_to[pname].d_id
local dialog = yl_speak_up.speak_to[pname].dialog
-- this way we can store the actual changes and present them to the player for saving
if(not(yl_speak_up.npc_was_changed[ n_id ])) then
yl_speak_up.npc_was_changed[ n_id ] = {}
end
-- nothing to do if that dialog does not exist
if(not(d_id) or not(dialog.n_dialogs) or not(dialog.n_dialogs[ d_id ])) then
return
end
-- allow owner to mute/unmute npc (would be bad if players can already see what is going
-- to happen while the owner creates a long quest)
-- mute/unmute gets logged in the function and does not need extra log entries
local obj = yl_speak_up.speak_to[pname].obj
if(fields.mute_npc and obj) then
yl_speak_up.set_muted(pname, obj, true)
elseif(fields.un_mute_npc and obj) then
yl_speak_up.set_muted(pname, obj, false)
end
-- new options etc. may be added; store these IDs so that we can switch to the right target
local result = {}
-- make this the first dialog shown when starting a conversation
if(fields.make_first_option) then
-- check which dialog(s) previously had the highest priority and change thsoe
for k, v in pairs(dialog.n_dialogs) do
if(v and v.d_sort and (v.d_sort=="0" or v.d_sort==0)) then
-- try to derive a sensible future sort priority from the key:
-- here we make use of the d_<nr> pattern; but even if that fails to yield
-- a number, the sort function will later be able to deal with it anyway
local new_priority = string.sub(k, 3)
dialog.n_dialogs[ k ].d_sort = new_priority
end
end
-- actually make this the chat with the highest priority
dialog.n_dialogs[ d_id ].d_sort = "0"
-- this is not immediately saved, even though the changes to the previous dialog with
-- the highest priority cannot be automaticly undone (but as long as it is not saved,
-- it really does not matter; and when saving, the player has to take some care)
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": Turned into new start dialog.")
end
-- detect changes to d_text: text of the dialog (what the npc is saying)
-- (only happens in dialog edit menu)
if(fields.d_text and dialog.n_dialogs[ d_id ].d_text ~= fields.d_text) then
-- store that there have been changes to this npc
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": d_text (what the NPC says) was changed from \""..
tostring( dialog.n_dialogs[ d_id ].d_text)..
"\" to \""..tostring(fields.d_text).."\".")
-- actually change the text - but do not save to disk yet
dialog.n_dialogs[ d_id ].d_text = fields.d_text
end
-- add a new option/answer
if(fields[ "add_option"]) then
-- count the options/answers so that the limit is not exceeded
local anz_options = 0
local future_o_id = "o_" .. yl_speak_up.find_next_id(dialog.n_dialogs[d_id].d_options)
if dialog.n_dialogs[d_id].d_options == nil then
dialog.n_dialogs[d_id].d_options = {}
else
local sorted_list = yl_speak_up.get_sorted_options(dialog.n_dialogs[d_id].d_options, "o_sort")
anz_options = #sorted_list
end
-- we don't want an infinite amount of answers per dialog
if(anz_options >= yl_speak_up.max_number_of_options_per_dialog) then
-- this is already checked earlier on and the button only shown if
-- options can be added; so this can reamin a chat message
minetest.chat_send_player(pname, "Sorry. Only "..
tostring(yl_speak_up.max_number_of_options_per_dialog)..
" options/answers are allowed per dialog.")
fields.add_option = nil
else
dialog.n_dialogs[d_id].d_options[future_o_id] = {
o_id = future_o_id,
o_hide_when_prerequisites_not_met = "false",
o_grey_when_prerequisites_not_met = "false",
o_sort = -1,
o_text_when_prerequisites_not_met = "",
o_text_when_prerequisites_met = "",
}
-- necessary in order for it to work
local s = yl_speak_up.sanitize_sort(dialog.n_dialogs[d_id].d_options, yl_speak_up.speak_to[pname].o_sort)
dialog.n_dialogs[d_id].d_options[future_o_id].o_sort = s
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": Added new option/answer "..future_o_id..".")
-- if this is selected in the options edit menu, we want to move straight on to the new option
result["show_next_option"] = future_o_id
end
end
if(fields[ "del_option"] and fields.o_id and dialog.n_dialogs[d_id].d_options[fields.o_id]) then
local o_id = fields.o_id
-- which dialog to show instead of the deleted one?
local next_o_id = o_id
local sorted_list = yl_speak_up.get_sorted_options(dialog.n_dialogs[d_id].d_options, "o_sort")
for i, o in ipairs(sorted_list) do
if(o == o_id and sorted_list[ i+1 ]) then
next_o_id = sorted_list[ i+1 ]
elseif(o == o_id and sorted_list[ i-1 ]) then
next_o_id = sorted_list[ i-1 ]
end
end
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": Option "..tostring(o_id).." deleted.")
-- actually delete the dialog
dialog.n_dialogs[d_id].d_options[o_id] = nil
-- the current dialog is deleted; we need to show another one
result["show_next_option"] = next_o_id
-- after deleting the entry, all previous/further changes to it are kind of unintresting
return result
end
-- ignore entries to o_sort if they are not a number
if(fields[ "edit_option_o_sort"]
and tonumber(fields[ "edit_option_o_sort"])
and fields.o_id and dialog.n_dialogs[d_id].d_options[fields.o_id]) then
local o_id = fields.o_id
local new_nr = tonumber(fields[ "edit_option_o_sort"])
local old_nr = tonumber(dialog.n_dialogs[d_id].d_options[o_id].o_sort)
-- if the nr is -1 (do not show) then we are done already: nothing to do
if(old_nr == new_nr) then
-- -1: do not list as option/answer (but still store and keep it)
elseif(new_nr == -1 and old_nr ~= -1) then
dialog.n_dialogs[d_id].d_options[o_id].o_sort = "-1"
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": Option "..tostring(o_id).." was set to -1 (do not list).")
else
-- get the old sorted list
local sorted_list = yl_speak_up.get_sorted_options(dialog.n_dialogs[d_id].d_options, "o_sort")
-- negative numbers are not shown
local entries_shown_list = {}
for i, o in ipairs(sorted_list) do
local n = tonumber(dialog.n_dialogs[d_id].d_options[o].o_sort)
if(n and n > 0 and o ~= o_id) then
table.insert(entries_shown_list, o)
end
end
-- insert the entry at the new position and let lua do the job
table.insert(entries_shown_list, new_nr, o_id)
-- take the indices from that new list as new sort values and store them;
-- this has the side effect that duplicate entries get sorted out as well
for i, o in ipairs(entries_shown_list) do
dialog.n_dialogs[d_id].d_options[o].o_sort = tostring(i)
end
-- store that there was a cahnge
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": Option "..tostring(o_id).." was moved to position "..
tostring(new_nr)..".")
end
end
-- changes to options are not possible if there are none
if(dialog.n_dialogs[ d_id ].d_options) then
-- detect changes to text_option_<o_id>: text for option <o_id>
for k, v in pairs(dialog.n_dialogs[ d_id ].d_options) do
if( fields[ "text_option_"..k ]
and fields[ "text_option_"..k ] ~= v.o_text_when_prerequisites_met ) then
-- store that there have been changes to this npc
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": The text for option "..tostring(k)..
" was changed from \""..tostring(v.o_text_when_prerequisites_met)..
"\" to \""..tostring(fields[ "text_option_"..k]).."\".")
-- actually change the text of the option
dialog.n_dialogs[ d_id ].d_options[ k ].o_text_when_prerequisites_met = fields[ "text_option_"..k ]
end
end
-- detect changes to d_id_<o_id>: target dialog for option <o_id>
for k, v in pairs(dialog.n_dialogs[ d_id ].d_options) do
if(fields[ "d_id_"..k ]) then
local new_target_dialog = yl_speak_up.prepare_new_dialog_for_option(
dialog, pname, n_id, d_id, k, fields[ "d_id_"..k ], v.o_results)
if(new_target_dialog ~= fields[ "d_id_"..k ]) then
fields[ "d_id_"..k ] = new_target_dialog
-- in options edit menu: show this update
result["show_next_option"] = k
end
end
end
end
-- add a new dialog; either via "+" button or "New dialog" in dialog dropdown menu
-- this has to be done after all the other changes because those (text changes etc.) still
-- apply to the *old* dialog
if(fields.show_new_dialog
or(fields["d_id"] and fields["d_id"] == yl_speak_up.text_new_dialog_id)) then
-- create the new dialog and make sure it gets shown
local d_id = yl_speak_up.add_new_dialog(dialog, pname, nil)
-- actually show the new dialog
fields["d_id"] = d_id
fields["show_new_dialog"] = nil
end
-- delete one empty dialog
if(fields.delete_this_empty_dialog) then
local anz_options = 0
-- we need to show a new dialog after this one was deleted
local new_dialog = d_id
local sorted_list = yl_speak_up.get_sorted_options(dialog.n_dialogs, "d_sort")
for i, k in ipairs(sorted_list) do
-- count the options of this dialog
if(k == d_id) then
if(dialog.n_dialogs[d_id].d_options) then
for o, w in pairs(dialog.n_dialogs[d_id].d_options) do
anz_options = anz_options + 1
end
end
if(sorted_list[i+1]) then
new_dialog = sorted_list[i+1]
elseif(sorted_list[i-1]) then
new_dialog = sorted_list[i-1]
end
end
end
-- there needs to be one dialog left after deleting this one,
if(#sorted_list > 1
-- this dialog isn't allowed to hold any more options/answers
and anz_options == 0
-- we really found a new dialog to show
and new_dialog ~= d_id
-- and the text needs to be empty
and dialog.n_dialogs[ d_id ].d_text == "") then
-- actually delete this dialog
dialog.n_dialogs[ d_id ] = nil
-- ..and store it to disk
yl_speak_up.delete_dialog(n_id, d_id)
yl_speak_up.log_change(pname, n_id,
"Deleted dialog "..tostring(d_id)..".")
-- switch to another dialog (this one was deleted after all)
fields["d_id"] = new_dialog
fields["show_new_dialog"] = nil
else
-- deleting is only possible from the talk menu, and there the delete
-- button is only shown if the dialog can be deleted; so this can remain
-- a chat message
minetest.chat_send_player(pname, "Sorry. This dialog cannot be deleted (yet). "..
"It is either the only dialog left or has a non-empty text or has at "..
"least on remaining option/answer.")
end
end
-- not in options edit menu?
local o_id = fields.o_id
if(not(o_id)) then
return result
end
local d_option = dialog.n_dialogs[ d_id ].d_options[ o_id ]
-- change alternate text when preconditions are not met
-- (only happens in options edit menu)
if(fields.option_text_not_met and d_option
and d_option.o_text_when_prerequisites_not_met ~= fields.option_text_not_met) then
-- add change to changelog
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": The alternate text for option "..tostring(o_id)..
" was changed from \""..
tostring(d_option.o_text_when_prerequisites_not_met).."\" to \""..
tostring(fields.option_text_not_met).."\".")
-- actually change the text of the option
d_option.o_text_when_prerequisites_not_met = fields.option_text_not_met
end
-- toggle autoselection/autoclick of an option
if(d_option and fields.option_autoanswer and fields.option_autoanswer ~= "") then
if(d_option.o_autoanswer and d_option.o_autoanswer == 1
and fields.option_autoanswer == "by clicking on it") then
d_option.o_autoanswer = nil
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": The modus for option "..tostring(o_id)..
" was changed from \"automaticly\" to \"by clicking on it\".")
elseif((not(d_option.o_autoanswer) or d_option.o_autoanswer ~= 1)
and fields.option_autoanswer == "automaticly") then
d_option.o_autoanswer = 1
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": The modus for option "..tostring(o_id)..
" was changed from \"by clicking on it\" to \"automaticly\".")
end
end
-- handle hide/grey out/show alternate answer
-- (only happens in options edit menu)
if(fields.hide_or_grey_or_alternate_answer and d_option) then
if(fields.hide_or_grey_or_alternate_answer == "..hide this answer."
and d_option.o_hide_when_prerequisites_not_met ~= "true") then
d_option.o_hide_when_prerequisites_not_met = "true"
d_option.o_grey_when_prerequisites_not_met = "false"
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": If precondition for option "..tostring(o_id)..
" is not met, hide option/answer.")
-- make sure we show this options update next
result["show_next_option"] = o_id
elseif(fields.hide_or_grey_or_alternate_answer == "..grey out the following answer:"
and d_option.o_grey_when_prerequisites_not_met ~= "true") then
d_option.o_hide_when_prerequisites_not_met = "false"
d_option.o_grey_when_prerequisites_not_met = "true"
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": If precondition for option "..tostring(o_id)..
" is not met, grey out option/answer.")
result["show_next_option"] = o_id
elseif(fields.hide_or_grey_or_alternate_answer == "..display the following alternate answer:"
and (d_option.o_hide_when_prerequisites_not_met ~= "false"
or d_option.o_grey_when_prerequisites_not_met) ~= "false") then
d_option.o_hide_when_prerequisites_not_met = "false"
d_option.o_grey_when_prerequisites_not_met = "false"
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": If precondition for option "..tostring(o_id)..
" is not met, show alternate option/answer.")
result["show_next_option"] = o_id
end
end
-- how many times can the player fail to execute the action successfully?
if(fields[ "timer_max_attempts_on_failure"]) then
local field_name = "timer_max_attempts_on_failure"
local timer_name = "timer_on_failure_"..tostring(d_id).."_"..tostring(o_id)
if(not(tonumber(fields[ field_name ]))) then
fields[ field_name ] = 0
end
-- make sure the variable exists
if(yl_speak_up.add_time_based_variable(timer_name)) then
yl_speak_up.set_variable_metadata(timer_name, nil, "parameter", "max_attempts",
fields[ field_name ])
end
end
-- ..and how long has the player to wait in order to try again?
if(fields[ "timer_max_seconds_on_failure"]) then
local field_name = "timer_max_seconds_on_failure"
local timer_name = "timer_on_failure_"..tostring(d_id).."_"..tostring(o_id)
if(not(tonumber(fields[ field_name ]))) then
fields[ field_name ] = 0
end
-- make sure the variable exists
if(yl_speak_up.add_time_based_variable(timer_name)) then
yl_speak_up.set_variable_metadata(timer_name, nil, "parameter", "duration",
fields[ field_name ])
end
end
if(fields[ "timer_max_seconds_on_success"]) then
local field_name = "timer_max_seconds_on_success"
local timer_name = "timer_on_success_"..tostring(d_id).."_"..tostring(o_id)
if(not(tonumber(fields[ field_name ]))) then
fields[ field_name ] = 0
end
-- make sure the variable exists
if(yl_speak_up.add_time_based_variable(timer_name)) then
yl_speak_up.set_variable_metadata(timer_name, nil, "parameter", "duration",
fields[ field_name ])
end
end
-- currently only contains result["show_new_option"] (which is needed for options edit menu)
return result
end
-- end of yl_speak_up.edit_mode_apply_changes
-- identify multiple results that lead to target dialogs
yl_speak_up.check_for_disambigous_results = function(n_id, pname)
local errors_found = false

View File

@ -23,6 +23,8 @@ dofile(modpath .. "show_fs.lua")
dofile(modpath .. "fs_talkdialog.lua")
-- ask if the player wants to save, discard or go back in edit mode
dofile(modpath .. "fs_save_or_discard_or_back.lua")
-- the player wants to change something regarding the dialog
dofile(modpath .. "edit_mode_apply_changes.lua")
-- as the name says: a collection of custom functions that you can
-- override on your server or in your game to suit your needs;
-- Note: No special privs are needed to call custom functions. But...