From 64a87f4d149196dad8f9d378f7a777e346f4c1d4 Mon Sep 17 00:00:00 2001 From: Wouters Dorian Date: Fri, 24 Jul 2015 22:29:05 +0200 Subject: [PATCH] Icons, tasks --- core.lua | 157 ++++++++++++++++++++----- formspecs.lua | 134 +++++++++++++++------ hud.lua | 71 ++++++----- textures/quests_default_quest_icon.png | Bin 0 -> 873 bytes unified_inventory.lua | 3 +- 5 files changed, 263 insertions(+), 102 deletions(-) create mode 100644 textures/quests_default_quest_icon.png diff --git a/core.lua b/core.lua index f5d7f1a..2111ac1 100644 --- a/core.lua +++ b/core.lua @@ -11,6 +11,65 @@ else end local empty_callback = function(...) end +local function compute_tasks(playername, questname, nocallback) + local quest = quests.registered_quests[questname] + local plr_quest = quests.active_quests[playername][questname] + for taskname, task in pairs(quest.tasks) do + local plr_task = plr_quest[taskname] + if task.requires == nil then + plr_task.visible = true + else + local was_visible = task.visible + local final_enabler = "" + for _, enabler_name in ipairs(task.requires) do + if type(enabler_name) == "table" then + plr_task.visible = true + for _, subena_name in ipairs(plr_task[enabler_name]) do + local plr_subena = plr_task[subena_name] + if not plr_subena.visible or not plr_subena.finished then + plr_task.visible = false + break + end + end + else + plr_task.visible = plr_task[enabler_name].finished + end + if plr_task.visible then + final_enabler = enabler + break + end + end + if plr_task.visible and not was_visible and not nocallback then + task.availablecallback(playername, questname, taskname, final_enabler, quest.metadata) + end + end + if task.disables_on ~= nil then + local was_disabled = task.disabled + local final_disabler = "" + for _, disabler_name in ipairs(task.disables_on) do + if type(disabler) == "table" then + plr_task.disabled = true + for _, subdis_name in ipairs(disabler) do + local plr_subdis = plr_task[subdis_name] + if plr_subdis.visible and plr_subdis.finished then + plr_task.disabled = false + break + end + end + else + plr_task.disabled = plr_task[disabler_name].finished + end + if plr_task.disabled then + final_disabler = disabler + break + end + end + if plr_task.disabled and not was_disabled and not nocallback then + task.disablecallback(playername, questname, taskname, final_disabler, quest.metadata) + end + end + end +end --- Registers a quest for later use. -- There are two types of quests: simple and tasked. @@ -26,6 +85,7 @@ local empty_callback = function(...) end -- icon, -- Texture name of the quest's icon. If missing, a default icon is used. -- startcallback, -- Called upon quest start. function(playername, questname, metadata) -- autoaccept, -- If true, quest automatically becomes completed if its progress reaches the max. +-- -- Defaults to true. -- endcallback, -- If autoaccept is true, gets called at the end of the quest. -- -- function(playername, questname, metadata) -- abortcallback, -- Called when a player cancels the quest. function(playername, questname, metadata) @@ -49,9 +109,13 @@ local empty_callback = function(...) end -- -- To to task completion groups (i.e. where ALL must be compileted), pass said names in a (sub)table. -- -- availablecallback, --- -- Called when the task becomes available. --- -- function(playername, questname, metadata, taskname, enablingtaskname) +-- -- Called when the task becomes available. Not called when there are no task requirements (i.e. task is available from the start). +-- -- function(playername, questname, taskname, enablingtaskname, metadata) -- -- enablingtaskname is a string or a table of strings, depending on the condition that unlocked the task +-- +-- endcallback, +-- -- Called upon task completion. +-- -- function(playername, questname, taskname, metadata) -- } -- something = { -- [...], @@ -61,20 +125,22 @@ local empty_callback = function(...) end -- -- Same as `requires`, but *disables* the task (it then does not count towards quest completion) -- -- disablecallback, --- -- Called when the task becomes disabled. --- -- function(playername, questname, metadata, taskname, disablingtaskname) +-- -- Called when the task becomes disabled. Not called when the task is disabled upon quest start. +-- -- function(playername, questname, taskname, disablingtaskname, metadata) -- -- disablingtaskname is a string or a table of strings, depending on the condition that locked the task -- } -- } -- In this previous example the 2 last tasks enables once the `start` one is completed, and the -- last one disables upon `another_task` completion, effectively making it optional if one -- completes `another_task` before it. +-- Note: this function *copies* the `quest` table, keeping only what's needed. This way you can implement custom +-- quest attributes in your mod and register the quest directly without worrying about keyvalue name collision. -- @param questname Name of the quest. Should follow the naming conventions: `modname:questname` -- @param quest Quest definition `table` -- @return `true` when the quest was successfully registered -- @return `false` when there was already such a quest, or if mandatory info was omitted/corrupt function quests.register_quest(questname, quest) - if (quests.registered_quests[questname] ~= nil) then + if quests.registered_quests[questname] ~= nil then return false -- The quest was not registered since there already a quest with that name end quests.registered_quests[questname] = { @@ -82,8 +148,7 @@ function quests.register_quest(questname, quest) description = quest.description or S("missing description"), icon = quest.icon or "quests_default_quest_icon.png", startcallback = quest.startcallback or empty_callback, - autoaccept = quest.autoaccept or false, - callback = quest.callback or empty_callback, + autoaccept = quest.autoaccept or true, endcallback = quest.endcallback or empty_callback, abortcallback = quest.abortcallback or empty_callback, periodicity = quest.periodicity or 0 @@ -93,7 +158,7 @@ function quests.register_quest(questname, quest) new_quest.max = quest.max or 1 new_quest.simple = true else - if quest.tasks == nil or type(quests.task) ~= "table" then + if quest.tasks == nil or type(quest.tasks) ~= "table" then quests.registered_quests[questname] = nil return false end @@ -101,14 +166,15 @@ function quests.register_quest(questname, quest) local tcount = 0 for tname, task in pairs(quest.tasks) do new_quest.tasks[tname] = { - title = quest.title or S("missing title"), - description = quest.description or S("missing description"), - icon = quest.icon or "quests_default_quest_icon.png", - max = quest.max or 1, - requires = quest.requires, - availablecallback = quest.availablecallback or empty_callback, - disables_on = quest.disables_on, - disablecallback = quest.disablecallback or empty_callback + title = task.title or S("missing title"), + description = task.description or S("missing description"), + icon = task.icon or "quests_default_quest_icon.png", + max = task.max or 1, + requires = task.requires, + availablecallback = task.availablecallback or empty_callback, + disables_on = task.disables_on, + disablecallback = task.disablecallback or empty_callback, + endcallback = task.endcallback or empty_callback } tcount = tcount + 1 end @@ -138,10 +204,19 @@ function quests.start_quest(playername, questname, metadata) return false -- the player already has this quest end if quest.simple then - quests.active_quests[playername][questname] = {value = 0, metadata = metadata} + quests.active_quests[playername][questname] = {value = 0, metadata = metadata, finished = false} else quests.active_quests[playername][questname] = {metadata = metadata} + for tname, task in pairs(quest.tasks) do + quests.active_quests[playername][questname][tname] = { + value = 0, + visible = false, + disabled = false, + finished = false + } + end end + compute_tasks(playername, questname) quests.update_hud(playername) quests.show_message("new", playername, S("New quest:") .. " " .. quest.title) @@ -179,6 +254,9 @@ function quests.update_quest(playername, questname, value) return false -- The quest is already finished end local quest = quests.registered_quests[questname] + if not quest.simple then + return false -- See quests.update_quest_task + end plr_quest.value = plr_quest.value + value if plr_quest.value >= quest.max then plr_quest.value = quest.max @@ -201,35 +279,54 @@ end -- @param questname Quest which gets updated -- @param taskname Task to update -- @param value Value to add to the task's progress (can be negative) --- @return `true` if the quest is finished --- @return `false` if there is no such quest, is a simple one, or the quest continues +-- @return `true` if the task is finished +-- @return `false` if there is no such quest, is a simple one, or the task continues -- @see quests.update_quest function quests.update_quest_task(playername, questname, taskname, value) ---[[ if not check_active_quest(playername, questname) then return false -- There is no such quest or it isn't active end local quest = quests.registered_quests[questname] - if taskname == nil or quest.tasks[taskname] == nil or value == nil then - return false + if quest.simple then + return false -- See quests.update_quest + end + local task = quest.tasks[taskname] + if taskname == nil or task == nil or value == nil then + return false -- No such task, or bad value end local plr_quest = quests.active_quests[playername][questname] - if plr_quest.finished then + local plr_task = plr_quest[taskname] + if not plr_task or plr_task.finished then return false -- The quest is already finished end - plr_quest.value = plr_quest.value + value - if plr_quest.value >= quest.max then - plr_quest.value = quest.max + + local task_finished = false + plr_task.value = plr_task.value + value + if plr_task.value >= task.max then + plr_task.value = task.max + plr_task.finished = true + task.endcallback(playername, questname, taskname, quest.metadata) + task_finished = true + end + + compute_tasks(playername, questname) + -- Check for quest completion + local all_tasks_finished = true + for taskname, task in pairs(quest.tasks) do + if plr_task.visible and not plr_task.disabled and not plr_task.finished then + all_tasks_finished = false + end + end + if all_tasks_finished then if quest.autoaccept then quest.endcallback(playername, questname, plr_quest.metadata) quests.accept_quest(playername,questname) quests.update_hud(playername) end - return true -- the quest is finished + return true end quests.update_hud(playername) - return false -- the quest continues -]] + return task_finished end --- Confirms quest completion and ends it. @@ -251,7 +348,7 @@ function quests.accept_quest(playername, questname) end quests.active_quests[playername][questname].finished = true for _,quest in ipairs(quests.hud[playername].list) do - if (quest.name == questname) then + if quest.name == questname then local player = minetest.get_player_by_name(playername) player:hud_change(quest.id, "number", quests.colors.success) end diff --git a/formspecs.lua b/formspecs.lua index 5db7cd7..e4d6d91 100644 --- a/formspecs.lua +++ b/formspecs.lua @@ -16,23 +16,32 @@ function quests.create_formspec(playername, tab, integrated) quests.formspec_lists[playername].id = 1 quests.formspec_lists[playername].list = {} tab = tab or quests.formspec_lists[playername].tab or "1" - if (tab == "1") then + if tab == "1" then questlist = quests.active_quests[playername] or {} - elseif (tab == "2") then + elseif tab == "2" then questlist = quests.successfull_quests[playername] or {} - elseif (tab == "3") then + elseif tab == "3" then questlist = quests.failed_quests[playername] or {} end quests.formspec_lists[playername].tab = tab - + local no_quests = true for questname,questspecs in pairs(questlist) do - if (questspecs.finished == nil) then - local queststring = quests.registered_quests[questname]["title"] - if (questspecs["count"] and questspecs["count"] > 1) then - queststring = queststring .. " - " .. questspecs["count"] - elseif(not questspecs["count"] and quests.registered_quests[questname]["max"] ~= 1) then - queststring = queststring .. " - (" .. quests.round(questspecs["value"], 2) .. "/" .. quests.registered_quests[questname]["max"] .. ")" + if not questspecs.finished then + local quest = quests.registered_quests[questname] + local queststring = quest.title + if quest.simple then + if questspecs.count and questspecs.count > 1 then + queststring = queststring .. " - " .. questspecs.count + elseif not questspecs.count and quest.max ~= 1 then + queststring = queststring .. " - (" .. quests.round(questspecs.value, 2) .. "/" .. quest.max .. ")" + end + else + if questspecs.count and questspecs.count > 1 then + queststring = queststring .. " - " .. questspecs.count + elseif not questspecs.count and quest.max ~= 1 then + queststring = queststring .. " - (...)" + end end table.insert(queststringlist, queststring) table.insert(quests.formspec_lists[playername].list, questname) @@ -40,16 +49,16 @@ function quests.create_formspec(playername, tab, integrated) end end local formspec = "" - if (not integrated) then + if not integrated then formspec = formspec .. "size[7,9]" end formspec = formspec .. "tabheader[0,0;quests_header;" .. S("Open quests") .. "," .. S("Finished quests") .. "," .. S("Failed quests") .. ";" .. tab .. "]" - if (no_quests) then + if no_quests then formspec = formspec .. "label[0.25,0.25;" .. S("There are no quests in this category.") .. "]" else formspec = formspec .. "textlist[0.25,0.25;6.5,6.5;quests_questlist;"..table.concat(queststringlist, ",") .. ";1;false]" end - if (quests.formspec_lists[playername].tab == "1") then + if quests.formspec_lists[playername].tab == "1" then formspec = formspec .."button[0.25,7;3,.7;quests_abort;" .. S("Abort quest") .. "]" end formspec = formspec .. "button[3.75,7;3,.7;quests_config;" .. S("Configure") .. "]".. @@ -117,26 +126,62 @@ local function wordwrap(text, linelength) end -- construct the info formspec -function quests.create_info(playername, questname, integrated) +function quests.create_info(playername, questname, taskid, integrated) local formspec = "" - if (not integrated) then - formspec = formspec .. "size[9,6.5]" + if not integrated then + formspec = formspec .. "size[7.5,9]" end - formspec = formspec .. "label[0.5,0.5;" + formspec = formspec .. "label[0.8,0.1;" - if (questname) then - formspec = formspec .. quests.registered_quests[questname].title .. "]" .. - "box[.4,1.5;8.2,4.5;#999999]" .. - "label[.5,1.5;" .. - wordwrap(quests.registered_quests[questname].description, 60) .. "]" + if questname then + local quest = quests.registered_quests[questname] + formspec = formspec .. quest.title .. "]" .. + "image[0,0;0.8,0.8;" .. quest.icon .. "]" - if (quests.formspec_lists[playername].tab == "1") then - formspec = formspec .. "button[.5,6;3,.7;quests_info_abort;" .. S("Abort quest") .. "]" + if quest.simple then + formspec = formspec .. "textarea[.4,1;7.2,7;_;;" .. minetest.formspec_escape(quest.description) .. "]" + else + quests.formspec_lists[playername].taskid = nil + local taskidlist = {} + local taskstringlist = {} + for taskname, task in pairs(quest.tasks) do + local plr_task = quests.active_quests[playername][questname][taskname] + if not plr_task or (plr_task and plr_task.visible) then + -- not plr_task => quest is finished, display all tasks + table.insert(taskidlist, taskname) + local color = "" + if plr_task then + if plr_task.finished then + color = "#00BB00" + end + if plr_task.disabled then + color = "#AAAAAA" + end + end + table.insert(taskstringlist, color .. task.title .. " - " .. quests.round(plr_task.value, 2) .. "/" .. task.max) + end + end + local task = false + if taskid ~= nil then + task = quest.tasks[taskidlist[taskid]] + end + task = task or {title=S("No task selected"), description=""} + formspec = formspec .. "textarea[.4,1;7.2,2;_;;" .. minetest.formspec_escape(quest.description) .. "]" .. + "textlist[0.1,2.9;7,2;quest_info_tasklist;" .. table.concat(taskstringlist, ",") .. "]" .. + "label[0.8,5.2;" .. task.title .. "]" .. + "textarea[.4,6;7.2,2;__;;" .. minetest.formspec_escape(task.description) .. "]" + if task.icon then + formspec = formspec .. "image[0,5.1;0.8,0.8;" .. task.icon .. "]" + end + end + + if quests.formspec_lists[playername].tab == "1" then + formspec = formspec .. "button[3.6,8;3,.7;quests_info_abort;" .. S("Abort quest") .. "]" end else formspec = formspec .. S("No quest specified.") .. "]" end - formspec = formspec .. "button[3.25,6;3,.7;quests_info_return;" .. S("Return") .. "]" + formspec = formspec .. "button[.4,8;3,.7;quests_info_return;" .. S("Return") .. "]" return formspec end @@ -157,22 +202,22 @@ minetest.register_chatcommand("quests", { -- Handle the return fields of the questlog minetest.register_on_player_receive_fields(function(player, formname, fields) - if (player == nil) then + if player == nil then return end - local playername = player:get_player_name(); - if (playername == "") then + local playername = player:get_player_name() + if playername == "" then return end -- questlog - if (fields["quests_header"]) then - if (formname == "quests:questlog") then - minetest.show_formspec(playername, "quests:questlog", quests.create_formspec(playername, fields["quests_header"])) + if fields.quests_header then + if formname == "quests:questlog" then + minetest.show_formspec(playername, "quests:questlog", quests.create_formspec(playername, fields.quests_header)) else - if (fields["quests_header"] == "1") then + if fields.quests_header == "1" then unified_inventory.set_inventory_formspec(player, "quests") - elseif (fields["quests_header"] == "2") then + elseif fields.quests_header == "2" then unified_inventory.set_inventory_formspec(player, "quests_successfull") return else @@ -208,7 +253,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) end if (fields["quests_info"]) then if (formname == "quests:questlog") then - minetest.show_formspec(playername, "quests:info", quests.create_info(playername, quests.formspec_lists[playername].list[quests.formspec_lists[playername].id])) + minetest.show_formspec(playername, "quests:info", quests.create_info(playername, quests.formspec_lists[playername].list[quests.formspec_lists[playername].id], nil, false)) else unified_inventory.set_inventory_formspec(player, "quests_info") end @@ -263,19 +308,30 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) end -- info - if (fields["quests_info_abort"]) then + if fields.quest_info_tasklist then + local event = minetest.explode_textlist_event(fields.quest_info_tasklist) + if event.type == "CHG" then + if formname == "quests:questlog" then + minetest.show_formspec(playername, "quests:info", quests.create_info(playername, quests.formspec_lists[playername].list[quests.formspec_lists[playername].id]), event.index, false) + else + quests.formspec_lists[playername].taskid = event.index + unified_inventory.set_inventory_formspec(player, "quests_info") + end + end + end + if fields.quests_info_abort then if (quests.formspec_lists[playername].id == nil) then return end - quests.abort_quest(playername, quests.formspec_lists[playername]["list"][quests.formspec_lists[playername].id]) - if (formname == "quests:info") then + quests.abort_quest(playername, quests.formspec_lists[playername].list[quests.formspec_lists[playername].id]) + if formname == "quests:info" then minetest.show_formspec(playername, "quests:questlog", quests.create_formspec(playername)) else unified_inventory.set_inventory_formspec(player, "quests") end end - if (fields["quests_info_return"]) then - if (formname == "quests:info") then + if fields.quests_info_return then + if formname == "quests:info" then minetest.show_formspec(playername, "quests:questlog", quests.create_formspec(playername)) else unified_inventory.set_inventory_formspec(player, "quests") diff --git a/hud.lua b/hud.lua index c1f37be..ce40f18 100644 --- a/hud.lua +++ b/hud.lua @@ -68,8 +68,10 @@ end local function get_quest_hud_string(questname, quest) local quest_string = quests.registered_quests[questname].title - if (quests.registered_quests[questname].max ~= 1) then + if quest.simple and quests.registered_quests[questname].max ~= 1 then quest_string = quest_string .. "\n ("..quests.round(quest.value, 2).."/"..quests.registered_quests[questname].max..")" + else + quest_string = quest_string .. "\n (...)" end return quest_string end @@ -146,37 +148,42 @@ function quests.update_hud(playername) -- add new quests local counter = i - 1 for questname,questspecs in pairs(quests.active_quests[playername]) do - if (not visible[questname]) then - local id = player:hud_add({ hud_elem_type = "text", - alignment = { x=1, y= 1 }, - position = {x = hud_config.position.x, y = hud_config.position.y}, - offset = {x = hud_config.offset.x, y = hud_config.offset.y + counter * 40}, - number = hud_config.number, - text = get_quest_hud_string(questname, questspecs) }) - local id_background - local id_bar - if (quests.registered_quests[questname].max ~= 1) then - id_background = player:hud_add({ hud_elem_type = "image", - scale = { x = 1, y = 1 }, - size = { x = 2, y = 4 }, - alignment = { x = 1, y = 1 }, - position = { x = hud_config.position.x, y = hud_config.position.y }, - offset = { x = hud_config.offset.x, y = hud_config.offset.y + counter * 40 + 22 }, - text = "quests_questbar_background.png" }) - id_bar = player:hud_add({hud_elem_type = "image", - scale = { x = math.floor(20 * questspecs.value / quests.registered_quests[questname].max), - y = 1 }, - alignment = { x = 1, y = 1 }, - position = { x = hud_config.position.x, y = hud_config.position.y }, - offset = { x = hud_config.offset.x + 2, y = hud_config.offset.y + counter * 40 + 24 }, - text = "quests_questbar.png" }) - end + if not visible[questname] then + local quest = quests.registered_quests[questname] + if quest.simple then + local id = player:hud_add({ hud_elem_type = "text", + alignment = { x=1, y= 1 }, + position = {x = hud_config.position.x, y = hud_config.position.y}, + offset = {x = hud_config.offset.x, y = hud_config.offset.y + counter * 40}, + number = hud_config.number, + text = get_quest_hud_string(questname, questspecs) }) + local id_background + local id_bar + if quest.max ~= 1 then + id_background = player:hud_add({ hud_elem_type = "image", + scale = { x = 1, y = 1 }, + size = { x = 2, y = 4 }, + alignment = { x = 1, y = 1 }, + position = { x = hud_config.position.x, y = hud_config.position.y }, + offset = { x = hud_config.offset.x, y = hud_config.offset.y + counter * 40 + 22 }, + text = "quests_questbar_background.png" }) + id_bar = player:hud_add({hud_elem_type = "image", + scale = { x = math.floor(20 * questspecs.value / quest.max), + y = 1 }, + alignment = { x = 1, y = 1 }, + position = { x = hud_config.position.x, y = hud_config.position.y }, + offset = { x = hud_config.offset.x + 2, y = hud_config.offset.y + counter * 40 + 24 }, + text = "quests_questbar.png" }) + end - table.insert(quests.hud[playername].list, { name = questname, - id = id, - id_background = id_background, - id_bar = id_bar, - value = questspecs.value }) + table.insert(quests.hud[playername].list, { name = questname, + id = id, + id_background = id_background, + id_bar = id_bar, + value = questspecs.value }) + else + -- TODO + end counter = counter + 1 if (counter >= show_max + 1) then break @@ -184,7 +191,7 @@ function quests.update_hud(playername) end end - if (quests.hud[playername].autohide) then + if quests.hud[playername].autohide then if (next(quests.active_quests[playername]) == nil) then player:hud_change(quests.hud[playername].list[1].id, "text", S("No more Quests")) minetest.after(3, function(playername) diff --git a/textures/quests_default_quest_icon.png b/textures/quests_default_quest_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..eb25506fd1bedbc7a8df25e258cf07ec9a1e0991 GIT binary patch literal 873 zcmV-v1D5=WP)BCh%eTnK_XB35K{GG>~Y&ScUg%_MPADwVdAWa#DH<(%)l z-@`fI`8W~g=jQ{CP$__gg@q$YzPPx!2@pk+^owHgBZa~jB&mWZ)<~t+NhBORFH5(Z z!?uT6Uq3~=JxQx|4#znj>Kh6$IJnHn$P%*r0GI&Y0H6PhNhBQ7={Ay7Wnkbv!^5uu zfpU4AM&l8#JH4lWA`GD0%_GYt-~uoL%!Mrh!1Dq;?;D!dJ1!KU*__6*RNw>flg%9n zmuW($GeI&r(K9YW4G5^}RmR4iMoPRT!vI~MA(zYbj0@cXfLiS~zMqMlJP4rKEZ{ho zNhErwhy>ueMOIg@LfOiyYikMC)@Bh!asL2Xttm`%EHtj$ z1y!9QogR(k8yNtgTD=n*(`>@(>I{ma>_5PtKR59_Y0vo}08KlF>s|^izPqA0G-Y_?e^In0N{D2snuTLc^&|Y(w|k|0D|CC zDt#rJ)iKR6OmpP$07S9M)YNkn<;NBd_4+l+sg!}^oIq9Y5d^cbn^B*AAcgBb zrdE51ZJP)}3R#v9w-W-0q8RDn*-OGv|DOK^SUd|cBRx!000000NkvXXu0mjfqAG?- literal 0 HcmV?d00001 diff --git a/unified_inventory.lua b/unified_inventory.lua index 4855533..fc71ff2 100644 --- a/unified_inventory.lua +++ b/unified_inventory.lua @@ -41,7 +41,8 @@ unified_inventory.register_page("quests_config", { unified_inventory.register_page("quests_info", { get_formspec = function(player) local playername = player:get_player_name() - local formspec = quests.create_info(playername, quests.formspec_lists[playername].list[quests.formspec_lists[playername].id], true) + local formspec = quests.create_info(playername, quests.formspec_lists[playername].list[quests.formspec_lists[playername].id], + quests.formspec_lists[playername].taskid, true) return {formspec = formspec, draw_inventory = false } end })