From e8082faf75a81252966f769dbc1944ff103b6e1c Mon Sep 17 00:00:00 2001 From: Sokomine Date: Thu, 14 Dec 2023 04:30:20 +0100 Subject: [PATCH] added forgotten file --- api/api_quest_steps.lua | 270 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 api/api_quest_steps.lua diff --git a/api/api_quest_steps.lua b/api/api_quest_steps.lua new file mode 100644 index 0000000..f7bf90f --- /dev/null +++ b/api/api_quest_steps.lua @@ -0,0 +1,270 @@ + +-- returns a table with helpful information *if* the player is working on a quest; +-- else error_msg is set +yl_speak_up.player_is_working_on_quest = function(player) + if(not(player)) then + return + end + local t = {} + t.pname = player:get_player_name() + if(not(t.pname)) then + return {error_msg = "Player not found."} + end + if(not(yl_speak_up.speak_to or not(yl_speak_up.speak_to[t.pname]))) then + return {error_msg = "Player not working on a quest."} + end + t.q_id = yl_speak_up.speak_to[t.pname].q_id + if(not(t.q_id) or not(yl_speak_up.quests) or not(yl_speak_up.quests[t.q_id])) then + return {error_msg = "No quest selected or quest not found."} + end + t.quest = yl_speak_up.quests[t.q_id] + if(not(t.quest.step_data) or type(t.quest.step_data) ~= "table") then + yl_speak_up.quests[t.q_id].step_data = {} + end + -- TODO: check if the player has access to that data + t.step_data = yl_speak_up.quests[t.q_id].step_data + t.current_step = yl_speak_up.speak_to[t.pname].quest_step + -- check here if the step exists + if(t.current_step and not(t.step_data[t.current_step])) then + yl_speak_up.speak_to[t.pname].quest_step = nil + t.current_step = nil + end + -- t contains pname, q_id, quest, step_data and current_step - or error_msg + return t +end + + +-- show the error message created above +yl_speak_up.get_fs_quest_edit_error = function(error_msg, back_button_name) + return "size[10,3]".. + "label[0.2,0.5;Error:]".. + "label[0.5,1.0;"..minetest.colorize("#FFFF00", + minetest.formspec_escape( + minetest.wrap_text(tostring(error_msg), 80))).. + "]button[3.5,2.0;2,0.9;"..tostring(back_button_name)..";Back]" +end + + +-- for which other quest steps is this_step needed for? +yl_speak_up.quest_step_required_for = function(step_data, this_step) + -- find out the next quest step + local required_for = {} + for s, d in pairs(step_data) do + if(s and d and d.one_step_required and type(d.one_step_required) == "table" + and table.indexof(d.one_step_required, this_step) ~= -1) then + table.insert(required_for, s) + end + if(s and d and d.all_steps_required and type(d.all_steps_required) == "table" + and table.indexof(d.all_steps_required, this_step) ~= -1) then + table.insert(required_for, s) + end + end + table.sort(required_for) + return required_for +end + + +-- sorts quest steps into lists: start, middle, end, unconnected +yl_speak_up.quest_step_get_start_end_unconnected_lists = function(step_data) + local start_steps = {} + local end_steps = {} + local unconnected_steps = {} + -- construct tables of *candidates* for start/end steps first + for s, d in pairs(step_data) do + if(#d.one_step_required == 0 and #d.all_steps_required == 0) then + start_steps[s] = true + end + end_steps[s] = true + end + for s, d in pairs(step_data) do + -- anything that is required somewhere cannot be an end step + for i, s2 in ipairs(d.one_step_required or {}) do + end_steps[s2] = nil + end + for i, s2 in ipairs(d.all_steps_required or {}) do + end_steps[s2] = nil + end + end + local lists = {} + lists.start_steps = {} + lists.end_steps = {} + lists.unconnected_steps = {} + lists.middle_steps = {} + for s, d in pairs(step_data) do + -- if it's both a start and end step, then it's an unconnected step + if(start_steps[s] and end_steps[s]) then + table.insert(lists.unconnected_steps, s) + elseif(start_steps[s]) then + table.insert(lists.start_steps, s) + elseif(end_steps[s]) then + table.insert(lists.end_steps, s) + else + table.insert(lists.middle_steps, s) + end + end + return lists +end + + +-- some lists are offered in diffrent formspecs for selection; +-- this function will display the right quest step if possible +-- res needs to be yl_speak_up.player_is_working_on_quest(player) +yl_speak_up.input_routing_show_a_quest_step = function(player, formname, fields, back_field_name, res) + if(not(player) or not(fields) or (fields and fields.back) or not(res)) then + return false + end + + if(res.error_msg) then + yl_speak_up.show_fs(player, "msg", { + input_to = formname, + formspec = yl_speak_up.get_fs_quest_edit_error(error_msg, back_field_name) + }) + return true + end + local step_data = res.step_data or {} + + -- which quest step to show next? (if any) + local show_step = "" + -- was a quest step selected from the start/end/unconnected lists? + local list = {} + local field_name = "" + local row_offset = 0 + if( fields.select_from_start_steps and fields.select_from_start_steps ~= "") then + -- selected a start quest step + list = yl_speak_up.quest_step_get_start_end_unconnected_lists(step_data).start_steps + field_name = "select_from_start_steps" + elseif(fields.select_from_end_steps and fields.select_from_end_steps ~= "") then + -- selected an end quest step + list = yl_speak_up.quest_step_get_start_end_unconnected_lists(step_data).end_steps + field_name = "select_from_end_steps" + elseif(fields.select_from_unconnected_steps and fields.select_from_unconnected_steps ~= "") then + -- selected an unconnected/unused quest step + list = yl_speak_up.quest_step_get_start_end_unconnected_lists(step_data).unconnected_steps + field_name = "select_from_unconnected_steps" + elseif(res.current_step and step_data[res.current_step] and fields.one_step_required) then + list = step_data[res.current_step].one_step_required + field_name = "one_step_required" + elseif(res.current_step and step_data[res.current_step] and fields.all_steps_required) then + list = step_data[res.current_step].all_steps_required + field_name = "all_steps_required" + elseif(res.current_step and step_data[res.current_step] and fields.next_steps_show) then + list = yl_speak_up.quest_step_required_for(step_data, res.current_step) + field_name = "next_steps_show" + elseif(fields.add_from_available) then + -- selected a quest step from the list of available steps offered + list = yl_speak_up.speak_to[res.pname].available_quest_steps or {} + field_name = "add_from_available" + -- this table has a header + row_offset = 1 + + -- show prev logical step + elseif(fields.show_prev_step and res.current_step and step_data[res.current_step]) then + if( #step_data[res.current_step].one_step_required > 0) then + show_step = step_data[res.current_step].one_step_required[1] + elseif(#step_data[res.current_step].all_steps_required > 0) then + show_step = step_data[res.current_step].all_steps_required[1] + end + -- show next logical step + elseif(fields.show_next_step) then + local list = yl_speak_up.quest_step_required_for(res.step_data, res.current_step) + if(list and #list > 0) then + show_step = list[1] + end + end + + if(list and field_name) then + local selected = minetest.explode_table_event(fields[field_name]) + -- if a table uses a header, row_offset will be 1; else 0 + if(selected and selected.row and selected.row > row_offset and selected.row <= #list + row_offset) then + show_step = list[selected.row - row_offset] + end + end + -- actually show the selected quest step + if(show_step and show_step ~= "") then + yl_speak_up.speak_to[res.pname].quest_step = show_step + yl_speak_up.show_fs(player, "manage_quest_steps", show_step) + return true + -- show the entire list + elseif(fields.show_step_list) then + yl_speak_up.speak_to[res.pname].tmp_index_general = -1 + yl_speak_up.speak_to[res.pname].quest_step = nil + yl_speak_up.show_fs(player, "manage_quest_steps", nil) + return true + end + return false +end + + +-- describe a location where a quest step can be set; also used by yl_speak_up.fs_manage_quest_steps +yl_speak_up.quest_step_show_where_set = function(pname, formspec, label, n_id, d_id, o_id, box_color, nr) + if(not(pname)) then + return + end + -- what are we talking about? + local dialog = nil + if(yl_speak_up.speak_to[pname] and yl_speak_up.speak_to[pname].n_id == n_id) then + dialog = yl_speak_up.speak_to[pname].dialog + else + dialog = yl_speak_up.load_dialog(n_id, false) + end + local name_txt = "- ? -" + local dialog_txt = "- ? -" + local option_txt = "- ? -" + if(yl_speak_up.check_if_dialog_has_option(dialog, d_id, o_id)) then + dialog_txt = dialog.n_dialogs[d_id].d_text or "- ? -" + option_txt = dialog.n_dialogs[d_id].d_options[o_id].o_text_when_prerequisites_met or "- ? -" + name_txt = (dialog.n_npc or "- ? -") + if(dialog.n_description and dialog.n_description ~= "") then + name_txt = name_txt..", "..tostring(dialog.n_description) + end + end + -- are we dealing with an NPC? + local id_label = "the block at position " + if(n_id and string.sub(n_id, 1, 2) == "n_") then + id_label = "NPC " + end + + if(box_color) then + name_txt = name_txt.." ["..tostring(n_id).."]" + table.insert(formspec, "label[0.2,0.2;") + if(nr) then + table.insert(formspec, tostring(nr)..". ") + end + table.insert(formspec, id_label) + table.insert(formspec, minetest.colorize("#AAAAFF", minetest.formspec_escape(name_txt))) + table.insert(formspec, " says in dialog ") + table.insert(formspec, minetest.colorize("#AAAAFF", minetest.formspec_escape(d_id)..":]")) + table.insert(formspec, "]") + table.insert(formspec, "box[1.0,0.4;16,1.8;") + table.insert(formspec, box_color) + table.insert(formspec, "]") + table.insert(formspec, "textarea[1.0,0.4;16,1.8;;;") + table.insert(formspec, minetest.formspec_escape(dialog_txt)) + table.insert(formspec, "]") + table.insert(formspec, "label[1.0,2.4;Answer ") + table.insert(formspec, minetest.colorize("#AAAAFF", minetest.formspec_escape(o_id..": "))) + table.insert(formspec, minetest.colorize("#AAAAFF", minetest.formspec_escape(option_txt))) + table.insert(formspec, "]") + return + end + table.insert(formspec, "label[0.2,0;") + table.insert(formspec, label or "which will be set by ") + table.insert(formspec, id_label) + table.insert(formspec, minetest.colorize("#AAAAFF", minetest.formspec_escape(n_id))) + table.insert(formspec, ":]") + table.insert(formspec, "label[1.0,0.4;") + table.insert(formspec, minetest.colorize("#AAAAFF", minetest.formspec_escape(name_txt))) + table.insert(formspec, "]") + table.insert(formspec, "label[0.2,0.9;when answering to dialog ") + table.insert(formspec, minetest.colorize("#AAAAFF", minetest.formspec_escape(d_id))) + table.insert(formspec, ":]") + table.insert(formspec, "textarea[1.0,1.1;16,1.8;;;") + table.insert(formspec, minetest.formspec_escape(dialog_txt)) + table.insert(formspec, "]") + table.insert(formspec, "label[0.2,3.2;with the following answer/option ") + table.insert(formspec, minetest.colorize("#AAAAFF", minetest.formspec_escape(o_id))) + table.insert(formspec, ":]") + table.insert(formspec, "label[1.0,3.6;") + table.insert(formspec, minetest.colorize("#AAAAFF", minetest.formspec_escape(option_txt))) + table.insert(formspec, "]") +end