added random option for dialogs

This commit is contained in:
Sokomine 2022-09-23 23:10:53 +02:00
parent 7f60031ab1
commit 90dc2d34d5
4 changed files with 105 additions and 22 deletions

View File

@ -300,6 +300,25 @@ once it hits an option where selecting has been set to "automaticly" and all oth
preconditions are true, it will abort processing the current dialog and move on to
the dialog stated in the automaticly selected option/answer and display that one.
Random Dialogs
==============
If you want the NPC to answer with one of several texts (randomly selected), then
add a new dialog with options/answers that lead to your random texts and edit one
of these options so that it is "randomly" selected.
Note that random selection affects the entire dialog! That dialogs' text isn't shown
anymore, and neither are the texts of the options/answers shown. Whenever your NPC
ends up at this dialog, he'll automaticly choose one of the options/answers randomly
and continue there!
Maximum recursion depth
=======================
Autoselect/autoanswer and random dialogs may both lead to further dialogs with further
autoanswers and/or random selections. As this might create infinite loops, there's a
maximum number of "redirections" through autoanswer and random selection that your NPC
can take. It is configured in config.lua as
yl_speak_up.max_allowed_recursion_depth
and usually set to 5.
Giving things to the NPC
========================
There are several ways of giving items to the NPC: trade, using an action where the

View File

@ -349,18 +349,41 @@ yl_speak_up.edit_mode_apply_changes = function(pname, fields)
-- 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\".")
local old_answer_mode = "by clicking on it"
if(dialog.n_dialogs[ d_id ].o_random) then
old_answer_mode = "randomly"
elseif(d_option.o_autoanswer and d_option.o_autoanswer == 1) then
old_answer_mode = "automaticly"
end
if(fields.otpion_autoanswer ~= old_answer_mode) then
local new_answer_mode = ""
if(fields.option_autoanswer == "by clicking on it") then
d_option.o_autoanswer = nil
-- the dialog is no longer random
dialog.n_dialogs[ d_id ].o_random = nil
new_answer_mode = fields.option_autoanswer
elseif(fields.option_autoanswer == "automaticly") then
d_option.o_autoanswer = 1
-- the dialog is no longer random
dialog.n_dialogs[ d_id ].o_random = nil
new_answer_mode = fields.option_autoanswer
elseif(fields.option_autoanswer == "randomly") then
d_option.o_autoanswer = nil
-- the entire dialog needs to be set to randomly - not just this option
dialog.n_dialogs[ d_id ].o_random = 1
new_answer_mode = fields.option_autoanswer
end
if(new_answer_mode ~= "" and new_answer_mode ~= old_answer_mode) then
local random_was_changed = ""
if(new_answer_mode == "randomly" or old_answer_mode == "randomly") then
random_was_changed = " Note that changes to/from \"randomly\" "..
"affect the entire dialog!"
end
table.insert(yl_speak_up.npc_was_changed[ n_id ],
"Dialog "..d_id..": The modus for option "..tostring(o_id)..
" was changed from \""..old_answer_mode.."\" to \""..
new_answer_mode.."\"."..random_was_changed)
end
end
end

View File

