added yl_speak_up.execute_next_action and general action handling

This commit is contained in:
Sokomine 2021-06-18 04:36:59 +02:00
parent 2290f9d463
commit 9ed4cfc92d
3 changed files with 135 additions and 63 deletions

View File

@ -119,13 +119,100 @@ yl_speak_up.show_action = function(a)
end
yl_speak_up.execute_all_actions = function(player, actions, o_id)
-- TODO: implement execute_all_actions
-- actions - in contrast to preconditions and effects - may take time
-- because the player usually gets presented a formspec and needs to
-- react to that; thus, we can't just execute all actions simultaneously
yl_speak_up.execute_next_action = function(player, a_id, result_of_a_id)
local pname = player:get_player_name()
local n_id = yl_speak_up.speak_to[pname].n_id
local d_id = yl_speak_up.speak_to[pname].d_id
local o_id = yl_speak_up.speak_to[pname].o_id
local dialog = yl_speak_up.speak_to[pname].dialog
yl_speak_up.debug_msg(player, n_id, o_id, "Last action: "..tostring(a_id).." returned "..
tostring(result_of_a_id)..".")
local actions = {}
local effects = {}
local sorted_key_list = {}
if(dialog
and dialog.n_dialogs
and dialog.n_dialogs[d_id]
and dialog.n_dialogs[d_id].d_options
and dialog.n_dialogs[d_id].d_options[o_id]
and dialog.n_dialogs[d_id].d_options[o_id].actions) then
-- get the actual actions
actions = dialog.n_dialogs[d_id].d_options[o_id].actions
-- needed later on when all actions are executed
effects = dialog.n_dialogs[d_id].d_options[o_id].o_results
-- sort the actions so that we can execute them always in the
-- same order
sorted_key_list = yl_speak_up.sort_keys(actions)
local nr = 0
if(a_id) then
nr = table.indexof(sorted_key_list, a_id)
-- did the action fail?
if(nr > -1 and not(result_of_a_id)) then
local this_action = actions[ sorted_key_list[ nr ]]
-- if there is an on_failure target dialog: go there
if(this_action.a_on_failure) then
-- set the current action to nil
yl_speak_up.speak_to[pname].a_id = nil
-- no option of the new dialog has been selected yet
yl_speak_up.speak_to[pname].o_id = nil
-- show the new dialog
yl_speak_up.debug_msg(player, n_id, o_id, "Action "..
tostring(a_id).." failed. Switching to dialog "..
tostring(this_action.a_on_failure)..".")
yl_speak_up.show_fs(player, "talk", {n_id = n_id,
d_id = this_action.a_on_failure})
return
else
yl_speak_up.debug_msg(player, n_id, o_id, "Action "..
tostring(a_id).." failed, but no a_on_failure target "..
"dialog defined. Continuing execution.")
end
end
end
-- get the next entry
if(nr > -1 and nr < #sorted_key_list and sorted_key_list[nr + 1]) then
local next_action = actions[ sorted_key_list[ nr + 1 ]]
-- store which action we are currently executing
yl_speak_up.speak_to[pname].a_id = next_action.a_id
-- execute the next action
yl_speak_up.debug_msg(player, n_id, o_id, "Executing next action "..
tostring(next_action.a_id)..".")
yl_speak_up.execute_action(player, n_id, o_id, next_action)
-- the player needs time to react
return
end
end
-- when all actions are executed:
-- set the current action to nil
yl_speak_up.speak_to[pname].a_id = nil
yl_speak_up.debug_msg(player, n_id, o_id, "All actions have been executed successfully. "..
"Doing effects/results now.")
-- execute all effects/results
local target_dialog = yl_speak_up.execute_all_relevant_effects(player, effects, o_id, true)
-- the function above returns a target dialog; show that to the player
yl_speak_up.show_fs(player, "talk", {n_id = n_id, d_id = target_dialog})
end
yl_speak_up.execute_action = function(player, n_id, o_id, r)
-- TODO: implement execute_action. boils down to showing formspecs
yl_speak_up.execute_action = function(player, n_id, o_id, a)
if(not(a.a_type) or a.a_type == "" or a.a_type == "none") then
-- no action - nothing to do
return true
elseif(a.a_type == "trade") then
yl_speak_up.show_fs(player, "trade_simple", a.a_value)
return
elseif(a.a_type == "npc_gives") then
-- TODO implement npc_gives action
elseif(a.a_type == "npc_wants") then
-- TODO implement npc_wants action
elseif(a.a_type == "text_input") then
-- TODO implement text_input action
elseif(a.a_type == "custom") then
-- TODO implement custom action
end
-- fallback: unkown type
return false
end

View File

@ -2450,6 +2450,26 @@ yl_speak_up.input_talk = function(player, formname, fields)
local dialog = yl_speak_up.speak_to[pname].dialog
-- we may soon need actions and o_results from the selected_option
local selected_option = {}
if(d_id and o and dialog
and dialog.n_dialogs
and dialog.n_dialogs[d_id]
and dialog.n_dialogs[d_id].d_options
and dialog.n_dialogs[d_id].d_options[o]) then
selected_option = dialog.n_dialogs[d_id].d_options[o]
end
if(not(edit_mode)) then
-- abort if the option does not exist
if(not(selected_option)) then
return
end
yl_speak_up.speak_to[pname].o_id = o
-- start with executing the first action
yl_speak_up.execute_next_action(player, nil, true)
return
end
-- all three buttons (pre(C)onditions, (Ef)fects, edit option) lead to the same new formspec
if( edit_mode ) then
@ -2468,15 +2488,25 @@ yl_speak_up.input_talk = function(player, formname, fields)
end
end
end
-- in edit mode: another dialog was selected
if ( o == "" and edit_mode) then
-- in edit mode: has another dialog been selected?
-- if nothing better can be found: keep the old dialog
local show_dialog = d_id
-- an option button was selected;
-- since we do not execute actions and effects in edit mode, we need to find out the
-- right target dialog manually (and assume all went correct)
if( o ~= "" ) then
-- find out the normal target dialog of this option
if(selected_option and selected_option.o_results) then
for k, v in pairs(selected_option.o_results) do
if(v and v.r_type == "dialog") then
show_dialog = v.v_value
end
end
end
-- dropdown menu was used; provided the dialog exists (and it's not the "New dialog" option)
-- (if a new dialog was added using the "+" button, fields.d_id gets set accordingly)
if(fields.d_id and fields.d_id ~= show_dialog and dialog.n_dialogs[fields.d_id]) then
elseif(fields.d_id and fields.d_id ~= show_dialog and dialog.n_dialogs[fields.d_id]) then
show_dialog = fields.d_id
-- in edit mode: prev_dialog_../next_dialog_.. was selected
else
@ -2498,42 +2528,9 @@ yl_speak_up.input_talk = function(player, formname, fields)
-- no option was selected - so we need to end this here
return
end
local n_dialog = dialog.n_dialogs[d_id]
-- if there are no options, there can be no results either
if(not(n_dialog) or not(n_dialog.d_options)) then
return
end
local d_option = n_dialog.d_options[o]
-- which dialog do we have to show next?
-- determine that by executing the effects
local target_dialog = yl_speak_up.execute_all_relevant_effects(
player, d_option.o_results, o, true) --action_was_successful) --TODO
-- if there is a trade associated with this dialog and option, show that trade now
local trade_id = tostring(d_id).." "..tostring(o)
if(dialog.trades and dialog.trades[ trade_id ]) then
-- remember which option was selected
yl_speak_up.speak_to[pname].o_id = o
-- which dialog shall be shown in case of a successful trade?
yl_speak_up.speak_to[pname].target_d_id = target_dialog
-- show the trade dialog
yl_speak_up.show_fs(player, "trade_simple", trade_id)
return
end
-- else switch to the target dialog as stated in results/effects
if(target_dialog ~= d_id) then
-- if there are any changes done: ask first and don't switch to the new dialog yet
yl_speak_up.save_changes_and_switch_to_other_dialog(player, fields, target_dialog)
return
end
end
-- Make the NPC talk
function yl_speak_up.config(clicker, npc)

View File

@ -140,30 +140,16 @@ yl_speak_up.input_do_trade_simple = function(player, formname, fields)
-- go back to the main dialog
if(fields.abort_trade_simple or fields.quit or fields.finished_trading) then
local n_id = yl_speak_up.speak_to[pname].n_id
local d_id = yl_speak_up.speak_to[pname].d_id
local o_id = yl_speak_up.speak_to[pname].o_id
local target_dialog = d_id
-- if at least one successful trade has happened: show the target dialog
-- (else show the current dialog again)
if(trade and trade.trade_done > 0 and yl_speak_up.speak_to[pname].target_d_id) then
target_dialog = yl_speak_up.speak_to[pname].target_d_id
end
-- was the action a success?
local success = not(not(trade and trade.trade_done and trade.trade_done > 0))
local a_id = trade.a_id
yl_speak_up.debug_msg(player, n_id, o_id, "Ending trade.")
-- done trading
yl_speak_up.speak_to[pname].target_d_id = nil
yl_speak_up.speak_to[pname].trade_id = nil
-- if in edit mode: go back to the edit options dialog
if(yl_speak_up.edit_mode[pname] == n_id and n_id and o_id) then
-- go to the edit options dialog
yl_speak_up.show_fs(player, "edit_option_dialog",
{n_id = n_id, d_id = d_id, o_id = o_id})
return
-- show either the current or the target dialog
elseif(target_dialog) then
yl_speak_up.show_fs(player, "talk", {n_id = n_id, d_id = target_dialog})
return
end
-- execute the next action
yl_speak_up.execute_next_action(player, a_id, success)
return
end
-- show this formspec again
@ -564,6 +550,8 @@ yl_speak_up.get_fs_trade_simple = function(player, trade_id)
trade.edit_trade = true
end
yl_speak_up.trade[pname] = trade
-- store which action we are working at
trade.a_id = yl_speak_up.speak_to[pname].a_id
else
trade_id = yl_speak_up.speak_to[pname].trade_id
trade.trade_id = trade_id