764 lines
30 KiB
Lua
764 lines
30 KiB
Lua
-- helper function to make unintresting zeros in tables less visible
|
|
local grey_if_zero = function(fs, n)
|
|
if(n and n == 0) then
|
|
table.insert(fs, "#444444")
|
|
else
|
|
table.insert(fs, "#FFFFFF")
|
|
end
|
|
table.insert(fs, minetest.formspec_escape(n))
|
|
end
|
|
|
|
|
|
-- small helper function
|
|
local show_error_fs = function(player, text)
|
|
yl_speak_up.show_fs(player, "msg", {
|
|
input_to = "yl_speak_up:add_quest_steps",
|
|
formspec = yl_speak_up.build_fs_quest_edit_error(text, "back_from_error_msg")})
|
|
end
|
|
|
|
|
|
-- find out in how many quest steps this NPC or location is used;
|
|
-- ID can either be n_<ID> or a location p_(x,y,z)
|
|
yl_speak_up.count_used_in_quest_steps = function(id, step_data)
|
|
local used = 0
|
|
for s, d in pairs(step_data or {}) do
|
|
for loc_id, loc in pairs(d.where or {}) do
|
|
if(loc and loc.n_id and loc.n_id == id) then
|
|
used = used + 1
|
|
end
|
|
end
|
|
end
|
|
return used
|
|
end
|
|
|
|
|
|
-- This order imposed here on the quest steps is the one in which the
|
|
-- quest steps have to be solved - as far as we can tell (the quest
|
|
-- may be in the process of beeing created and not logicly complete yet).
|
|
yl_speak_up.get_sorted_quest_step_list_by_prev_step = function(pname, q_id)
|
|
if(not(q_id) or not(yl_speak_up.quests[q_id]) or not(yl_speak_up.quests[q_id].step_data)) then
|
|
return {}
|
|
end
|
|
|
|
-- for now: sort alphabeticly
|
|
local step_data = yl_speak_up.quests[q_id].step_data
|
|
local liste = {}
|
|
for k, v in pairs(step_data) do
|
|
table.insert(liste, k)
|
|
end
|
|
table.sort(liste)
|
|
return liste
|
|
end
|
|
|
|
--[[ still belongs to the above function
|
|
-- add back links (or rather: forward links to quest steps that get enabled)
|
|
local connected = table.copy(step_data)
|
|
for k, v in pairs(connected) do
|
|
-- will store the inverse data
|
|
connected[k].inv_one_step_required = {}
|
|
connected[k].inv_all_steps_require = {}
|
|
end
|
|
for k, v in pairs(connected) do
|
|
if(k and v and v.one_step_required) then
|
|
for i, s in ipairs(v.one_step_required) do
|
|
table.insert(connected[s].inv_one_step_required, k)
|
|
end
|
|
end
|
|
if(k and v and v.all_steps_required) then
|
|
for i, s in ipairs(v.all_steps_required) do
|
|
table.insert(connected[s].inv_all_steps_required, k)
|
|
end
|
|
end
|
|
end
|
|
-- get those quest steps that are not connected and not used yet
|
|
local liste = {}
|
|
for k, v in pairs(connected) do
|
|
if(k and v
|
|
and #v.one_step_required == 0 and #v.all_steps_required == 0
|
|
and #v.inv_one_step_required == 0 and #v.inv_all_steps_required == 0) then
|
|
table.insert(liste, k)
|
|
end
|
|
end
|
|
-- sort alphabeticly
|
|
table.sort(liste)
|
|
-- remove those entries from our connection table (they're not connected anyway);
|
|
-- we have already added them to the beginning of the list
|
|
for i, v in ipairs(liste) do
|
|
connected[v] = nil
|
|
end
|
|
|
|
|
|
return liste
|
|
end
|
|
--]]
|
|
|
|
|
|
-- helper function: find out if a quest step is required by other quest steps
|
|
yl_speak_up.quest_step_get_required_for_steps = function(step_data)
|
|
local required_for_steps = {}
|
|
for s, d in pairs(step_data) do
|
|
required_for_steps[s] = {}
|
|
end
|
|
for s, d in pairs(step_data) do
|
|
if(s and d and d.one_step_required and type(d.one_step_required) == "table") then
|
|
for i, s2 in ipairs(d.one_step_required) do
|
|
table.insert(required_for_steps[s2], s)
|
|
end
|
|
end
|
|
if(s and d and d.all_steps_required and type(d.all_steps_required) == "table") then
|
|
for i, s2 in ipairs(d.all_steps_required) do
|
|
table.insert(required_for_steps[s2], s)
|
|
end
|
|
end
|
|
end
|
|
return required_for_steps
|
|
end
|
|
|
|
|
|
yl_speak_up.input_fs_add_quest_steps = function(player, formname, fields)
|
|
if(not(fields) or not(player)) then
|
|
return
|
|
end
|
|
local res = yl_speak_up.player_is_working_on_quest(player)
|
|
if(res.error_msg) then
|
|
return show_error_fs(player, res.error_msg)
|
|
end
|
|
local pname = res.pname
|
|
local q_id = res.q_id
|
|
local current_step = res.current_step
|
|
local step_data = res.step_data
|
|
local quest = res.quest
|
|
|
|
if(fields.back_from_error_msg) then
|
|
yl_speak_up.show_fs(player, "add_quest_steps")
|
|
return
|
|
end
|
|
local mode = yl_speak_up.speak_to[pname].quest_step_mode
|
|
if(fields.back) then
|
|
-- go back to quest overview
|
|
if(mode and (mode == "manage_quest_npcs" or mode == "manage_quest_locations")) then
|
|
return yl_speak_up.show_fs(player, "manage_quests")
|
|
end
|
|
return yl_speak_up.show_fs(player, "manage_quest_steps", current_step)
|
|
end
|
|
|
|
-- has a quest step be selected?
|
|
local work_step = nil
|
|
if(fields.add_element and fields.add_element_name) then
|
|
if( mode and mode == "manage_quest_npcs") then
|
|
-- manually entered an NPC ID
|
|
local npc_id = fields.add_element_name or ""
|
|
-- just check if it is *potentially* an NPC ID; that way NPC the quest
|
|
-- creator has no write access to can be added
|
|
if(string.sub(npc_id, 1, 2) ~= "n_"
|
|
or not(tonumber(string.sub(npc_id, 3)))) then
|
|
return show_error_fs(player, "This is not an NPC ID. They have the form n_<id>.")
|
|
end
|
|
-- only npcs that are not yet added (and we store IDs without n_ prefix)
|
|
local id = tonumber(string.sub(npc_id, 3))
|
|
if(id and table.indexof(res.quest.npcs or {}, id) == -1) then
|
|
table.insert(yl_speak_up.quests[q_id].npcs, id)
|
|
yl_speak_up.save_quest(q_id)
|
|
end
|
|
return yl_speak_up.show_fs(player, "add_quest_steps")
|
|
elseif(mode and mode == "manage_quest_locations") then
|
|
-- manually entered a quest location
|
|
local location_id = fields.add_element_name or ""
|
|
local d = yl_speak_up.player_vars["$NPC_META_DATA$"][location_id]
|
|
local error_msg = ""
|
|
-- the owner is not checked; that way, locations can be added where the
|
|
-- quest onwer does not (yet) have write access
|
|
if(string.sub(location_id, 1, 1) ~= "p") then
|
|
error_msg = "This is not a location ID."
|
|
elseif(not(d)) then
|
|
error_msg = "Location not found."
|
|
end
|
|
if(error_msg ~= "") then
|
|
return show_error_fs(player, error_msg)
|
|
end
|
|
-- only locations that are not yet added
|
|
if(table.indexof(res.quest.locations or {}, location_id) == -1) then
|
|
table.insert(yl_speak_up.quests[q_id].locations, location_id)
|
|
yl_speak_up.save_quest(q_id)
|
|
end
|
|
return yl_speak_up.show_fs(player, "add_quest_steps")
|
|
end
|
|
|
|
-- create a new quest step
|
|
local new_step = fields.add_element_name:trim()
|
|
-- a new one shall be created
|
|
local msg = yl_speak_up.quest_step_add_quest_step(pname, q_id, new_step)
|
|
if(msg ~= "OK") then
|
|
return show_error_fs(player, msg)
|
|
end
|
|
-- this will also be set if the quest step exists already; this is fine so far
|
|
work_step = new_step
|
|
|
|
elseif(fields.add_from_available
|
|
and yl_speak_up.speak_to[pname].list_available) then
|
|
-- selected a quest step from the list of available steps offered
|
|
local liste = yl_speak_up.speak_to[pname].list_available
|
|
local selected = minetest.explode_table_event(fields.add_from_available)
|
|
if(selected and selected.row and selected.row > 1 and selected.row <= #liste + 1) then
|
|
work_step = liste[selected.row - 1]
|
|
end
|
|
|
|
elseif(fields.add_to_npc_list
|
|
and yl_speak_up.speak_to[pname].list_available) then
|
|
-- selected an NPC from the list of available NPC offered
|
|
local liste = yl_speak_up.speak_to[pname].list_available
|
|
local selected = minetest.explode_table_event(fields.add_to_npc_list)
|
|
if(selected and selected.row and selected.row > 1 and selected.row <= #liste + 1) then
|
|
local npc_id = liste[selected.row - 1]
|
|
if(table.indexof(res.quest.npcs or {}, npc_id) == -1) then
|
|
table.insert(yl_speak_up.quests[q_id].npcs, npc_id)
|
|
yl_speak_up.save_quest(q_id)
|
|
end
|
|
end
|
|
return yl_speak_up.show_fs(player, "add_quest_steps")
|
|
|
|
elseif(fields.add_to_location_list
|
|
and yl_speak_up.speak_to[pname].list_available) then
|
|
-- selected a location from the list of available locations offered
|
|
local liste = yl_speak_up.speak_to[pname].list_available
|
|
local selected = minetest.explode_table_event(fields.add_to_location_list)
|
|
if(selected and selected.row and selected.row > 1 and selected.row <= #liste + 1) then
|
|
local location_id = liste[selected.row - 1]
|
|
if(table.indexof(res.quest.locations or {}, location_id) == -1) then
|
|
table.insert(yl_speak_up.quests[q_id].locations, location_id)
|
|
yl_speak_up.save_quest(q_id)
|
|
end
|
|
end
|
|
return yl_speak_up.show_fs(player, "add_quest_steps")
|
|
|
|
elseif(fields.delete_from_one_step_required and current_step and step_data[current_step]) then
|
|
-- remove a quest step from the list (from one step required)
|
|
local selected = minetest.explode_table_event(fields.delete_from_one_step_required)
|
|
local liste = (step_data[current_step].one_step_required or {})
|
|
if(selected and selected.row and selected.row > 1 and selected.row <= #liste + 1) then
|
|
table.remove(yl_speak_up.quests[q_id].step_data[current_step].one_step_required, selected.row-1)
|
|
end
|
|
yl_speak_up.save_quest(q_id)
|
|
return yl_speak_up.show_fs(player, "add_quest_steps")
|
|
|
|
elseif(fields.delete_from_all_steps_required and current_step and step_data[current_step]) then
|
|
-- remove a quest step from the lists (from all steps required)
|
|
local selected = minetest.explode_table_event(fields.delete_from_all_steps_required)
|
|
local liste = (step_data[current_step].all_steps_required or {})
|
|
if(selected and selected.row and selected.row > 1 and selected.row <= #liste + 1) then
|
|
table.remove(yl_speak_up.quests[q_id].step_data[current_step].all_steps_required, selected.row-1)
|
|
end
|
|
yl_speak_up.save_quest(q_id)
|
|
return yl_speak_up.show_fs(player, "add_quest_steps")
|
|
|
|
elseif(fields.delete_from_npc_list) then
|
|
-- remove an NPC from the list of contributors
|
|
local selected = minetest.explode_table_event(fields.delete_from_npc_list)
|
|
local liste = (res.quest.npcs or {})
|
|
if(selected and selected.row and selected.row > 1 and selected.row <= #liste + 1) then
|
|
-- *can* it be removed, or is it needed somewhere?
|
|
local full_id = "n_"..tostring(liste[selected.row - 1])
|
|
if(yl_speak_up.count_used_in_quest_steps(full_id, step_data) > 0) then
|
|
return show_error_fs(player, "This NPC is needed for setting a quest step.")
|
|
end
|
|
table.remove(yl_speak_up.quests[q_id].npcs, selected.row - 1)
|
|
end
|
|
yl_speak_up.save_quest(q_id)
|
|
return yl_speak_up.show_fs(player, "add_quest_steps")
|
|
|
|
elseif(fields.delete_from_location_list) then
|
|
-- remove a location from the list of contributors
|
|
local selected = minetest.explode_table_event(fields.delete_from_location_list)
|
|
local liste = (res.quest.locations or {})
|
|
if(selected and selected.row and selected.row > 1 and selected.row <= #liste + 1) then
|
|
-- *can* it be removed, or is it needed somewhere?
|
|
local full_id = liste[selected.row - 1]
|
|
if(yl_speak_up.count_used_in_quest_steps(full_id, step_data) > 0) then
|
|
return show_error_fs(player, "This location is needed for setting a quest step.")
|
|
end
|
|
table.remove(yl_speak_up.quests[q_id].locations, selected.row - 1)
|
|
end
|
|
yl_speak_up.save_quest(q_id)
|
|
return yl_speak_up.show_fs(player, "add_quest_steps")
|
|
end
|
|
|
|
if(not(work_step)) then
|
|
return -- TODO
|
|
elseif(mode == "embedded_select") then
|
|
yl_speak_up.speak_to[pname].quest_step = work_step
|
|
return yl_speak_up.show_fs(player, "manage_quest_steps", work_step)
|
|
elseif(mode == "assign_quest_step") then
|
|
-- TODO: what if there's already a step assigned?
|
|
-- actually add the step
|
|
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
|
|
-- this saves the quest data as well if needed
|
|
local msg = yl_speak_up.quest_step_add_where(pname, q_id, work_step,
|
|
{n_id = n_id, d_id = d_id, o_id = o_id})
|
|
if(msg ~= "OK") then
|
|
return show_error_fs(player, msg)
|
|
end
|
|
if(not(n_id)) then
|
|
return show_error_fs(player, "NPC or location not found.")
|
|
end
|
|
-- store the new connection in the NPC file itself (do not load generic dialogs)
|
|
local dialog = yl_speak_up.load_dialog(n_id, false)
|
|
if(yl_speak_up.check_if_dialog_has_option(dialog, d_id, o_id)) then
|
|
-- ok - the tables exist, so we can store the connection
|
|
dialog.n_dialogs[d_id].d_options[o_id].quest_id = quest.var_name
|
|
dialog.n_dialogs[d_id].d_options[o_id].quest_step = work_step
|
|
-- write it back to disc
|
|
yl_speak_up.save_dialog(n_id, dialog)
|
|
else
|
|
return show_error_fs(player, "Failed to save this quest step for this NPC.")
|
|
end
|
|
-- the player is working on the NPC - thus, the NPC may be in a modified stage
|
|
-- that hasn't been written to disc yet, and we need to adjust this stage as well
|
|
dialog = yl_speak_up.speak_to[pname].dialog
|
|
if(yl_speak_up.check_if_dialog_has_option(dialog, d_id, o_id)) then
|
|
-- ok - the tables exist, so we can store the connection
|
|
dialog.n_dialogs[d_id].d_options[o_id].quest_id = quest.var_name
|
|
dialog.n_dialogs[d_id].d_options[o_id].quest_step = work_step
|
|
yl_speak_up.speak_to[pname].dialog = dialog
|
|
else
|
|
return show_error_fs(player, "Failed to update NPC.")
|
|
end
|
|
-- show the newly created or selected step
|
|
yl_speak_up.speak_to[pname].quest_step = work_step
|
|
-- log the change
|
|
yl_speak_up.log_change(pname, n_id,
|
|
"Dialog "..tostring(d_id)..": Option "..tostring(o_id)..
|
|
" will now set quest step \""..
|
|
tostring(dialog.n_dialogs[d_id].d_options[o_id].quest_step)..
|
|
"\" of quest \""..
|
|
tostring(dialog.n_dialogs[d_id].d_options[o_id].quest_id).."\".")
|
|
return yl_speak_up.show_fs(player, "manage_quest_steps", work_step)
|
|
elseif(not(current_step) or not(step_data[current_step])) then
|
|
return yl_speak_up.show_fs(player, "manage_quests")
|
|
end
|
|
|
|
local required_for_steps = yl_speak_up.quest_step_get_required_for_steps(step_data)
|
|
|
|
-- make sure we have a sane data structure
|
|
for i, s in ipairs({current_step, work_step}) do
|
|
if(s and yl_speak_up.quests[q_id].step_data[s]) then
|
|
if(not(yl_speak_up.quests[q_id].step_data[s].one_step_required)) then
|
|
yl_speak_up.quests[q_id].step_data[s].one_step_required = {}
|
|
end
|
|
if(not(yl_speak_up.quests[q_id].step_data[s].all_steps_required)) then
|
|
yl_speak_up.quests[q_id].step_data[s].all_steps_required = {}
|
|
end
|
|
end
|
|
end
|
|
-- actually do the work
|
|
if(mode == "add_to_one_needed") then
|
|
table.insert(yl_speak_up.quests[q_id].step_data[current_step].one_step_required, work_step)
|
|
elseif(mode == "add_to_all_needed") then
|
|
table.insert(yl_speak_up.quests[q_id].step_data[current_step].all_steps_required, work_step)
|
|
elseif(mode == "insert_after_prev_step") then
|
|
-- the work_step requires what the current step used to require
|
|
if(#step_data[current_step].one_step_required == 1) then
|
|
-- a clear insert is possible
|
|
yl_speak_up.quests[q_id].step_data[work_step].one_step_required = {
|
|
step_data[current_step].one_step_required[1]}
|
|
yl_speak_up.quests[q_id].step_data[current_step].one_step_required[1] = work_step
|
|
else
|
|
-- no useful information on what the new work_step ought to depend on;
|
|
-- we just insert the new step at the first place
|
|
table.insert(yl_speak_up.quests[q_id].step_data[current_step].one_step_required,
|
|
1, work_step)
|
|
end
|
|
return yl_speak_up.show_fs(player, "manage_quest_steps", work_step)
|
|
elseif(mode == "insert_before_next_step") then
|
|
-- the work_step requires the current_step
|
|
table.insert(yl_speak_up.quests[q_id].step_data[work_step].one_step_required, 1, current_step)
|
|
-- the current step has exactly one successor? then we adjust that one
|
|
if(#required_for_steps[current_step] == 1) then
|
|
local next_step = required_for_steps[current_step][1]
|
|
local i = table.indexof(step_data[next_step].one_step_required, current_step)
|
|
local a = table.indexof(step_data[next_step].all_steps_required, current_step)
|
|
if(i > -1) then
|
|
-- is it in one_step_required? -> replace current_step with work_step
|
|
yl_speak_up.quests[q_id].step_data[next_step].one_step_required[i] = work_step
|
|
elseif(a > -1) then
|
|
-- or in all_steps_required? -> replace current_step with work_step
|
|
yl_speak_up.quests[q_id].step_data[next_step].all_steps_required[i] =work_step
|
|
end
|
|
end
|
|
return yl_speak_up.show_fs(player, "manage_quest_steps", work_step)
|
|
end
|
|
yl_speak_up.save_quest(q_id)
|
|
return yl_speak_up.show_fs(player, "add_quest_steps")
|
|
end
|
|
|
|
|
|
-- small helper function for yl_speak_up.get_fs_add_quest_steps;
|
|
-- lists all the quest steps found in liste in the order they occour there
|
|
yl_speak_up.quest_step_list_show_table = function(formspec, table_specs, liste, data, required_for_steps)
|
|
table.insert(formspec, "tablecolumns["..
|
|
"color;text,align=right;".. -- #d.one_step_required
|
|
"color;text,align=right;".. -- #d.all_steps_required
|
|
"color;text,align=right;".. -- #required_for_steps (quest steps that need this one)
|
|
"color;text,align=right;".. -- #where (locations/NPC that *set* this quest step)
|
|
"color;text,align=left".. -- name of quest step
|
|
"]table[")
|
|
table.insert(formspec, table_specs)
|
|
table.insert(formspec,"#FFFFFF,(O),#FFFFFF,(A),#FFFFFF,(U),#FFFFFF,(L),#FFFFFF,Name of step:,")
|
|
local tmp = {}
|
|
for i, s in ipairs(liste or {}) do
|
|
local d = data[s]
|
|
if(not(d.one_step_required) or type(d.one_step_required) ~= "table") then
|
|
d.one_step_required = {}
|
|
end
|
|
grey_if_zero(tmp, #d.one_step_required)
|
|
if(not(d.all_steps_required) or type(d.all_steps_required) ~= "table") then
|
|
d.all_steps_required = {}
|
|
end
|
|
grey_if_zero(tmp, #d.all_steps_required)
|
|
if(not(required_for_steps[s])) then
|
|
required_for_steps[s] = {}
|
|
end
|
|
grey_if_zero(tmp, #required_for_steps[s])
|
|
|
|
if(not(d.where) or type(d.where) ~= "table") then
|
|
d.where = {}
|
|
end
|
|
local anz_where = 0
|
|
for k, v in pairs(d.where) do
|
|
anz_where = anz_where + 1
|
|
end
|
|
grey_if_zero(tmp, anz_where)
|
|
|
|
table.insert(tmp, "#AAFFAA")
|
|
table.insert(tmp, minetest.formspec_escape(s))
|
|
end
|
|
table.insert(formspec, table.concat(tmp, ","))
|
|
table.insert(formspec, ";]")
|
|
end
|
|
|
|
|
|
-- returns list of NPCs that pname can edit and that are not yet part of quest_npc_list
|
|
yl_speak_up.quest_get_npc_candidate_list = function(pname, quest_npc_liste)
|
|
-- build a list of candidates
|
|
local npc_list = {}
|
|
for k, v in pairs(yl_speak_up.npc_list) do
|
|
-- only NPC that are not already added
|
|
if(table.indexof(quest_npc_liste or {}, k) == -1
|
|
-- and only those that the player can edit
|
|
and (v.owner == pname or (v.may_edit and v.may_edit[pname]))) then
|
|
table.insert(npc_list, k)
|
|
end
|
|
end
|
|
table.sort(npc_list)
|
|
return npc_list
|
|
end
|
|
|
|
|
|
-- lists npc that are either already added or could be added
|
|
-- can also handle locations
|
|
yl_speak_up.quest_npc_show_table = function(formspec, table_specs, liste, step_data, is_location_list)
|
|
table.insert(formspec, "tablecolumns["..
|
|
"color;text,align=right;".. -- used in this many quest steps
|
|
"color;text,align=left;".. -- n_id (number, for NPC) or p_(-185,3,-146) (for locations)
|
|
"color;text,align=left;".. -- owner
|
|
"color;text,align=left".. -- name of NPC
|
|
"]table[")
|
|
table.insert(formspec, table_specs)
|
|
if(is_location_list) then
|
|
table.insert(formspec,"#FFFFFF,Used:,#FFFFFF,PositionID:,#FFFFFF,Name")
|
|
else
|
|
table.insert(formspec,"#FFFFFF,Used:,#FFFFFF,n_id:,#FFFFFF,Name")
|
|
end
|
|
table.insert(formspec, minetest.formspec_escape(","))
|
|
table.insert(formspec, " description:,#FFFFFF,Owner:,")
|
|
local tmp = {}
|
|
for i, n_id in ipairs(liste or {}) do
|
|
local full_id = n_id
|
|
if(not(is_location_list)) then
|
|
full_id = "n_"..tostring(n_id)
|
|
end
|
|
grey_if_zero(tmp, yl_speak_up.count_used_in_quest_steps(full_id, step_data))
|
|
-- the n_id of the NPC
|
|
table.insert(tmp, "#AAFFAA")
|
|
if(is_location_list) then
|
|
-- this already encodes the position but contains , and ()
|
|
table.insert(tmp, minetest.formspec_escape(n_id))
|
|
else
|
|
table.insert(tmp, "n_"..minetest.formspec_escape(n_id))
|
|
end
|
|
-- get information from the NPC list (see fs_npc_list.lua)
|
|
local owner = "- ? -"
|
|
local name = "- ? -"
|
|
if(yl_speak_up.npc_list[n_id]) then
|
|
local npc = yl_speak_up.npc_list[n_id]
|
|
owner = npc.owner
|
|
name = (npc.name or name)
|
|
if(npc.desc and npc.desc ~= "") then
|
|
name = name..', '..(npc.desc or "")
|
|
end
|
|
end
|
|
-- name and description of the NPC
|
|
table.insert(tmp, "#AAFFAA")
|
|
table.insert(tmp, minetest.formspec_escape(name))
|
|
-- owner of the NPC
|
|
table.insert(tmp, "#AAFFAA")
|
|
table.insert(tmp, minetest.formspec_escape(owner))
|
|
end
|
|
table.insert(formspec, table.concat(tmp, ","))
|
|
table.insert(formspec, ";]")
|
|
end
|
|
|
|
|
|
-- returns list of locations that pname can edit and that are not yet part of quest_location_list
|
|
yl_speak_up.quest_get_location_candidate_list = function(pname, quest_location_liste)
|
|
-- build a list of candidates of locations
|
|
local location_list = {}
|
|
for n_id, v in pairs(yl_speak_up.player_vars["$NPC_META_DATA$"] or {}) do
|
|
-- TODO: better detection would be helpful
|
|
if(string.sub(n_id, 1, 1) == "p"
|
|
-- only locations that are not yet added
|
|
and table.indexof(quest_location_liste or {}, n_id) == -1
|
|
-- and only those that the player can edit
|
|
and (v.owner == pname or (v.may_edit and v.may_edit[pname]))) then
|
|
table.insert(location_list, n_id)
|
|
end
|
|
end
|
|
table.sort(location_list)
|
|
return location_list
|
|
end
|
|
|
|
|
|
-- param is unused
|
|
yl_speak_up.get_fs_add_quest_steps = function(player, param)
|
|
local res = yl_speak_up.player_is_working_on_quest(player)
|
|
if(res.error_msg) then
|
|
return yl_speak_up.build_fs_quest_edit_error(res.error_msg, "back")
|
|
end
|
|
local pname = res.pname
|
|
local step_data = res.step_data or {}
|
|
|
|
|
|
-- find out if a quest step is required by other quest steps
|
|
local required_for_steps = yl_speak_up.quest_step_get_required_for_steps(step_data)
|
|
|
|
local current_step = nil
|
|
local this_step_data = nil
|
|
if(pname and yl_speak_up.speak_to[pname] and yl_speak_up.speak_to[pname].quest_step) then
|
|
current_step = yl_speak_up.speak_to[pname].quest_step
|
|
this_step_data = step_data[current_step]
|
|
end
|
|
local mode = ""
|
|
if(param) then
|
|
mode = param
|
|
yl_speak_up.speak_to[pname].quest_step_mode = param
|
|
elseif(pname and yl_speak_up.speak_to[pname] and yl_speak_up.speak_to[pname].quest_step_mode) then
|
|
mode = yl_speak_up.speak_to[pname].quest_step_mode
|
|
end
|
|
|
|
local add_what = "Add a new quest step named:"
|
|
if(mode == "manage_quest_npcs") then
|
|
add_what = "Add the NPC with n_<id>:"
|
|
elseif(mode == "manage_quest_locations") then
|
|
add_what = "Add a location by entering its ID directly:"
|
|
end
|
|
|
|
local formspec = {}
|
|
if(mode and mode == "embedded_select") then
|
|
table.insert(formspec, "size[30,12]container[6,0;18.5,12]")
|
|
current_step = nil
|
|
else
|
|
table.insert(formspec, "size[18.5,17.3]")
|
|
end
|
|
|
|
-- add back button
|
|
table.insert(formspec, "button[8,0;2,0.7;back;Back]")
|
|
-- show which quest we're working at
|
|
table.insert(formspec, "label[0.2,1.0;Quest ID:]")
|
|
table.insert(formspec, "label[3.0,1.0;")
|
|
table.insert(formspec, minetest.formspec_escape(res.q_id))
|
|
table.insert(formspec, "]")
|
|
table.insert(formspec, "label[0.2,1.5;Quest name:]")
|
|
table.insert(formspec, "label[3.0,1.5;")
|
|
table.insert(formspec, minetest.formspec_escape(res.quest.name or "- unknown -"))
|
|
table.insert(formspec, "]")
|
|
|
|
-- add new quest step
|
|
table.insert(formspec, "label[0.2,2.2;")
|
|
table.insert(formspec, add_what)
|
|
table.insert(formspec, "]")
|
|
table.insert(formspec, "button[16.1,2.4;1.2,0.7;add_element;Add]")
|
|
table.insert(formspec, "field[1.0,2.4;15,0.7;add_element_name;;]")
|
|
|
|
local y_pos = 3.3
|
|
if(current_step and mode == "insert_after_prev_step") then
|
|
local prev_step = "-"
|
|
if(this_step_data and this_step_data.one_step_required and #this_step_data.one_step_required > 0) then
|
|
prev_step = this_step_data.one_step_required[1]
|
|
end
|
|
table.insert(formspec, "label[0.2,3.3;between the previous step:]")
|
|
table.insert(formspec, "label[1.0,3.7;")
|
|
table.insert(formspec, minetest.colorize("#AAFFAA", minetest.formspec_escape(prev_step)))
|
|
table.insert(formspec, "]")
|
|
table.insert(formspec, "label[0.2,4.1;and the currently selected step:]")
|
|
table.insert(formspec, "label[1.0,4.5;")
|
|
table.insert(formspec, minetest.colorize("#FFFF00", minetest.formspec_escape(current_step)))
|
|
table.insert(formspec, "]")
|
|
y_pos = 5.3
|
|
elseif(current_step and mode == "insert_before_next_step") then
|
|
local next_step = "-"
|
|
if(current_step and required_for_steps[current_step] and #required_for_steps[current_step] > 0) then
|
|
next_step = required_for_steps[current_step][1]
|
|
end
|
|
table.insert(formspec, "label[0.2,3.3;between the currently selected step:]")
|
|
table.insert(formspec, "label[1.0,3.7;")
|
|
table.insert(formspec, minetest.colorize("#FFFF00", minetest.formspec_escape(current_step)))
|
|
table.insert(formspec, "]")
|
|
table.insert(formspec, "label[0.2,4.1;and the next step:]")
|
|
table.insert(formspec, "label[1.0,4.5;")
|
|
table.insert(formspec, minetest.colorize("#AAFFAA", minetest.formspec_escape(next_step)))
|
|
table.insert(formspec, "]")
|
|
y_pos = 5.3
|
|
elseif(current_step and mode == "add_to_one_needed") then
|
|
table.insert(formspec, "label[0.2,3.3;as a requirement to the currently selected step:]")
|
|
table.insert(formspec, "label[1.0,3.7;")
|
|
table.insert(formspec, minetest.colorize("#FFFF00", minetest.formspec_escape(current_step)))
|
|
table.insert(formspec, "]")
|
|
table.insert(formspec, "label[0.2,4.1;so that "..
|
|
minetest.colorize("#9999FF", "at least one")..
|
|
" of these requirements is fulfilled:]")
|
|
yl_speak_up.quest_step_list_show_table(formspec,
|
|
"0.2,4.3;17.0,3.0;delete_from_one_step_required;",
|
|
step_data[current_step].one_step_required,
|
|
step_data, required_for_steps)
|
|
table.insert(formspec, "label[0.2,7.5;(Click on an entry to delete it from the list above.)]")
|
|
y_pos = 8.3
|
|
elseif(current_step and mode == "add_to_all_needed") then
|
|
table.insert(formspec, "label[0.2,3.3;as a requirement to the currently selected step:]")
|
|
table.insert(formspec, "label[1.0,3.7;")
|
|
table.insert(formspec, minetest.colorize("#FFFF00", minetest.formspec_escape(current_step)))
|
|
table.insert(formspec, "]")
|
|
table.insert(formspec, "label[0.2,4.1;so that "..
|
|
minetest.colorize("#9999FF", "all")..
|
|
" of these requirements are fulfilled:]")
|
|
yl_speak_up.quest_step_list_show_table(formspec,
|
|
"0.2,4.3;17.0,3.0;delete_from_all_steps_required;",
|
|
step_data[current_step].all_steps_required,
|
|
step_data, required_for_steps)
|
|
table.insert(formspec, "label[0.2,7.5;(Click on an entry to delete it from the list above.)]")
|
|
y_pos = 8.3
|
|
-- add a quest step to an NPC or location
|
|
elseif(mode == "assign_quest_step") then
|
|
table.insert(formspec, "container[0,3.3;17,4]")
|
|
-- what are we talking about?
|
|
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
|
|
-- describe where in the dialog of the NPC or location this quest step shall be set
|
|
yl_speak_up.quest_step_show_where_set(pname, formspec, "which will be set by ", n_id, d_id, o_id, nil, nil)
|
|
table.insert(formspec, "container_end[]")
|
|
y_pos = 7.8
|
|
|
|
-- which NPC may contribute to the quest?
|
|
elseif(mode == "manage_quest_npcs") then
|
|
table.insert(formspec, "container[0,3.3;18,6]")
|
|
table.insert(formspec, "label[0.2,0;so that the NPC "..
|
|
minetest.colorize("#9999FF", "may contribute")..
|
|
" to the quest like these NPC:]")
|
|
yl_speak_up.quest_npc_show_table(formspec,
|
|
"0.2,0.2;17.0,3.0;delete_from_npc_list;",
|
|
res.quest.npcs or {},
|
|
step_data, false)
|
|
table.insert(formspec, "label[0.2,3.4;(Click on an entry to delete it from the list above.)]")
|
|
local available_npcs = yl_speak_up.quest_get_npc_candidate_list(pname, res.quest.npcs or {})
|
|
yl_speak_up.speak_to[pname].list_available = available_npcs
|
|
table.insert(formspec, "label[0.2,4.4;or select an NPC from the list below:]")
|
|
yl_speak_up.quest_npc_show_table(formspec,
|
|
"0.2,4.6;17.0,6.0;add_to_npc_list;",
|
|
available_npcs or {}, step_data, false)
|
|
table.insert(formspec, "label[0.2,10.8;Used: Shows in how many quest steps this NPC is used.]")
|
|
table.insert(formspec, "container_end[]")
|
|
return table.concat(formspec, "")
|
|
-- which locations may contribute to the quest?
|
|
elseif(mode == "manage_quest_locations") then
|
|
table.insert(formspec, "container[0,3.3;18,6]")
|
|
table.insert(formspec, "label[0.2,0;so that the location "..
|
|
minetest.colorize("#9999FF", "may contribute")..
|
|
" to the quest like these locations:]")
|
|
yl_speak_up.quest_npc_show_table(formspec,
|
|
"0.2,0.2;17.0,3.0;delete_from_location_list;",
|
|
res.quest.locations or {},
|
|
step_data, true)
|
|
table.insert(formspec, "label[0.2,3.4;(Click on an entry to delete it from the list above.)]")
|
|
local available_locations = yl_speak_up.quest_get_location_candidate_list(pname, res.quest.locations or {})
|
|
yl_speak_up.speak_to[pname].list_available = available_locations
|
|
table.insert(formspec, "label[0.2,4.4;or select a location from the list below:]")
|
|
yl_speak_up.quest_npc_show_table(formspec,
|
|
"0.2,4.6;17.0,6.0;add_to_location_list;",
|
|
available_locations or {}, step_data, true)
|
|
table.insert(formspec, "label[0.2,10.8;Used: Shows in how many quest steps this location is used.]")
|
|
table.insert(formspec, "container_end[]")
|
|
return table.concat(formspec, "")
|
|
end
|
|
|
|
-- some quest steps may not be available/may not make sense
|
|
local not_available = {}
|
|
if(current_step and step_data[current_step] and (not(mode) or mode ~= "assign_quest_step")) then
|
|
-- steps that are already required
|
|
for i, s in ipairs(step_data[current_step].one_step_required or {}) do
|
|
not_available[s] = true
|
|
end
|
|
for i, s in ipairs(step_data[current_step].all_steps_required or {}) do
|
|
not_available[s] = true
|
|
end
|
|
-- steps that directly require this quest step here
|
|
for i, s in ipairs(required_for_steps[current_step] or {}) do
|
|
not_available[s] = true
|
|
end
|
|
end
|
|
if(current_step and (not(mode) or mode ~= "assign_quest_step")) then
|
|
not_available[current_step] = true
|
|
end
|
|
-- build a list of candidates
|
|
local available_steps = {}
|
|
for k, v in pairs(step_data) do
|
|
if(not(not_available[k])) then
|
|
table.insert(available_steps, k)
|
|
end
|
|
end
|
|
table.sort(available_steps)
|
|
yl_speak_up.speak_to[pname].list_available = available_steps
|
|
|
|
table.insert(formspec, "container[0,")
|
|
table.insert(formspec, tostring(y_pos))
|
|
table.insert(formspec, ";30,20]")
|
|
|
|
table.insert(formspec, "label[0.2,0;or select an existing quest step from the list below")
|
|
if(mode and mode == "embedded_select") then
|
|
table.insert(formspec, minetest.colorize("#9999FF", " to display the step")..":]")
|
|
else
|
|
table.insert(formspec, ":]")
|
|
end
|
|
yl_speak_up.quest_step_list_show_table(formspec,
|
|
"0.2,0.2;17,6.0;add_from_available;",
|
|
available_steps,
|
|
step_data, required_for_steps)
|
|
table.insert(formspec, "label[0.2,6.5;Legend: The numbers show the amount of quest steps...\n"..
|
|
"\t(O) from which (o)ne needs to be achieved for this quest step\n"..
|
|
"\t(A) that (a)ll need to be achieved for this quest step\n"..
|
|
"\t(U) that require/(u)se this quest step in some form\n"..
|
|
"\t(L) Number of locations (npc/places) that "..
|
|
minetest.colorize("#9999FF", "set").." this quest step]")
|
|
table.insert(formspec, "container_end[]")
|
|
|
|
return table.concat(formspec, "")
|
|
end
|
|
|
|
yl_speak_up.register_fs("add_quest_steps",
|
|
yl_speak_up.input_fs_add_quest_steps,
|
|
-- param is unused here
|
|
yl_speak_up.get_fs_add_quest_steps,
|
|
-- no special formspec version required
|
|
nil
|
|
)
|