added special d_trade dialog; efects based on preconditions can now be executed before showing the trade_list

This commit is contained in:
Sokomine 2022-10-28 13:30:19 +02:00
parent 4b34c46453
commit 5fd501187d
6 changed files with 154 additions and 10 deletions

View File

@ -32,6 +32,7 @@ end
-- called by yl_speak_up.input_talk(..) -- called by yl_speak_up.input_talk(..)
-- and also by yl_speak_up.get_fs_trade_list(..)
-- --
-- This function is called *after* the player has clicked on an option -- This function is called *after* the player has clicked on an option
-- and *after* any actions (i.e. trade) have been completed either -- and *after* any actions (i.e. trade) have been completed either

View File

@ -403,3 +403,55 @@ yl_speak_up.eval_precondition = function(player, n_id, p, other_options_true_or_
-- fallback - unknown type -- fallback - unknown type
return false return false
end end
-- helper function for yl_speak_up.eval_trade_list_preconditions
yl_speak_up.eval_precondition_npc_inv = function(p, inv, inv_name)
if(p.p_type ~= "npc_inv") then
return false
end
-- determine the right inventory
if( p.p_itemstack and p.p_value == "inv_contains") then
return inv:contains_item(inv_name, p.p_itemstack)
elseif(p.p_itemstack and p.p_value == "inv_does_not_contain") then
return not(inv:contains_item(inv_name, p.p_itemstack))
elseif(p.p_itemstack and p.p_value == "has_room_for") then
return inv:room_for_item(inv_name, p.p_itemstack)
elseif(p.p_value == "inv_is_empty") then
return inv:is_empty(inv_name)
end
return false
end
-- cheaper version of eval_all_preconditions for the trade_list (d_trade);
-- returns the ID of the first option where the precondition match or nil;
-- *only* preconditions of the type "npc_inv" are evaluated!
yl_speak_up.eval_trade_list_preconditions = function(player)
local pname = player:get_player_name()
local dialog = yl_speak_up.speak_to[pname].dialog
local n_id = yl_speak_up.speak_to[pname].n_id
if(not(dialog) or not(dialog.n_dialogs) or not(dialog.n_dialogs["d_trade"])
or not(dialog.n_dialogs["d_trade"].d_options)) then
return
end
local options = dialog.n_dialogs["d_trade"].d_options
local sorted_o_list = yl_speak_up.get_sorted_options(options, "o_sort")
local inv = minetest.get_inventory({type="detached", name="yl_speak_up_npc_"..tostring(n_id)})
local inv_name = "npc_main"
-- search through all options
for i, s_o_id in ipairs(sorted_o_list) do
local prereq = options[s_o_id].o_prerequisites
local all_ok = true
for k, p in pairs(prereq) do
if(not(yl_speak_up.eval_precondition_npc_inv(p, inv, inv_name))) then
all_ok = false
break
end
end
if(all_ok) then
return s_o_id
end
end
end

View File

@ -243,14 +243,14 @@ yl_speak_up.get_fs_edit_option_dialog = function(player, n_id, d_id, o_id, calle
"dropdown[16.0,-0.4;5.3,0.7;option_autoanswer;".. "dropdown[16.0,-0.4;5.3,0.7;option_autoanswer;"..
"by clicking on it,automaticly,randomly;"..tostring(answer_mode+1)..";]" "by clicking on it,automaticly,randomly;"..tostring(answer_mode+1)..";]"
-- (automaticly *by fulfilling the prerequirements*) -- (automaticly *by fulfilling the prerequirements*)
if(d_id == "d_got_item") then if(d_id == "d_got_item" or d_id == "d_trade") then
answer_mode = 1 answer_mode = 1
d_option.o_autoanswer = 1 d_option.o_autoanswer = 1
answer_text = answer_text =
"container[0.0,7.3]".. "container[0.0,7.3]"..
"label[0.2,0.0;..this option will be selected automaticly.]" "label[0.2,0.0;..this option will be selected automaticly.]"
end end
if(answer_mode == 0 and d_id ~= "d_got_item") then if(answer_mode == 0 and (d_id ~= "d_got_item" and d_id ~= "d_trade")) then
answer_text = answer_text.. answer_text = answer_text..
"label[1.2,0.8;A:]".. "label[1.2,0.8;A:]"..
"field[1.7,0.3;19.6,0.9;text_option_"..minetest.formspec_escape(o_id)..";;".. "field[1.7,0.3;19.6,0.9;text_option_"..minetest.formspec_escape(o_id)..";;"..
@ -276,10 +276,22 @@ yl_speak_up.get_fs_edit_option_dialog = function(player, n_id, d_id, o_id, calle
"label[1.2,0.8;This option will not be shown but will be selected automaticly if all ".. "label[1.2,0.8;This option will not be shown but will be selected automaticly if all "..
"prerequirements are fullfilled.]".. "prerequirements are fullfilled.]"..
"label[1.2,1.4;The remaining options of this dialog will in this case not be evaluated.]".. "label[1.2,1.4;The remaining options of this dialog will in this case not be evaluated.]"..
"label[1.2,2.0;The NPC will proceed as if this dialog was choosen manually.]".. "label[1.2,2.0;The NPC will proceed as if this option was choosen manually.]"..
"label[1.2,2.6;This is useful for offering a diffrent start dialog depending on the ".. "label[1.2,2.6;"
"player's progress in a quest.]".. if(d_id == "d_got_item") then
"container_end[]" answer_text = answer_text..
"Note: This is used here to process items that the player gave to the NPC."
elseif(d_id == "d_trade") then
answer_text = answer_text..
"Note: This is useful for refilling stock by crafting new things when "..
"necessary, or for getting\nsupplies from a storage, or for storing "..
"traded goods in external storage chests."
else
answer_text = answer_text..
"This is i.e. useful for offering a diffrent start dialog depending on the "..
"player's progress in a quest."
end
answer_text = answer_text .. "]container_end[]"
elseif(answer_mode == 2) then elseif(answer_mode == 2) then
answer_text = answer_text.. 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,0.8;One option of the dialog - for example this one - will be selected randomly.]"..
@ -384,7 +396,7 @@ yl_speak_up.get_fs_edit_option_dialog = function(player, n_id, d_id, o_id, calle
-- constructs the list_of_effects; may also update target_dialog and target_effect -- constructs the list_of_effects; may also update target_dialog and target_effect
local res = yl_speak_up.get_list_of_effects_and_target_dialog_and_effect(dialog, results, pname, local res = yl_speak_up.get_list_of_effects_and_target_dialog_and_effect(dialog, results, pname,
target_dialog, target_effect) target_dialog, target_effect)
list_of_effects = res.list local list_of_effects = res.list
target_dialog = res.target_dialog target_dialog = res.target_dialog
target_effect = res.target_effect target_effect = res.target_effect
@ -615,8 +627,14 @@ yl_speak_up.get_fs_edit_option_dialog = function(player, n_id, d_id, o_id, calle
"(Ef)fects will always be executed when this option here is\n".. "(Ef)fects will always be executed when this option here is\n"..
"selected.\n".. "selected.\n"..
"Please click on an (Ef)fect in order to edit or delete it!]".. "Please click on an (Ef)fect in order to edit or delete it!]"..
"container[0.0,3.2]".. "container[0.0,3.2]"..
"label[0.4,0.4;The NPC will react to this answer with dialog:]"
if(d_id == "d_trade") then
action_text = action_text..
"label[13.5,0.4;..by showing his trade list.]"..
"container_end[]"
else
action_text = action_text..
-- allow to change the target dialog via a dropdown menu -- allow to change the target dialog via a dropdown menu
"dropdown[10.2,0.0;3.0,0.7;d_id_"..minetest.formspec_escape(o_id)..";".. "dropdown[10.2,0.0;3.0,0.7;d_id_"..minetest.formspec_escape(o_id)..";"..
dialog_list..";"..dialog_selected..",]".. dialog_list..";"..dialog_selected..",]"..
@ -627,7 +645,6 @@ yl_speak_up.get_fs_edit_option_dialog = function(player, n_id, d_id, o_id, calle
-- ..and what the NPC will reply to that answer -- ..and what the NPC will reply to that answer
"tooltip[1.2,0.7;19.6,2.5;This is what the NPC will say next when the player has ".. "tooltip[1.2,0.7;19.6,2.5;This is what the NPC will say next when the player has "..
"selected this answer here.]".. "selected this answer here.]"..
"label[0.4,0.4;The NPC will react to this answer with dialog:]"..
yl_speak_up.show_colored_dialog_text( yl_speak_up.show_colored_dialog_text(
dialog, dialog,
-- this is either the "dialog" effect or an empty fallback -- this is either the "dialog" effect or an empty fallback
@ -639,7 +656,7 @@ yl_speak_up.get_fs_edit_option_dialog = function(player, n_id, d_id, o_id, calle
"", "",
"button_edit_action_success_dialog").. "button_edit_action_success_dialog")..
"container_end[]" "container_end[]"
end
end end
action_text = action_text.."container_end[]" action_text = action_text.."container_end[]"

View File

@ -413,6 +413,39 @@ yl_speak_up.get_fs_talkdialog_main_text_in_edit_mode = function(
"You can also work with an alternate text here (as is done in the ".. "You can also work with an alternate text here (as is done in the "..
"default setup when adding a new option here).".. "default setup when adding a new option here)."..
"\n</normal>]") "\n</normal>]")
-- static help text instead of text input field for d_trade
elseif(c_d_id == "d_trade") then
table.insert(formspec, "hypertext[0.2,5;19.6,17.8;d_text;"..
"<normal>Note:\nThis is a special dialog."..
"It will be called when the player clicks on "..
"<b>Let's trade!</b>."..
"\nSome of the things listed below will be added automaticly when you add a "..
"new option to this dialog. In most cases you may just have to edit the "..
"<b>precondition</b> so that the <i>right item(stack)</i> is beeing "..
"searched for, and you need to add suitable effects. The ones added "..
"automaticly are just an example."..
"\nNote that once the NPC found a matching precondition, it will execute the "..
"relevant effects and present the player the trade list. Any further options "..
"that might also fit will not be executed this time. Only <b>one</b> option "..
"(or none) will be selected each time."..
"\nThis is how it works in detail:"..
"\n<b>Each option</b> you add here ought to deal with one item(stack) that "..
"the NPC might or might not have in its inventory, "..
"i.e. <i>default:stick 4</i>. "..
"Each option needs to be selected <b>automaticly</b> and ought to contain:"..
"\n* at least one <b>precondition</b> regarding "..
"<b>the inventory of the NPC</b> "..
"where you define which item(stack) is relevant for this option "..
"(you can add multiple such preconditions for each option)"..
"\n* at least one <b>effect</b> regarding what the NPC shall do if the "..
"precondition matches. In most cases, <b>NPC crafts something</b>, "..
"<b>put item from the NPC's inventory into a chest etc.</b> or "..
"<b>take item from a chest etc. and put it into the NPC's inventory</b> "..
"will be what you are looking for. More than one effect is possible."..
"\n* In this particular case, no target dialog needs to be selected. After "..
"executing the effect(s), the trade list view will be shown to the "..
"player."..
"\n</normal>]")
elseif(active_dialog and active_dialog.d_text) then elseif(active_dialog and active_dialog.d_text) then
table.insert(formspec, "textarea[0.2,5;19.6,17.8;d_text;;".. table.insert(formspec, "textarea[0.2,5;19.6,17.8;d_text;;"..
minetest.formspec_escape(active_dialog.d_text or "?").. minetest.formspec_escape(active_dialog.d_text or "?")..
@ -507,6 +540,7 @@ yl_speak_up.get_fs_talkdialog_line_in_edit_mode = function(
if v.r_type == "dialog" if v.r_type == "dialog"
and (dialog.n_dialogs[v.r_value] ~= nil and (dialog.n_dialogs[v.r_value] ~= nil
or v.r_value == "d_end" or v.r_value == "d_end"
or v.r_value == "d_trade"
or v.r_value == "d_got_item") then or v.r_value == "d_got_item") then
-- there may be more than one in the data structure -- there may be more than one in the data structure
target_dialog = v.r_value target_dialog = v.r_value
@ -735,6 +769,11 @@ yl_speak_up.get_fs_talkdialog = function(player, n_id, d_id, alternate_text, rec
yl_speak_up.trade[pname] = nil yl_speak_up.trade[pname] = nil
yl_speak_up.speak_to[pname].trade_id = nil yl_speak_up.speak_to[pname].trade_id = nil
-- add a d_trade dialog if necessary
if(dialog and dialog.trades and dialog.n_dialogs and not(dialog.n_dialogs["d_trade"])) then
yl_speak_up.add_new_dialog(dialog, pname, "trade", "[no text]")
end
--[[ If we have an explicit call for a certain d_id, we grab it from parameters. --[[ If we have an explicit call for a certain d_id, we grab it from parameters.
If not, we grab in from context. If not, we grab in from context.
When neither are present, we grab it from d_sort When neither are present, we grab it from d_sort

View File

@ -124,6 +124,17 @@ yl_speak_up.get_fs_trade_list = function(player, show_dialog_option_trades)
"label[0.2,0.5;Ups! This NPC lacks ID or name.]".. "label[0.2,0.5;Ups! This NPC lacks ID or name.]"..
"button_exit[2,1.5;1,0.9;exit;Exit]" "button_exit[2,1.5;1,0.9;exit;Exit]"
end end
-- the trade list is a bit special - we need to evaluate the preconditions of the
-- options of the d_talk dialog and execute corresponding effects; this can be used
-- to refill stock from chests or craft new items to increase stock
local do_o_id = yl_speak_up.eval_trade_list_preconditions(player)
if(do_o_id) then
local effects = dialog.n_dialogs["d_trade"].d_options[do_o_id].o_results
-- the return value is of no intrest here - we won't be showing another dialog,
-- and alternate_text isn't relevant either; we just do the effects and then show
-- the trade list
local res = yl_speak_up.execute_all_relevant_effects(player, effects, do_o_id, true)
end
if(not(yl_speak_up.may_edit_npc(player, n_id))) then if(not(yl_speak_up.may_edit_npc(player, n_id))) then
-- do not show trades attached to dialog options for players who cannot edit the NPC -- do not show trades attached to dialog options for players who cannot edit the NPC

View File

@ -302,6 +302,11 @@ yl_speak_up.add_new_option = function(dialog, pname, next_id, d_id, option_text,
target_dialog = yl_speak_up.get_start_dialog_id(dialog) target_dialog = yl_speak_up.get_start_dialog_id(dialog)
-- ...and this option needs to be selected automaticly -- ...and this option needs to be selected automaticly
dialog.n_dialogs[d_id].d_options[future_o_id].o_autoanswer = 1 dialog.n_dialogs[d_id].d_options[future_o_id].o_autoanswer = 1
elseif(d_id == "d_trade") then
-- we really don't want to go to another dialog from here
target_dialog = "d_trade"
-- ...and this option needs to be selected automaticly
dialog.n_dialogs[d_id].d_options[future_o_id].o_autoanswer = 1
end end
local future_r_id = nil local future_r_id = nil
-- create a fitting dialog result automaticly if possible: -- create a fitting dialog result automaticly if possible:
@ -342,6 +347,25 @@ yl_speak_up.add_new_option = function(dialog, pname, next_id, d_id, option_text,
r_id = future_r_id, r_id = future_r_id,
r_type = "deal_with_offered_item", r_type = "deal_with_offered_item",
r_value = "take_all"} r_value = "take_all"}
-- the trade dialog is equally special
elseif(d_id == "d_trade") then
dialog.n_dialogs[d_id].d_options[future_o_id].o_prerequisites = {}
-- this is just an example
dialog.n_dialogs[d_id].d_options[future_o_id].o_prerequisites["p_1"] = {
p_id = "p_1",
p_type = "npc_inv",
p_value = "inv_does_not_contain",
p_inv_list_name = "npc_main",
p_itemstack = "default:stick "..tostring(100-next_id)}
future_r_id = yl_speak_up.add_new_result(dialog, d_id, future_o_id)
-- example craft
dialog.n_dialogs[d_id].d_options[future_o_id].o_results[future_r_id] = {
r_id = future_r_id,
r_type = "craft",
r_value = "default:stick 4",
o_sort = "1",
r_craft_grid = {"default:wood", "", "", "", "", "", "", "", ""}}
end end
return future_o_id return future_o_id
end end