npc_talk_edit/api/api_quest_steps.lua

271 lines
10 KiB
Lua

-- 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.build_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.handle_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.build_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