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(..)
-- and also by yl_speak_up.get_fs_trade_list(..)
--
-- This function is called *after* the player has clicked on an option
-- 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
return false
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;"..
"by clicking on it,automaticly,randomly;"..tostring(answer_mode+1)..";]"
-- (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
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(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..
"label[1.2,0.8;A:]"..
"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 "..
"prerequirements are fullfilled.]"..
"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.6;This is useful for offering a diffrent start dialog depending on the "..
"player's progress in a quest.]"..
"container_end[]"
"label[1.2,2.0;The NPC will proceed as if this option was choosen manually.]"..
"label[1.2,2.6;"
if(d_id == "d_got_item") then
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
answer_text = answer_text..
"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
local res = yl_speak_up.get_list_of_effects_and_target_dialog_and_effect(dialog, results, pname,
target_dialog, target_effect)
list_of_effects = res.list
local list_of_effects = res.list
target_dialog = res.target_dialog
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"..
"selected.\n"..
"Please click on an (Ef)fect in order to edit or delete it!]"..
"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
"dropdown[10.2,0.0;3.0,0.7;d_id_"..minetest.formspec_escape(o_id)..";"..
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
"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.]"..
"label[0.4,0.4;The NPC will react to this answer with dialog:]"..
yl_speak_up.show_colored_dialog_text(
dialog,
-- 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")..
"container_end[]"
end
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 "..
"default setup when adding a new option here)."..
"\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
table.insert(formspec, "textarea[0.2,5;19.6,17.8;d_text;;"..
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"
and (dialog.n_dialogs[v.r_value] ~= nil
or v.r_value == "d_end"
or v.r_value == "d_trade"
or v.r_value == "d_got_item") then
-- there may be more than one in the data structure
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.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 not, we grab in from context.
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.]"..
"button_exit[2,1.5;1,0.9;exit;Exit]"
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
-- 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)
-- ...and this option needs to be selected automaticly
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
local future_r_id = nil
-- 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_type = "deal_with_offered_item",
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
return future_o_id
end