From d3d90134eef548bac619e84f7cf214245ba31854 Mon Sep 17 00:00:00 2001 From: Sokomine Date: Fri, 11 Jun 2021 00:20:40 +0200 Subject: [PATCH] yl_speak_up.execute_all_relevant_effects --- fs_edit_effects.lua | 67 +++++++++++++++++++++++++-- functions.lua | 110 ++++---------------------------------------- 2 files changed, 72 insertions(+), 105 deletions(-) diff --git a/fs_edit_effects.lua b/fs_edit_effects.lua index af29901..2641d7d 100644 --- a/fs_edit_effects.lua +++ b/fs_edit_effects.lua @@ -155,6 +155,65 @@ yl_speak_up.show_effect = function(r) end +-- called by yl_speak_up.input_talk(..); -- TODO +-- This function is called *after* the player has clicked on an option +-- and *after* any actions (i.e. trade) have been completed either +-- successfully (=action_was_succesful is true) or not. +-- Unlike the preconditions, the effects are executed in ordered form, +-- ordered by their r_id. +-- Returns the new target dialog that is to be displayed next. This will +-- usually be the one with the r_type "dialog" - unless r_type "on_failure" +-- was encountered after an unsuccessful action *or* right after an +-- effect that returned false. +-- Note: In edit mode, effects will *not* be executed. +yl_speak_up.execute_all_relevant_effects = function(player, effects, o_id, action_was_successful) + local target_dialog = "" + if(not(effects)) then + yl_speak_up.debug_msg(player, n_id, o_id, "No effects given.") + -- no effects? Then...return to the start dialog + return "" + end + local pname = player:get_player_name() + local n_id = yl_speak_up.speak_to[pname].n_id + local edit_mode = (yl_speak_up.edit_mode[pname] == n_id) + if(not(edit_mode)) then + yl_speak_up.debug_msg(player, n_id, o_id, "Executing effects.") + else + yl_speak_up.debug_msg(player, n_id, o_id, "Not executing effects because in edit mode.") + end + local last_result = action_was_successful + -- Important: the list of effects is *sorted* here. The order remains constant! + local sorted_key_list = yl_speak_up.sort_keys(effects) + for i, k in ipairs(sorted_key_list) do + local r = effects[ k ] + yl_speak_up.debug_msg(player, n_id, o_id, "..executing ".. + tostring(r.r_id)..": "..yl_speak_up.show_effect(r)) + -- do not execute effects in edit mode + if(not(edit_mode)) then + local res = yl_speak_up.execute_effect(player, n_id, o_id, r) + if(not(res)) then + yl_speak_up.debug_msg(player, n_id, o_id, tostring(r.r_id).. + " -> Effect failed to execute.") + end + end + -- "dialog" gives us the normal target_dialog + if(r.r_type and r.r_type == "dialog") then + target_dialog = r.r_value + -- "on_failure" gives an alternate target dialog if the action + -- or last effect failed + elseif(r.r_type and r.r_type == "on_failure" and r.r_value and not(last_result)) then + yl_speak_up.debug_msg(player, n_id, o_id, "Aborted executing effects at ".. + tostring(r.r_id)..". New target dialog: "..tostring(r.r_value)..".") + -- we also stop execution here + return r.r_value + end + end + -- all preconditions are true + yl_speak_up.debug_msg(player, n_id, o_id, "Finished executing effects.") + return target_dialog +end + + -- executes an effect/result r for the player and npc n_id; -- returns true on success (relevant for on_failure) -- TODO: in edit mode, nothing gets executed except perhaps dialog @@ -165,8 +224,9 @@ yl_speak_up.execute_effect = function(player, n_id, o_id, r) elseif(r.r_type == "auto" or r.r_type == "trade") then -- these effects don't do anything return true - elseif(r.r_type == "dialog") then - -- TODO: how to handle target dialog? + elseif(r.r_type == "dialog" + or r.r_type == "on_failure") then + -- this needs to be handled in the calling function return true elseif(r.r_type == "function") then -- this can only be set and edited with the staff @@ -338,9 +398,6 @@ yl_speak_up.execute_effect = function(player, n_id, o_id, r) yl_speak_up.debug_msg(player, n_id, o_id, tostring(r_id).." ".. "Great: Crafting is possible!") return true - -- "go to other dialog if the action (i.e. trade) failed", -- 5 - elseif(r.r_type == "on_failure") then - -- TODO: implement effect on_failure -- "send a chat message to all players", -- 6 elseif(r.r_type == "chat_all") then local pname = player:get_player_name() diff --git a/functions.lua b/functions.lua index 5d4f7f8..731934e 100644 --- a/functions.lua +++ b/functions.lua @@ -2510,103 +2510,14 @@ yl_speak_up.input_talk = function(player, formname, fields) local d_option = n_dialog.d_options[o] - -- which dialog do we have to show next? default: keep this one - local target_dialog = d_id + -- 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 - -- Let's do something if results exist - if d_option.o_results ~= nil then - for k, v in pairs(d_option.o_results) do - -- in edit_mode, only the switching to the next dialog is executed (we want to edit, - -- not solve quests, get/take items, teleport...) - if not(edit_mode) and v.r_type == "give_item" then - local item = ItemStack(v.r_value) - - if minetest.registered_items[item:get_name()] ~= nil then - local r = player:get_inventory():add_item("main", item) - else - say("Item not found!") - end - end - if not(edit_mode) and v.r_type == "take_item" then - local item = ItemStack(v.r_value) - - if minetest.registered_items[item:get_name()] ~= nil then - local r = player:get_inventory():remove_item("main", item) - else - say("Item not found!") - end - end - if not(edit_mode) and v.r_type == "move" then - local target_pos = nil - local target_pos_valid = false - - --pos like (100,20,400) - if minetest.string_to_pos(v.r_value) then - target_pos = minetest.string_to_pos(v.r_value) - target_pos_valid = true - end - - --pos like 100,20,400 - local maybe = string.split(v.r_value, ",") - if not target_pos_valid and maybe and tonumber(maybe[1]) and tonumber(maybe[2]) and tonumber(maybe[3]) and maybe[4] == nil and - tonumber(maybe[1]) <= 32000 and tonumber(maybe[1]) >= -32000 and - tonumber(maybe[2]) <= 32000 and tonumber(maybe[2]) >= -32000 and - tonumber(maybe[3]) <= 32000 and tonumber(maybe[3]) >= -32000 then - target_pos = {x=maybe[1],y=maybe[2],z=maybe[3]} - target_pos_valid = true - end - - --pos like {x=100,y=20,z=400} - if not target_pos_valid and string.sub(v.r_value,1,1) == "{" and string.sub(v.r_value,-1,-1) == "}" then - local might_be_pos = minetest.deserialize("return " .. v.r_value) - if tonumber(might_be_pos.x) and tonumber(might_be_pos.x) <= 32000 and tonumber(might_be_pos.x) >= -32000 and - tonumber(might_be_pos.y) and tonumber(might_be_pos.y) <= 32000 and tonumber(might_be_pos.y) >= -32000 and - tonumber(might_be_pos.z) and tonumber(might_be_pos.z) <= 32000 and tonumber(might_be_pos.z) >= -32000 then - target_pos = might_be_pos - target_pos_valid = true - end - - end - - if target_pos_valid == true then - player:set_pos(target_pos) - if vector.distance(player:get_pos(),target_pos) >= 2 then - say("Something went wrong! Player wasn't moved properly.") - end - end - - -- Debug - if target_pos_valid == false then - local obj = yl_speak_up.speak_to[pname].obj - local n_id = yl_speak_up.speak_to[pname].n_id - local npc = get_number_from_id(n_id) - if obj:get_luaentity() and tonumber(npc) then - minetest.log("error","[MOD] yl_speak_up: NPC with ID n_"..npc.." at position "..minetest.pos_to_string(obj:get_pos(),0).." could not move player "..pname.." because the content of "..v.r_id.." is wrong:"..dump(v.r_value)) - else - minetest.log("error","[MOD] yl_speak_up: NPC with unknown ID or without proper object could not move player "..dump(pname).." because the content of "..v.r_id.." is wrong:"..dump(v.r_value)) - end - end - - end - if not(edit_mode) and v.r_type == "function" then - yl_speak_up.eval_and_execute_function(player, v, "r_") - - end - if v.r_type == "dialog" then - if dialog.n_dialogs[v.r_value] ~= nil then - target_dialog = v.r_value - else - say("This dialog does not exist") - end - end - if v.r_type == "auto" then - say("auto forward") - end - end -- end of loop over d_option.o_results - - -- 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 + -- 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? @@ -2614,14 +2525,13 @@ yl_speak_up.input_talk = function(player, formname, fields) -- show the trade dialog yl_speak_up.show_fs(player, "trade_simple", trade_id) return - end + end - -- else switch to the target dialog as stated in results/effects - if(target_dialog ~= d_id) then + -- 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 end