Icons, tasks

This commit is contained in:
Wouters Dorian 2015-07-24 22:29:05 +02:00
parent 555f4af5b6
commit 64a87f4d14
5 changed files with 263 additions and 102 deletions

157
core.lua
View File

@ -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

View File

@ -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")

71
hud.lua
View File

@ -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)

Binary file not shown.

After

Width:  |  Height:  |  Size: 873 B

View File

@ -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
})