@ -187,27 +187,31 @@ yl_speak_up.get_fs_edit_option_dialog = function(player, n_id, d_id, o_id, calle
alternate_answer_option = "2"
end
local answer_mode = 0
-- shall this option be choosen automaticly?
local autoanswer = 0
if(d_option.o_autoanswer and d_option.o_autoanswer == 1) then
autoanswer = 1
answer_mode = 1
-- or randomly?
elseif(n_dialog.o_random) then
answer_mode = 2
end
local answer_text =
-- answer of the player (the actual option)
"container[0.0,7.3]"..
"label[0.2,0.0;..the player may answer with this text"..
minetest.formspec_escape(" [dialog option \""..tostring(o_id).."\"]:").."]"..
"dropdown[16.0,-0.4;5.3,0.7;option_autoanswer;"..
"by clicking on it,automaticly;"..tostring(autoanswer+1)..";]"
"by clicking on it,automaticly,randomly;"..tostring(answer_mode+1)..";]"
-- (automaticly *by fulfilling the prerequirements*)
if(d_id == "d_got_item") then
autoanswer = 1
answer_mode = 1
d_option.o_autoanswer = 1
answer_text =
"container[0.0,7.3]"..
"label[0.2,0.0;..this option will be selected automaticly.]"
end
if(autoanswer == 0 and d_id ~= "d_got_item") then
if(answer_mode == 0 and d_id ~= "d_got_item") then
answer_text = answer_text..
"label[1.2,0.8;A:]"..
"field[1.7,0.3;19.6,0.9;text_option_"..minetest.formspec_escape(o_id)..";;"..
@ -228,7 +232,7 @@ yl_speak_up.get_fs_edit_option_dialog = function(player, n_id, d_id, o_id, calle
"tooltip[option_text_not_met;This is the answer the player may choose if the "..
"preconditions are NOT all fulfilled.]"..
"container_end[]"
else
elseif(answer_mode == 1) then
answer_text = answer_text..
"label[1.2,0.8;This option will not be shown but will be selected automaticly if all "..
"prerequirements are fullfilled.]"..
@ -237,6 +241,13 @@ yl_speak_up.get_fs_edit_option_dialog = function(player, n_id, d_id, o_id, calle
"label[1.2,2.6;This is useful for offering a diffrent start dialog depending on the "..
"player's progress in a quest.]"..
"container_end[]"
elseif(answer_mode == 2) then
answer_text = answer_text..
"label[1.2,0.8;One option of the dialog - for example this one - will be selected randomly.]"..
"label[1.2,1.4;The other options of this dialog will be set to random as well.]"..
"label[1.2,2.0;The NPC will proceed as if this dialog was choosen manually.]"..
"label[1.2,2.6;Useful for small talk for generic NPC but usually not for quests.]"..
"container_end[]"
end
-- remember which option we are working at (better than a hidden field)
@ -269,8 +280,8 @@ yl_speak_up.get_fs_edit_option_dialog = function(player, n_id, d_id, o_id, calle
local actions = d_option.actions
local count_actions = 0
local action_data = nil
-- if autoanswer is choosen, then there can be no action
if(autoanswer == 1) then
-- if autoanswer or random is choosen, then there can be no action
if(answer_mode == 1 or answer_mode == 2) then
actions = nil
count_actions = 0
caller = ""
@ -300,10 +311,14 @@ yl_speak_up.get_fs_edit_option_dialog = function(player, n_id, d_id, o_id, calle
"container[0.0,11.0]"..
"label[0.2,0.0;When this answer has been selected, start the following (A)ction:]"..
"tablecolumns[text;color,span=1;text;text]"
if(autoanswer == 1) then
if(answer_mode == 1) then
action_list_text = action_list_text..
"label[1.2,0.6;No actions are executed because this option here is automaticly selected.]"..
"container_end[]"
elseif(answer_mode == 2) then
action_list_text = action_list_text..
"label[1.2,0.6;No actions are executed because this option here is selected randomly.]"..
"container_end[]"
else
action_list_text = action_list_text..
"table[1.2,0.3;20.2,0.7;table_of_actions;"..

View File

@ -530,6 +530,11 @@ yl_speak_up.get_fs_talkdialog_line_in_edit_mode = function(
"label["..tostring(9.9+offset+0.2)..","..tostring(h+0.5)..";"..
minetest.formspec_escape("[Automaticly selected if preconditions are met]")..
"]")
elseif(active_dialog.o_random) then
table.insert(formspec,
"label["..tostring(9.9+offset+0.2)..","..tostring(h+0.5)..";"..
minetest.formspec_escape("[One of these options is randomly selected]")..
"]")
else
-- show the actual text for the option
yl_speak_up.add_formspec_element_with_tooltip_if(formspec,
@ -724,10 +729,30 @@ yl_speak_up.get_fs_talkdialog = function(player, n_id, d_id, alternate_text, rec
local allowed = yl_speak_up.calculate_displayable_options(pname, active_dialog.d_options, edit_mode,
-- avoid loops by limiting max recoursion depths for autoanswers
(recursion_depth < yl_speak_up.max_allowed_recursion_depth))
-- autoanswer or o_random may force to select a particular dialog
local go_to_next_dialog = nil
-- abort here if needed - the autoanswer/autoselection did choose an option for us alread
if(not(edit_mode) and allowed and allowed["autoanswer"] and allowed["autoanswer"] ~= "") then
go_to_next_dialog = allowed["autoanswer"]
-- randomly select an answer
elseif(not(edit_mode) and allowed and active_dialog.o_random
and (recursion_depth < yl_speak_up.max_allowed_recursion_depth)) then
local liste = {}
-- only allowed options can be randomly selected from
for o_id, v in pairs(allowed) do
if(v) then
table.insert(liste, o_id)
end
end
-- randomly select one of the possible dialogs
if(#liste > 0) then
go_to_next_dialog = liste[math.random(1, #liste)]
end
end
if(go_to_next_dialog and go_to_next_dialog ~= "") then
-- no actions shall be executed
local o_id = allowed["autoanswer"]
local o_id = go_to_next_dialog
local effects = active_dialog.d_options[o_id].o_results
-- execute all effects/results
local res = yl_speak_up.execute_all_relevant_effects(player, effects, o_id, true)
@ -769,6 +794,7 @@ yl_speak_up.get_fs_talkdialog = function(player, n_id, d_id, alternate_text, rec
end
end
yl_speak_up.speak_to[pname].allowed = allowed