Better quests, still testing
|
@ -1,34 +1,85 @@
|
|||
--- HIGLY UNFINISHED!!!!
|
||||
--- HIGLY UNFINISHED!!!!
|
||||
--- HIGLY UNFINISHED!!!!
|
||||
--- HIGLY UNFINISHED!!!!
|
||||
--- HIGLY UNFINISHED!!!!
|
||||
--- HIGLY UNFINISHED!!!!
|
||||
--- HIGLY UNFINISHED!!!!
|
||||
--- HIGLY UNFINISHED!!!!
|
||||
--- HIGLY UNFINISHED!!!!
|
||||
--- HIGLY UNFINISHED!!!!
|
||||
--- HIGLY UNFINISHED!!!!
|
||||
--- HIGLY UNFINISHED!!!!
|
||||
-- GOT THAT ENOUGH?
|
||||
-- - gravgun
|
||||
mff.quests = {}
|
||||
mff.QPREFIX = "mff_quests:"
|
||||
mff.QNOPREFIX = function(s) return s:sub(mff.QPREFIX:len()+1) end
|
||||
|
||||
mff.quests.quests = {
|
||||
testdiggydiggyhole = {
|
||||
title = "Dig 10 stone nodes",
|
||||
max = 10,
|
||||
desc = "As long as you can not dig stone, you are not a real miner.",
|
||||
periodicity = 10,
|
||||
objective = {
|
||||
dig = {"default:stone"}
|
||||
still_testing_quests = {
|
||||
title = "Stone digger",
|
||||
description = "TEST QUEST!\nGet a mithril ingot at the end!",
|
||||
repeating = 60*60*24,
|
||||
awards = {["moreores:mithril_ingot"] = 1},
|
||||
tasks = {
|
||||
diggy = {
|
||||
title = "Dig 99 stone",
|
||||
description = "Show you can dig through stone",
|
||||
max = 99,
|
||||
objective = {
|
||||
dig = {"default:stone"}
|
||||
}
|
||||
},
|
||||
diggysrevenge = {
|
||||
title = "Dig the last stone",
|
||||
description = "You really thought 99 was a good number? Dig the last one.",
|
||||
requires = {"diggy"},
|
||||
max = 1,
|
||||
objective = {
|
||||
dig = {"default:stone"}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
still_testing_quests2 = {
|
||||
title = "Coal digger",
|
||||
description = "TEST QUEST!\nGet a mithril ingot at the end!",
|
||||
repeating = 60*60*24,
|
||||
awards = {["moreores:mithril_ingot"] = 1},
|
||||
tasks = {
|
||||
diggy = {
|
||||
title = "Dig 19 coal",
|
||||
description = "Get the fire mineral",
|
||||
max = 19,
|
||||
objective = {
|
||||
dig = {"default:stone_with_coal"}
|
||||
}
|
||||
},
|
||||
diggysrevenge = {
|
||||
title = "Dig the last one",
|
||||
description = "I do this because of a technical issue, sorry",
|
||||
requires = {"diggy"},
|
||||
max = 1,
|
||||
objective = {
|
||||
dig = {"default:stone_with_coal"}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
still_testing_quests3 = {
|
||||
title = "Shiny diamonds",
|
||||
description = "TEST QUEST!\nGet a mithril ingot at the end!",
|
||||
repeating = 60*60*24,
|
||||
awards = {["moreores:mithril_ingot"] = 1},
|
||||
tasks = {
|
||||
diggy = {
|
||||
title = "Dig 4 diamond",
|
||||
description = "Yarr harr fiddle dee-dee, being a pirate is alright with me! Do what you want 'cause a pirate is free, you are a pirate! Go get the precious booty... underground. Mine it :/",
|
||||
max = 4,
|
||||
objective = {
|
||||
dig = {"default:stone_with_diamond"}
|
||||
}
|
||||
},
|
||||
diggysrevenge = {
|
||||
title = "Ultimate calbon atom alignement",
|
||||
description = "Really, we must fix this",
|
||||
requires = {"diggy"},
|
||||
max = 1,
|
||||
objective = {
|
||||
dig = {"default:stone_with_diamond"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mff.quests.quest_status = {}
|
||||
|
||||
function table.contains(table, element)
|
||||
for _, value in pairs(table) do
|
||||
if value == element then
|
||||
|
@ -39,82 +90,49 @@ function table.contains(table, element)
|
|||
end
|
||||
|
||||
function mff.quests.start_quest(playername, qname, meta)
|
||||
mff.quests.quest_status[playername][qname] = 0
|
||||
quests.start_quest(playername, mff.QPREFIX .. qname, meta)
|
||||
end
|
||||
|
||||
function mff.quests.restart_periodic_quest(playername, qname)
|
||||
mff.quests.start_quest(playername, qname)
|
||||
end
|
||||
|
||||
function mff.quests.start_periodicity_timer(playername, qname)
|
||||
local tstamp = -mff.quests.quest_status[playername][qname]
|
||||
minetest.after(tstamp-os.time(), mff.quests.restart_periodic_quest, playername, qname)
|
||||
end
|
||||
|
||||
function mff.quests.start_all_periodicity_timers(playername)
|
||||
local qstatus = mff.quests.quest_status[playername]
|
||||
for qname, _ in pairs(qstatus) do
|
||||
mff.quests.start_periodicity_timer(playername, qname)
|
||||
end
|
||||
end
|
||||
|
||||
function mff.quests.set_quest_ended(playername, questname, metadata)
|
||||
local qstatus = mff.quests.quest_status[playername]
|
||||
local qname = questname:sub(mff.QPREFIX:len()+1)
|
||||
local qinfo = mff.quests.quests[qname]
|
||||
if qinfo.periodicity ~= nil and qinfo.periodicity >= 1 then
|
||||
qstatus[qname] = -(os.time() + qinfo.periodicity)
|
||||
mff.quests.start_periodicity_timer(playername, qname)
|
||||
else
|
||||
qstatus[qname] = nil
|
||||
function mff.quests.handle_quest_end(playername, questname, metadata)
|
||||
for item, count in pairs(mff.quests.quests[mff.QNOPREFIX(questname)].awards) do
|
||||
minetest.add_item(minetest.get_player_by_name(playername):getpos(), {name=item, count=count, wear=0, metadata=""})
|
||||
end
|
||||
end
|
||||
|
||||
-- Register the quests defined above
|
||||
for qname, quest in pairs(mff.quests.quests) do
|
||||
quests.register_quest(mff.QPREFIX .. qname, {
|
||||
title = quest.title,
|
||||
description = quest.desc,
|
||||
max = quest.max,
|
||||
autoaccept = true,
|
||||
callback = mff.quests.set_quest_ended
|
||||
})
|
||||
quest.completecallback = mff.quests.handle_quest_end
|
||||
local ret = quests.register_quest(mff.QPREFIX .. qname, quest)
|
||||
end
|
||||
|
||||
-- For quests where you have to dig something, the updates happen here
|
||||
-- TODO
|
||||
-- implement magical iterator, going through BOTH the simple quests
|
||||
-- AND tasked quests objectives, returning a tuple like this:
|
||||
-- questname, questdef, taskname (nil?), taskdef (nil?), objective_container (that is, either questdef or taskdef), pointer_to_function_to_update_the_objective_progress_with_only_one_parameter_the_others_being_automagically_passed_to_the_quests_API_so_that_we_dont_have_to_write_ifs_and_elses_everywhere_to_handle_both_quest_and_tasks_cases_because_it_would_give_crap_code
|
||||
|
||||
minetest.register_on_dignode(function(pos, oldnode, digger)
|
||||
if not digger then return end -- Already happened before
|
||||
local qstatus = mff.quests.quest_status[digger:get_player_name()]
|
||||
if not digger then return end
|
||||
local pname = digger:get_player_name()
|
||||
for qname, quest in pairs(mff.quests.quests) do
|
||||
if qstatus[qname] ~= nil and qstatus[qname] >= 0 then
|
||||
if quest.objective.dig then
|
||||
if table.contains(quest.objective.dig, oldnode.name) then
|
||||
quests.update_quest(digger:get_player_name(), mff.QPREFIX .. qname, 1)
|
||||
if quest.tasks then
|
||||
for tname, task in pairs(quest.tasks) do
|
||||
if quests.is_task_visible(pname, mff.QPREFIX .. qname, tname)
|
||||
and not quests.is_task_disabled(pname, mff.QPREFIX .. qname, tname)
|
||||
and task.objective.dig then
|
||||
if table.contains(task.objective.dig, oldnode.name) then
|
||||
quests.update_quest_task(pname, mff.QPREFIX .. qname, tname, 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- TODO load data
|
||||
--[[
|
||||
for playername in players do
|
||||
mff.quests.start_all_periodicity_timers(playername)
|
||||
end
|
||||
]]
|
||||
|
||||
minetest.register_on_joinplayer(function (player)
|
||||
-- TODO do nothing
|
||||
mff.quests.quest_status[player:get_player_name()] = {}
|
||||
mff.quests.start_quest(player:get_player_name(), "testdiggydiggyhole")
|
||||
end)
|
||||
|
||||
minetest.register_on_leaveplayer(function (player)
|
||||
-- TODO do nothing
|
||||
mff.quests.quest_status[player:get_player_name()] = nil
|
||||
end)
|
||||
|
||||
minetest.register_on_shutdown(function()
|
||||
-- TODO save data
|
||||
end)
|
||||
local playername = player:get_player_name()
|
||||
for _, qname in ipairs({"still_testing_quests", "still_testing_quests2", "still_testing_quests3"}) do
|
||||
if not quests.quest_restarting_in(playername, mff.QPREFIX .. qname) then
|
||||
mff.quests.start_quest(playername, qname)
|
||||
end
|
||||
end
|
||||
end)
|
0
mods/quests/README
Executable file → Normal file
0
mods/quests/central_message.lua
Executable file → Normal file
621
mods/quests/core.lua
Executable file → Normal file
|
@ -1,3 +1,6 @@
|
|||
--- Quests core.
|
||||
-- @module core
|
||||
|
||||
-- Boilerplate to support localized strings if intllib mod is installed.
|
||||
local S
|
||||
if minetest.get_modpath("intllib") then
|
||||
|
@ -6,91 +9,276 @@ else
|
|||
-- If you don't use insertions (@1, @2, etc) you can use this:
|
||||
S = function(s) return s end
|
||||
end
|
||||
local empty_callback = function(...) end
|
||||
|
||||
|
||||
-- registers a quest for later use
|
||||
--
|
||||
-- questname is the name of the quest to identify it later
|
||||
-- it should follow the naming conventions: "modname:questname"
|
||||
-- quest is a table in the following format
|
||||
-- {
|
||||
-- title, -- is shown to the player and should contain usefull information about the quest.
|
||||
-- description, -- a small description of the mod.
|
||||
-- max, -- is the desired maximum. If max is 1, no maximum is displayed. defaults to 1
|
||||
-- autoaccept, -- is true or false, wether the result of the quest should be dealt by this mode or the registering mod.
|
||||
-- callback -- when autoaccept is true, at the end of the quest, it gets removed and callback is called.
|
||||
-- -- function(playername, questname, metadata)
|
||||
-- }
|
||||
--
|
||||
-- returns true, when the quest was successfully registered
|
||||
-- returns falls, when there was already such a quest
|
||||
function quests.register_quest(questname, quest)
|
||||
if (quests.registered_quests[questname] ~= nil) then
|
||||
return false -- The quest was not registered since there already a quest with that name
|
||||
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
|
||||
plr_task.visible = false
|
||||
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_quest[enabler_name]) do
|
||||
local plr_subena = plr_task[subena_name]
|
||||
if plr_task.visible and plr_subena and (not plr_subena.visible or not plr_subena.finished) then
|
||||
plr_task.visible = false
|
||||
end
|
||||
end
|
||||
else
|
||||
if plr_quest[enabler_name] then
|
||||
plr_task.visible = plr_quest[enabler_name].finished or false
|
||||
else
|
||||
plr_task.visible = true
|
||||
end
|
||||
end
|
||||
if plr_task.visible then
|
||||
final_enabler = enabler_name
|
||||
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_quest[subdis_name]
|
||||
if not plr_task.disabled and plr_subdis.visible and plr_subdis.finished then
|
||||
plr_task.disabled = true
|
||||
end
|
||||
end
|
||||
else
|
||||
plr_task.disabled = plr_quest[disabler_name].finished
|
||||
end
|
||||
if plr_task.disabled then
|
||||
final_disabler = disabler_name
|
||||
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.
|
||||
--
|
||||
-- * Simple quests are made of a single objective
|
||||
-- * Taked quests are made of tasks, allowing simultaneous progress
|
||||
-- within the quest as well as branching quest objectives
|
||||
--
|
||||
-- Both quest types are defined by a table, and they share common information:
|
||||
-- {
|
||||
-- title, -- Self-explanatory. Should describe the objective for simple quests.
|
||||
-- description, -- Description/lore of the quest
|
||||
-- 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.
|
||||
-- completecallback, -- If autoaccept is true, gets called at quest completion.
|
||||
-- -- function(playername, questname, metadata)
|
||||
-- abortcallback, -- Called when a player cancels the quest. function(playername, questname, metadata)
|
||||
-- repeating -- Delay in seconds before the quest becomes available again. If nil, 0 or false, doesn't restart.
|
||||
-- }
|
||||
--
|
||||
-- In addition, simple quests have a number-type `max` element indicating the max progress of the quest.
|
||||
-- As for tasked quests, they have a table-type `tasks` element which value is like this:
|
||||
-- tasks = {
|
||||
-- start = {
|
||||
-- title,
|
||||
-- description,
|
||||
-- icon,
|
||||
-- max -- Max task progress
|
||||
-- },
|
||||
-- another_task = {
|
||||
-- [...],
|
||||
--
|
||||
-- requires = {"start"},
|
||||
-- -- Table of task names which one must be completed for this task to unlock.
|
||||
-- -- 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. 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
|
||||
--
|
||||
-- completecallback,
|
||||
-- -- Called upon task completion.
|
||||
-- -- function(playername, questname, taskname, metadata)
|
||||
-- }
|
||||
-- something = {
|
||||
-- [...],
|
||||
-- requires = {"start"},
|
||||
--
|
||||
-- disables_on = {"another_task"},
|
||||
-- -- Same as `requires`, but *disables* the task (it then does not count towards quest completion)
|
||||
--
|
||||
-- disablecallback,
|
||||
-- -- 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.
|
||||
-- Some task names are reserved and will be ignored:
|
||||
--
|
||||
-- * `metadata`
|
||||
-- * `finished`
|
||||
-- * `value`
|
||||
--
|
||||
-- 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
|
||||
return false -- The quest was not registered since there's already a quest with that name
|
||||
end
|
||||
quests.registered_quests[questname] = {
|
||||
title = quest.title or S("missing title"),
|
||||
description = quest.description or S("missing description"),
|
||||
icon = quest.icon or "quests_default_quest_icon.png",
|
||||
startcallback = quest.startcallback or empty_callback,
|
||||
autoaccept = not(quest.autoaccept == false),
|
||||
completecallback = quest.completecallback or empty_callback,
|
||||
abortcallback = quest.abortcallback or empty_callback,
|
||||
repeating = quest.repeating or 0
|
||||
}
|
||||
local new_quest = quests.registered_quests[questname]
|
||||
if quest.max ~= nil then -- Simple quest
|
||||
new_quest.max = quest.max or 1
|
||||
new_quest.simple = true
|
||||
else
|
||||
if quest.tasks == nil or type(quest.tasks) ~= "table" then
|
||||
quests.registered_quests[questname] = nil
|
||||
return false
|
||||
end
|
||||
new_quest.tasks = {}
|
||||
local tcount = 0
|
||||
for tname, task in pairs(quest.tasks) do
|
||||
if tname ~= "metadata" and tname ~= "finished" and tname ~= "value" then
|
||||
new_quest.tasks[tname] = {
|
||||
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,
|
||||
completecallback = task.completecallback or empty_callback
|
||||
}
|
||||
tcount = tcount + 1
|
||||
end
|
||||
end
|
||||
if tcount == 0 then -- No tasks!
|
||||
quests.registered_quests[questname] = nil
|
||||
return false
|
||||
end
|
||||
end
|
||||
quests.registered_quests[questname] =
|
||||
{ title = quest.title or S("missing title"),
|
||||
description = quest.description or S("missing description"),
|
||||
max = quest.max or 1,
|
||||
autoaccept = quest.autoaccept or false,
|
||||
callback = quest.callback, }
|
||||
return true
|
||||
end
|
||||
|
||||
-- starts a quest for a specified player
|
||||
--
|
||||
-- playername - the name of the player
|
||||
-- questname - the name of the quest, which was registered with quests.register_quest
|
||||
-- metadata - optional additional data
|
||||
--
|
||||
-- returns false on failure
|
||||
-- returns true if the quest was started
|
||||
--- Starts a quest for a specified player.
|
||||
-- @param playername Name of the player
|
||||
-- @param questname Name of the quest, which was registered with @{quests.register_quest}
|
||||
-- @param metadata Optional additional data
|
||||
-- @return `false` on failure
|
||||
-- @return `true` if the quest was started
|
||||
function quests.start_quest(playername, questname, metadata)
|
||||
if (quests.registered_quests[questname] == nil) then
|
||||
local quest = quests.registered_quests[questname]
|
||||
if quest == nil then
|
||||
return false
|
||||
end
|
||||
if (quests.active_quests[playername] == nil) then
|
||||
if quests.active_quests[playername] == nil then
|
||||
quests.active_quests[playername] = {}
|
||||
end
|
||||
if (quests.active_quests[playername][questname] ~= nil) then
|
||||
return false -- the player has already this quest
|
||||
if quests.active_quests[playername][questname] ~= nil then
|
||||
return false -- the player already has this quest
|
||||
end
|
||||
if quest.simple then
|
||||
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
|
||||
compute_tasks(playername, questname)
|
||||
end
|
||||
quests.active_quests[playername][questname] = {value = 0, metadata = metadata}
|
||||
|
||||
quests.update_hud(playername)
|
||||
quests.show_message("new", playername, S("New quest:") .. " " .. quests.registered_quests[questname].title)
|
||||
quests.show_message("new", playername, S("New quest:") .. " " .. quest.title)
|
||||
return true
|
||||
end
|
||||
|
||||
-- when something happens that has effect on a quest, a mod should call this method
|
||||
-- playername is the name of the player
|
||||
-- questname is the quest which gets updated
|
||||
-- the quest gets updated by value
|
||||
-- this method calls a previously specified callback if autoaccept is true
|
||||
--
|
||||
-- returns true if the quest is finished
|
||||
-- returns false if there is no such quest or the quest continues
|
||||
local function check_active_quest(playername, questname)
|
||||
return not(
|
||||
playername == nil or
|
||||
questname == nil or
|
||||
quests.registered_quests[questname] == nil or -- Quest doesn't exist
|
||||
quests.active_quests[playername] == nil or -- Player has no data
|
||||
quests.active_quests[playername][questname] == nil -- Quest isn't active
|
||||
)
|
||||
end
|
||||
local function check_active_quest_task(playername, questname, taskname)
|
||||
return not(
|
||||
taskname == nil or
|
||||
not check_active_quest(playername, questname) or
|
||||
quests.registered_quests[questname].simple or -- Quest is simple (i.e. no tasks)
|
||||
quests.registered_quests[questname].tasks == nil or -- Who knows? Avoid crash.
|
||||
quests.registered_quests[questname].tasks[taskname] == nil or -- No such task
|
||||
quests.active_quests[playername][questname][taskname] == nil -- Player quest data has no such task
|
||||
)
|
||||
end
|
||||
|
||||
--- Updates a *simple* quest's status.
|
||||
-- Calls the quest's `completecallback` if autoaccept is `true` and the quest reaches its max value.
|
||||
-- Has no effect on tasked quests.
|
||||
-- @param playername Name of the player
|
||||
-- @param questname Quest which gets updated
|
||||
-- @param value Value to add to the quest's progress (can be negative)
|
||||
-- @return `true` if the quest is finished
|
||||
-- @return `false` if the quest continues
|
||||
-- @return `nil` if there is no such quest, it is a tasked or non-active one, or no value was given
|
||||
-- @see quests.update_quest_task
|
||||
function quests.update_quest(playername, questname, value)
|
||||
if (quests.active_quests[playername] == nil) then
|
||||
quests.active_quests[playername] = {}
|
||||
if not check_active_quest(playername, questname) or not quests.registered_quests[questname].simple
|
||||
or value == nil then
|
||||
return nil
|
||||
end
|
||||
if (quests.active_quests[playername][questname] == nil) then
|
||||
return false -- there is no such quest
|
||||
local plr_quest = quests.active_quests[playername][questname]
|
||||
if plr_quest.finished then
|
||||
return true -- The quest is already finished
|
||||
end
|
||||
if (quests.active_quests[playername][questname].finished) then
|
||||
return false -- the quest is already finished
|
||||
end
|
||||
if (value == nil) then
|
||||
return false -- no value given
|
||||
end
|
||||
quests.active_quests[playername][questname]["value"] = quests.active_quests[playername][questname]["value"] + value
|
||||
if (quests.active_quests[playername][questname]["value"] >= quests.registered_quests[questname]["max"]) then
|
||||
quests.active_quests[playername][questname]["value"] = quests.registered_quests[questname]["max"]
|
||||
if (quests.registered_quests[questname]["autoaccept"]) then
|
||||
if (quests.registered_quests[questname]["callback"] ~= nil) then
|
||||
quests.registered_quests[questname]["callback"](playername, questname,
|
||||
quests.active_quests[playername][questname].metadata)
|
||||
end
|
||||
local quest = quests.registered_quests[questname]
|
||||
plr_quest.value = plr_quest.value + value
|
||||
if plr_quest.value >= quest.max then
|
||||
plr_quest.value = quest.max
|
||||
if quest.autoaccept then
|
||||
quest.completecallback(playername, questname, plr_quest.metadata)
|
||||
quests.accept_quest(playername,questname)
|
||||
quests.update_hud(playername)
|
||||
end
|
||||
|
@ -100,27 +288,238 @@ function quests.update_quest(playername, questname, value)
|
|||
return false -- the quest continues
|
||||
end
|
||||
|
||||
-- When the mod handels the end of quests himself, e.g. you have to talk to somebody to finish the quest,
|
||||
--- Get a *simple* quest's progress.
|
||||
-- @param playername Name of the player
|
||||
-- @param questname Quest to get the progress value from
|
||||
-- @return `number` of the progress
|
||||
-- @return `nil` if there is no such quest, it is a tasked or non-active one
|
||||
-- @see quests.get_task_progress
|
||||
function quests.get_quest_progress(playername, questname)
|
||||
if not check_active_quest(playername, questname) or not quests.registered_quests[questname].simple then
|
||||
return nil
|
||||
end
|
||||
local plr_quest = quests.active_quests[playername][questname]
|
||||
if plr_quest.finished then
|
||||
return nil
|
||||
end
|
||||
return plr_quest.value
|
||||
end
|
||||
|
||||
--- Updates a *tasked* quest task's status.
|
||||
-- Calls the quest's `completecallback` if autoaccept is `true` and all the quest's visible
|
||||
-- and non-disabled tasks reaches their max value.
|
||||
-- Also calls the task's `completecallback` it it gets completed.
|
||||
-- Has no effect on simple quests.
|
||||
-- @param playername Name of the player
|
||||
-- @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 task is finished
|
||||
-- @return `false` if it continues
|
||||
-- @return `nil` if there is no such quest/task, is a simple or non-active quest, or no value was given
|
||||
-- @see quests.update_quest
|
||||
function quests.update_quest_task(playername, questname, taskname, value)
|
||||
if not check_active_quest_task(playername, questname, taskname) or value == nil then
|
||||
return nil
|
||||
end
|
||||
local plr_quest = quests.active_quests[playername][questname]
|
||||
local plr_task = plr_quest[taskname]
|
||||
if plr_task.finished then
|
||||
return true -- The task is already finished
|
||||
end
|
||||
|
||||
local quest = quests.registered_quests[questname]
|
||||
local task = quest.tasks[taskname]
|
||||
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.completecallback(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
|
||||
local plr_task = plr_quest[taskname]
|
||||
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.completecallback(playername, questname, plr_quest.metadata)
|
||||
quests.accept_quest(playername,questname)
|
||||
quests.update_hud(playername)
|
||||
end
|
||||
-- If the update of this task ends the quest, it consequently *is* finished.
|
||||
return true
|
||||
end
|
||||
quests.update_hud(playername)
|
||||
return task_finished
|
||||
end
|
||||
|
||||
--- Get a task's progress.
|
||||
-- Returns the max progress value possible for the given task if it is complete.
|
||||
-- @param playername Name of the player
|
||||
-- @param questname Quest the task belongs to
|
||||
-- @param taskname Task to get the progress value from
|
||||
-- @return `number` of the progress
|
||||
-- @return `false` if the task has been disabled by another
|
||||
-- @return `nil` if there is no such quest/task, or is a simple or non-active quest
|
||||
-- @see quests.get_quest_progress
|
||||
function quests.get_task_progress(playername, questname, taskname)
|
||||
if not not check_active_quest_task(playername, questname, taskname) then
|
||||
return nil
|
||||
end
|
||||
local plr_quest = quests.active_quests[playername][questname]
|
||||
if plr_quest.finished then
|
||||
return nil
|
||||
end
|
||||
local plr_task = plr_quest[taskname]
|
||||
if not plr_task then
|
||||
return nil
|
||||
end
|
||||
if plr_task.disabled then
|
||||
return false
|
||||
end
|
||||
return plr_task.value
|
||||
end
|
||||
|
||||
--- Checks if a quest's task is visible to the player.
|
||||
-- @param playername Name of the player
|
||||
-- @param questname Quest which contains the task
|
||||
-- @param taskname Task to check visibility
|
||||
-- @return `true` if the task is visible
|
||||
-- @return `false` if it is not
|
||||
-- @return `nil` if the quest/task doesn't exist, is simple or isn't active
|
||||
function quests.is_task_visible(playername, questname, taskname)
|
||||
if not check_active_quest_task(playername, questname, taskname) then
|
||||
return nil
|
||||
end
|
||||
return quests.active_quests[playername][questname][taskname].visible
|
||||
end
|
||||
|
||||
--- Checks if a quest's task is disabled to the player.
|
||||
-- @param playername Name of the player
|
||||
-- @param questname Quest which contains the task
|
||||
-- @param taskname Task to check if it is disabled
|
||||
-- @return `true` if the task is disabled
|
||||
-- @return `false` if it is not
|
||||
-- @return `nil` if the quest/task doesn't exist, is simple or isn't active
|
||||
function quests.is_task_disabled(playername, questname, taskname)
|
||||
if not check_active_quest_task(playername, questname, taskname) then
|
||||
return nil
|
||||
end
|
||||
return quests.active_quests[playername][questname][taskname].disabled
|
||||
end
|
||||
|
||||
--- Gets the number of active (visible & non-disabled) tasks, and how many of them are completed
|
||||
-- @param playername Name of the player
|
||||
-- @param questname Quest name
|
||||
-- @return `number, number` pair, where the first is the number of active tasks, and the second how many of them are completed
|
||||
-- @return `nil` if the quest doesn't exist, is simple or isn't active
|
||||
function quests.get_active_tasks_stats(playername, questname)
|
||||
if not check_active_quest(playername, questname) or quests.registered_quests[questname].simple then
|
||||
return nil
|
||||
end
|
||||
local plr_quest = quests.active_quests[playername][questname]
|
||||
local active_tasks = 0
|
||||
local completed_active = 0
|
||||
for taskname, _ in pairs(quests.registered_quests[questname].tasks) do
|
||||
local plr_task = plr_quest[taskname]
|
||||
if plr_task.visible and not plr_task.disabled then
|
||||
active_tasks = active_tasks + 1
|
||||
if plr_task.finished then
|
||||
completed_active = completed_active + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
return active_tasks, completed_active
|
||||
end
|
||||
|
||||
--- Gets number of seconds before a quest can be done again.
|
||||
-- @param playername Player's name
|
||||
-- @param questname Quest name
|
||||
-- @return `number` of seconds before quests becomes available
|
||||
-- @return `nil` if the quest isn't repeating
|
||||
function quests.quest_restarting_in(playername, questname)
|
||||
if quests.info_quests[playername] and
|
||||
quests.info_quests[playername][questname] and
|
||||
quests.info_quests[playername][questname].restart_tstamp then
|
||||
return quests.info_quests[playername][questname].restart_tstamp - os.time()
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function restart_periodic_quest(playername, questname)
|
||||
quests.start_quest(playername, questname)
|
||||
if quests.info_quests[playername] and quests.info_quests[playername][questname] then
|
||||
quests.info_quests[playername][questname].restart_tstamp = nil
|
||||
end
|
||||
end
|
||||
|
||||
local function start_repeating_timer(playername, questname)
|
||||
local delay = quests.quest_restarting_in(playername, questname)
|
||||
if delay ~= nil then
|
||||
minetest.after(delay, restart_periodic_quest, playername, questname)
|
||||
end
|
||||
end
|
||||
|
||||
local function start_all_repeating_timers(playername)
|
||||
local qinfos = quests.info_quests[playername]
|
||||
if qinfos then
|
||||
for questname, qinfo in pairs(qinfos) do
|
||||
if qinfo.restart_tstamp then
|
||||
start_repeating_timer(playername, questname)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Restart all stopped repeating quests' timers
|
||||
for playername, _ in pairs(quests.info_quests) do
|
||||
start_all_repeating_timers(playername)
|
||||
end
|
||||
|
||||
local function handle_quest_end(playername, questname)
|
||||
local quest = quests.registered_quests[questname]
|
||||
if quest.repeating ~= 0 then
|
||||
quests.info_quests[playername] = quests.info_quests[playername] or {}
|
||||
quests.info_quests[playername][questname] = quests.info_quests[playername][questname] or {}
|
||||
local qinfo = quests.info_quests[playername][questname]
|
||||
qinfo.restart_tstamp = os.time() + quest.repeating
|
||||
start_repeating_timer(playername, questname)
|
||||
end
|
||||
end
|
||||
|
||||
--- Confirms quest completion and ends it.
|
||||
-- When the mod handles the end of quests himself, e.g. you have to talk to somebody to finish the quest,
|
||||
-- you have to call this method to end a quest
|
||||
-- returns true, when the quest is completed
|
||||
-- returns false, when the quest is still ongoing
|
||||
-- @param playername Player's name
|
||||
-- @param questname Quest name
|
||||
-- @return `true` when the quest is completed
|
||||
-- @return `false` when an error occured (the quest is still ongoing if it was)
|
||||
function quests.accept_quest(playername, questname)
|
||||
if (quests.active_quests[playername][questname] and not quests.active_quests[playername][questname].finished) then
|
||||
if (quests.successfull_quests[playername] == nil) then
|
||||
if check_active_quest(playername, questname) and not quests.active_quests[playername][questname].finished then
|
||||
if quests.successfull_quests[playername] == nil then
|
||||
quests.successfull_quests[playername] = {}
|
||||
end
|
||||
if (quests.successfull_quests[playername][questname] ~= nil) then
|
||||
if quests.successfull_quests[playername][questname] ~= nil then
|
||||
quests.successfull_quests[playername][questname].count = quests.successfull_quests[playername][questname].count + 1
|
||||
else
|
||||
quests.successfull_quests[playername][questname] = {count = 1}
|
||||
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
|
||||
end
|
||||
handle_quest_end(playername, questname)
|
||||
quests.show_message("success", playername, S("Quest completed:") .. " " .. quests.registered_quests[questname].title)
|
||||
minetest.after(3, function(playername, questname)
|
||||
quests.active_quests[playername][questname] = nil
|
||||
|
@ -131,22 +530,21 @@ function quests.accept_quest(playername, questname)
|
|||
return false -- the quest hasn't finished
|
||||
end
|
||||
|
||||
-- call this method, when you want to end a quest even when it was not finished
|
||||
-- example: the player failed
|
||||
--
|
||||
-- returns false if the quest was not aborted
|
||||
-- returns true when the quest was aborted
|
||||
--- Aborts a quest.
|
||||
-- Call this method when you want to end a quest even when it was not finished.
|
||||
-- Example: the player failed.
|
||||
-- @param playername Player's name
|
||||
-- @param questname Quest name
|
||||
-- @return `true` when the quest was aborted
|
||||
-- @return `false` if there was an error (quest not aborted)
|
||||
function quests.abort_quest(playername, questname)
|
||||
if (questname == nil) then
|
||||
if not check_active_quest(playername, questname) then
|
||||
return false
|
||||
end
|
||||
if (quests.failed_quests[playername] == nil) then
|
||||
if quests.failed_quests[playername] == nil then
|
||||
quests.failed_quests[playername] = {}
|
||||
end
|
||||
if (quests.active_quests[playername][questname] == nil) then
|
||||
return false
|
||||
end
|
||||
if (quests.failed_quests[playername][questname] ~= nil) then
|
||||
if quests.failed_quests[playername][questname] ~= nil then
|
||||
quests.failed_quests[playername][questname].count = quests.failed_quests[playername][questname].count + 1
|
||||
else
|
||||
quests.failed_quests[playername][questname] = { count = 1 }
|
||||
|
@ -154,30 +552,69 @@ function quests.abort_quest(playername, questname)
|
|||
|
||||
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.failed)
|
||||
end
|
||||
end
|
||||
quests.show_message("failed", playername, S("Quest failed:") .. " " .. quests.registered_quests[questname].title)
|
||||
|
||||
local quest = quests.registered_quests[questname]
|
||||
quest.abortcallback(playername, questname, quests.active_quests[playername][questname].metadata)
|
||||
handle_quest_end(playername, questname)
|
||||
quests.show_message("failed", playername, S("Quest failed:") .. " " .. quest.title)
|
||||
minetest.after(3, function(playername, questname)
|
||||
quests.active_quests[playername][questname] = nil
|
||||
quests.update_hud(playername)
|
||||
end, playername, questname)
|
||||
return true
|
||||
end
|
||||
|
||||
-- get metadata of the quest if the quest exists, else return nil
|
||||
--- Set quest HUD visibility.
|
||||
-- @param playername Player's name
|
||||
-- @param questname Quest name
|
||||
-- @param visible `bool` indicating if the quest should be visible
|
||||
-- @see quests.get_quest_hud_visibility
|
||||
function quests.set_quest_hud_visibility(playername, questname, visible)
|
||||
if not check_active_quest(playername, questname) then
|
||||
return
|
||||
end
|
||||
quests.info_quests[playername] = quests.info_quests[playername] or {}
|
||||
quests.info_quests[playername][questname] = quests.info_quests[playername][questname] or {}
|
||||
quests.info_quests[playername][questname].hide_from_hud = not visible
|
||||
quests.update_hud(playername)
|
||||
end
|
||||
|
||||
--- Get quest HUD visibility.
|
||||
-- @param playername Player's name
|
||||
-- @param questname Quest name
|
||||
-- @return `bool`: quest HUD visibility
|
||||
-- @see quests.set_quest_hud_visibility
|
||||
function quests.get_quest_hud_visibility(playername, questname)
|
||||
if not check_active_quest(playername, questname) then
|
||||
return false
|
||||
end
|
||||
local plr_qinfos = quests.info_quests[playername]
|
||||
return not(plr_qinfos and plr_qinfos[questname] and plr_qinfos[questname].hide_from_hud)
|
||||
end
|
||||
|
||||
--- Get quest metadata.
|
||||
-- @return Metadata of the quest, `nil` if there is none
|
||||
-- @return `nil, false` if the quest doesn't exist or isn't active
|
||||
-- @see quests.set_metadata
|
||||
function quests.get_metadata(playername, questname)
|
||||
if (quests.active_quests[playername] == nil or quests.active_quests[playername][questname] == nil) then
|
||||
return nil
|
||||
if not check_active_quest(playername, questname) then
|
||||
return nil, false
|
||||
end
|
||||
return quests.active_quests[playername][questname].metadata
|
||||
end
|
||||
|
||||
-- set metadata of the quest
|
||||
--- Set quest metadata.
|
||||
-- @return `false` if the quest doesn't exist or isn't active
|
||||
-- @return `nil` otherwise
|
||||
-- @see quests.get_metadata
|
||||
function quests.set_metadata(playername, questname, metadata)
|
||||
if (quests.active_quests[playername] == nil or quests.active_quests[playername][questname] == nil) then
|
||||
return
|
||||
if not check_active_quest(playername, questname) then
|
||||
return false
|
||||
end
|
||||
quests.active_quests[playername][questname].metadata = metadata
|
||||
end
|
||||
|
|
0
mods/quests/depends.txt
Executable file → Normal file
239
mods/quests/formspecs.lua
Executable file → Normal file
|
@ -7,52 +7,82 @@ else
|
|||
S = function(s) return s end
|
||||
end
|
||||
|
||||
|
||||
-- construct the questlog
|
||||
function quests.create_formspec(playername, tab, integrated)
|
||||
local queststringlist = {}
|
||||
local questlist = {}
|
||||
quests.formspec_lists[playername] = quests.formspec_lists[playername] or {}
|
||||
quests.formspec_lists[playername].id = 1
|
||||
quests.formspec_lists[playername] = quests.formspec_lists[playername] or {
|
||||
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"] .. ")"
|
||||
local quest_count = 0
|
||||
for questname,questspecs in quests.sorted_pairs(questlist) do
|
||||
if not questspecs.finished then
|
||||
local quest = quests.registered_quests[questname]
|
||||
if quest then -- Quest might have been deleted
|
||||
local queststring = quest.title
|
||||
if questspecs.count then
|
||||
if questspecs.count > 1 then
|
||||
queststring = queststring .. " - " .. questspecs.count
|
||||
end
|
||||
local restart_remaining = quests.quest_restarting_in(playername, questname)
|
||||
if restart_remaining ~= nil then
|
||||
queststring = queststring .. " (" .. S("restarts in %ds"):format(restart_remaining) .. ")"
|
||||
end
|
||||
elseif not questspecs.count and quest.max ~= 1 then
|
||||
if quest.simple then
|
||||
queststring = queststring .. " (" .. quests.round(questspecs.value, 2) .. "/" .. quest.max .. ")"
|
||||
else
|
||||
local active_tasks, active_completed = quests.get_active_tasks_stats(playername, questname)
|
||||
if active_tasks and active_completed then
|
||||
queststring = queststring .. " (" .. S("%d/%d tasks done"):format(active_completed, active_tasks) .. ")"
|
||||
else
|
||||
-- Kind of an error
|
||||
queststring = queststring .. " (...)"
|
||||
end
|
||||
end
|
||||
end
|
||||
table.insert(queststringlist, queststring)
|
||||
table.insert(quests.formspec_lists[playername].list, questname)
|
||||
quest_count = quest_count + 1
|
||||
end
|
||||
table.insert(queststringlist, queststring)
|
||||
table.insert(quests.formspec_lists[playername].list, questname)
|
||||
no_quests = false
|
||||
end
|
||||
end
|
||||
if quest_count ~= 0 and quests.formspec_lists[playername].id > quest_count then
|
||||
quests.formspec_lists[playername].id = quest_count
|
||||
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 quest_count == 0 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]"
|
||||
formspec = formspec .. "textlist[0.25,0.25;6.5,6;quests_questlist;"..table.concat(queststringlist, ",") .. ";" .. tostring(quests.formspec_lists[playername].id) .. ";false]"
|
||||
end
|
||||
if (quests.formspec_lists[playername].tab == "1") then
|
||||
formspec = formspec .."button[0.25,7;3,.7;quests_abort;" .. S("Abort quest") .. "]"
|
||||
if quests.formspec_lists[playername].tab == "1" then
|
||||
local hud_display = "true"
|
||||
if quests.formspec_lists[playername].id then
|
||||
local questname = quests.formspec_lists[playername].list[quests.formspec_lists[playername].id]
|
||||
if not quests.get_quest_hud_visibility(playername, questname) then
|
||||
hud_display = "false"
|
||||
end
|
||||
end
|
||||
formspec = formspec .."button[0.25,7.1;3,.7;quests_abort;" .. S("Abort quest") .. "]" ..
|
||||
"checkbox[.25,6.2;quests_show_quest_in_hud;" .. S("Show in HUD") .. ";" .. hud_display .. "]"
|
||||
end
|
||||
formspec = formspec .. "button[3.75,7;3,.7;quests_config;" .. S("Configure") .. "]"..
|
||||
formspec = formspec .. "button[3.75,7.1;3,.7;quests_config;" .. S("Configure") .. "]"..
|
||||
"button[.25,8;3,.7;quests_info;" .. S("Info") .. "]"..
|
||||
"button_exit[3.75,8;3,.7;quests_exit;" .. S("Exit") .. "]"
|
||||
return formspec
|
||||
|
@ -75,7 +105,7 @@ function quests.create_config(playername, integrated)
|
|||
formspec = formspec .. "true"
|
||||
else
|
||||
formspec = formspec .. "false"
|
||||
end
|
||||
end
|
||||
formspec = formspec .. "]checkbox[.25,1.25;quests_config_central_message;" .. S("Central messages") .. ";"
|
||||
if(quests.hud[playername] ~= nil and quests.hud[playername].central_message_enabled) then
|
||||
formspec = formspec .. "true"
|
||||
|
@ -117,31 +147,77 @@ 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;"
|
||||
|
||||
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 restart_remaining = quests.quest_restarting_in(playername, questname)
|
||||
local quest = quests.registered_quests[questname]
|
||||
formspec = formspec .. "image[0,0;0.8,0.8;" .. quest.icon .. "]"
|
||||
if restart_remaining ~= nil then
|
||||
formspec = formspec .. "label[0.8,0;" .. quest.title .. "]" ..
|
||||
"label[0.8,0.3;" .. S("%ds seconds remaining"):format(restart_remaining) .. "]"
|
||||
else
|
||||
formspec = formspec .. "label[0.8,0.1;" .. quest.title .. "]"
|
||||
end
|
||||
|
||||
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 = nil
|
||||
if quests.active_quests[playername] and quests.active_quests[playername][questname] then
|
||||
plr_task = quests.active_quests[playername][questname][taskname]
|
||||
end
|
||||
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 = ""
|
||||
local suffix = ""
|
||||
if plr_task then
|
||||
if plr_task.finished then
|
||||
color = "#00BB00"
|
||||
end
|
||||
if plr_task.disabled then
|
||||
color = "#AAAAAA"
|
||||
end
|
||||
suffix = " - " .. quests.round(plr_task.value, 2) .. "/" .. task.max
|
||||
end
|
||||
table.insert(taskstringlist, color .. task.title .. suffix)
|
||||
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.") .. "]"
|
||||
formspec = formspec .. "label[0.8,0.1;" .. 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
|
||||
|
||||
-- show the player playername his/her questlog
|
||||
function quests.show_formspec(playername)
|
||||
function quests.show_formspec(playername)
|
||||
minetest.show_formspec(playername, "quests:questlog", quests.create_formspec(playername))
|
||||
end
|
||||
|
||||
|
@ -157,22 +233,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
|
||||
|
@ -182,42 +258,58 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|||
end
|
||||
return
|
||||
end
|
||||
if (fields["quests_questlist"]) then
|
||||
local event = minetest.explode_textlist_event(fields["quests_questlist"])
|
||||
if (event.type == "CHG") then
|
||||
if fields.quests_questlist then
|
||||
local event = minetest.explode_textlist_event(fields.quests_questlist)
|
||||
if event.type == "CHG" then
|
||||
quests.formspec_lists[playername].id = event.index
|
||||
if formname == "quests:questlog" then
|
||||
minetest.show_formspec(playername, "quests:questlog", quests.create_formspec(playername))
|
||||
else
|
||||
unified_inventory.set_inventory_formspec(player, "quests")
|
||||
end
|
||||
end
|
||||
end
|
||||
if (fields["quests_abort"]) then
|
||||
if (quests.formspec_lists[playername].id == nil) then
|
||||
if fields.quests_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:questlog") then
|
||||
quests.abort_quest(playername, quests.formspec_lists[playername].list[quests.formspec_lists[playername].id])
|
||||
if formname == "quests:questlog" then
|
||||
minetest.show_formspec(playername, "quests:questlog", quests.create_formspec(playername))
|
||||
else
|
||||
unified_inventory.set_inventory_formspec(player, "quests")
|
||||
end
|
||||
end
|
||||
if (fields["quests_config"]) then
|
||||
if (formname == "quests:questlog") then
|
||||
if fields.quests_config then
|
||||
if formname == "quests:questlog" then
|
||||
minetest.show_formspec(playername, "quests:config", quests.create_config(playername))
|
||||
else
|
||||
unified_inventory.set_inventory_formspec(player, "quests_config")
|
||||
end
|
||||
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]))
|
||||
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], nil, false))
|
||||
else
|
||||
unified_inventory.set_inventory_formspec(player, "quests_info")
|
||||
end
|
||||
end
|
||||
if fields.quests_show_quest_in_hud ~= nil then
|
||||
local questname = quests.formspec_lists[playername].list[quests.formspec_lists[playername].id]
|
||||
if questname then
|
||||
quests.set_quest_hud_visibility(playername, questname, fields.quests_show_quest_in_hud == "true")
|
||||
if formname == "quests:questlog" then
|
||||
minetest.show_formspec(playername, "quests:questlog", quests.create_formspec(playername))
|
||||
else
|
||||
unified_inventory.set_inventory_formspec(player, "quests")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- config
|
||||
if (fields["quests_config_enable"]) then
|
||||
quests.hud[playername].autohide = false
|
||||
if (fields["quests_config_enable"] == "true") then
|
||||
if (fields["quests_config_enable"] == "true") then
|
||||
quests.show_hud(playername)
|
||||
else
|
||||
quests.hide_hud(playername)
|
||||
|
@ -257,27 +349,38 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|||
if (fields["quests_config_return"]) then
|
||||
if (formname == "quests:config") then
|
||||
minetest.show_formspec(playername, "quests:questlog", quests.create_formspec(playername))
|
||||
else
|
||||
else
|
||||
unified_inventory.set_inventory_formspec(player, "quests")
|
||||
end
|
||||
end
|
||||
|
||||
-- info
|
||||
if (fields["quests_info_abort"]) then
|
||||
if (quests.formspec_lists[playername].id == nil) 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:info" 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
|
||||
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
|
||||
else
|
||||
unified_inventory.set_inventory_formspec(player, "quests")
|
||||
end
|
||||
end
|
||||
|
|
321
mods/quests/hud.lua
Executable file → Normal file
|
@ -1,3 +1,6 @@
|
|||
--- Quests HUD.
|
||||
-- @module hud
|
||||
|
||||
-- Boilerplate to support localized strings if intllib mod is installed.
|
||||
local S
|
||||
if minetest.get_modpath("intllib") then
|
||||
|
@ -13,38 +16,39 @@ local hud_config = { position = {x = 1, y = 0.2},
|
|||
offset = { x = -200, y = 0},
|
||||
number = quests.colors.new }
|
||||
|
||||
-- call this function to enable the HUD for the player that shows his quests
|
||||
-- the HUD can only show up to show_max quests
|
||||
--- Show quests HUD to player.
|
||||
-- The HUD can only show up to `show_max` quests
|
||||
-- @param playername Player whose quests HUD must be shown
|
||||
-- @param autohide Whether to automatically hide the HUD once it's empty
|
||||
function quests.show_hud(playername, autohide)
|
||||
if (quests.hud[playername] == nil) then
|
||||
quests.hud[playername] = { autohide = autohide}
|
||||
if quests.hud[playername] == nil then
|
||||
quests.hud[playername] = { autohide = autohide }
|
||||
end
|
||||
if (quests.hud[playername].list ~= nil) then
|
||||
if quests.hud[playername].list ~= nil then
|
||||
return
|
||||
end
|
||||
local hud = {
|
||||
local player = minetest.get_player_by_name(playername)
|
||||
if player == nil then
|
||||
return false
|
||||
end
|
||||
quests.hud[playername].header = 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},
|
||||
offset = {x = hud_config.offset.x, y = hud_config.offset.y - 20},
|
||||
number = hud_config.number,
|
||||
text = S("Quests:") }
|
||||
text = S("Quests:")
|
||||
})
|
||||
|
||||
|
||||
|
||||
local player = minetest.get_player_by_name(playername)
|
||||
if (player == nil) then
|
||||
return false
|
||||
end
|
||||
quests.hud[playername].list = {}
|
||||
table.insert(quests.hud[playername].list, { value=0, id=player:hud_add(hud) })
|
||||
minetest.after(0, quests.update_hud, playername)
|
||||
end
|
||||
|
||||
-- call this method to hide the hud
|
||||
--- Hide quests HUD to player.
|
||||
-- @param playername Player whose quests HUD must be hidden
|
||||
function quests.hide_hud(playername)
|
||||
local player = minetest.get_player_by_name(playername)
|
||||
if (player == nil or quests.hud[playername] == nil or quests.hud[playername].list == nil) then
|
||||
if player == nil or quests.hud[playername] == nil or quests.hud[playername].list == nil then
|
||||
return
|
||||
end
|
||||
for _,quest in pairs(quests.hud[playername].list) do
|
||||
|
@ -60,136 +64,203 @@ function quests.hide_hud(playername)
|
|||
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
|
||||
quest_string = quest_string .. "\n ("..quests.round(quest.value, 2).."/"..quests.registered_quests[questname].max..")"
|
||||
end
|
||||
return quest_string
|
||||
local function get_quest_hud_string(title, value, max)
|
||||
return title .. "\n ("..quests.round(value, 2).."/"..max..")"
|
||||
end
|
||||
|
||||
local function get_hud_list(playername)
|
||||
local deftable = {}
|
||||
local counter = 0
|
||||
for questname, plr_quest in quests.sorted_pairs(quests.active_quests[playername]) do
|
||||
local quest = quests.registered_quests[questname]
|
||||
local hide_from_hud
|
||||
if quests.info_quests[playername] and quests.info_quests[playername][questname] then
|
||||
hide_from_hud = quests.info_quests[playername][questname].hide_from_hud
|
||||
else
|
||||
hide_from_hud = false
|
||||
end
|
||||
if quest and not hide_from_hud then -- Quest might have been deleted
|
||||
local function get_table(name, value, max)
|
||||
local def = {
|
||||
text = {
|
||||
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 = name
|
||||
}
|
||||
}
|
||||
if plr_quest.finished then
|
||||
if quests.failed_quests[playername] and quests.failed_quests[playername][questname] then
|
||||
def.text.number = quests.colors.failed
|
||||
else
|
||||
def.text.number = quests.colors.success
|
||||
end
|
||||
else
|
||||
def.text.number = hud_config.number
|
||||
end
|
||||
if value and max then
|
||||
def.bar = {
|
||||
hud_elem_type = "image",
|
||||
scale = { x = math.floor(20 * value / 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"
|
||||
}
|
||||
def.background = {
|
||||
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"
|
||||
}
|
||||
end
|
||||
return def
|
||||
end
|
||||
if quest.simple then
|
||||
deftable[questname] = get_table(get_quest_hud_string(quest.title, plr_quest.value, quest.max), plr_quest.value, quest.max)
|
||||
counter = counter + 1
|
||||
else
|
||||
deftable[questname] = get_table(quest.title, plr_quest.value, quest.max)
|
||||
counter = counter + 0.5
|
||||
for taskname, task in pairs(quest.tasks) do
|
||||
local plr_task = quests.active_quests[playername][questname][taskname]
|
||||
if plr_task.visible and not plr_task.disabled and not plr_task.finished then
|
||||
deftable[questname .. "#" .. taskname] = get_table("- " .. get_quest_hud_string(task.title, plr_task.value, task.max), plr_task.value, task.max)
|
||||
counter = counter + 1
|
||||
if counter >= show_max + 1 then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
counter = counter + 0.1
|
||||
end
|
||||
if counter >= show_max + 1 then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
return deftable
|
||||
end
|
||||
|
||||
local DELETED = {}
|
||||
-- only for internal use
|
||||
-- updates the hud
|
||||
function quests.update_hud(playername)
|
||||
if (quests.hud[playername] == nil or quests.active_quests[playername] == nil) then
|
||||
if quests.hud[playername] == nil or quests.active_quests[playername] == nil then
|
||||
return
|
||||
end
|
||||
if (quests.hud[playername].list == nil) then
|
||||
if (quests.hud[playername].autohide and next(quests.active_quests[playername]) ~= nil) then
|
||||
if quests.hud[playername].list == nil then
|
||||
if quests.hud[playername].autohide and next(quests.active_quests[playername]) ~= nil then
|
||||
quests.show_hud(playername)
|
||||
end
|
||||
return
|
||||
end
|
||||
local player = minetest.get_player_by_name(playername)
|
||||
if (player == nil) then
|
||||
if player == nil then
|
||||
return
|
||||
end
|
||||
|
||||
-- Check for changes in the hud
|
||||
local i = 2 -- the first element is the title
|
||||
local change = false
|
||||
local visible = {}
|
||||
local remove = {}
|
||||
for j,hud_element in ipairs(quests.hud[playername].list) do
|
||||
if (hud_element.name ~= nil) then
|
||||
if (quests.active_quests[playername][hud_element.name] ~= nil) then
|
||||
if (hud_element.value ~= quests.active_quests[playername][hud_element.name].value) then
|
||||
hud_element.value = quests.active_quests[playername][hud_element.name].value
|
||||
player:hud_change(hud_element.id, "text", get_quest_hud_string(hud_element.name, quests.active_quests[playername][hud_element.name]))
|
||||
if (hud_element.id_bar ~= nil) then
|
||||
player:hud_change(hud_element.id_bar, "scale",
|
||||
{ x = math.floor(20 * hud_element.value / quests.registered_quests[hud_element.name].max),
|
||||
y = 1})
|
||||
end
|
||||
end
|
||||
if (i ~= j) then
|
||||
player:hud_change(hud_element.id, "offset", { x= hud_config.offset.x, y=hud_config.offset.y + (i-1) *40})
|
||||
if (hud_element.id_background ~= nil) then
|
||||
player:hud_change(hud_element.id_background, "offset", { x= hud_config.offset.x, y=hud_config.offset.y + (i-1) *40 + 22})
|
||||
end
|
||||
if (hud_element.id_bar ~= nil) then
|
||||
player:hud_change(hud_element.id_bar, "offset", { x= hud_config.offset.x + 2, y=hud_config.offset.y + (i-1) *40 + 24})
|
||||
end
|
||||
|
||||
end
|
||||
visible[hud_element.name] = true
|
||||
i = i + 1
|
||||
else
|
||||
player:hud_remove(hud_element.id)
|
||||
if (hud_element.id_background ~= nil) then
|
||||
player:hud_remove(hud_element.id_background)
|
||||
end
|
||||
if (hud_element.id_bar ~= nil) then
|
||||
player:hud_remove(hud_element.id_bar)
|
||||
end
|
||||
table.insert(remove, j)
|
||||
end
|
||||
end
|
||||
end
|
||||
--remove ended quests
|
||||
if (remove[1] ~= nil) then
|
||||
for _,j in ipairs(remove) do
|
||||
table.remove(quests.hud[playername].list, j)
|
||||
i = i - 1
|
||||
end
|
||||
end
|
||||
|
||||
if (i >= show_max + 1) then
|
||||
return
|
||||
end
|
||||
-- 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
|
||||
|
||||
table.insert(quests.hud[playername].list, { name = questname,
|
||||
id = id,
|
||||
id_background = id_background,
|
||||
id_bar = id_bar,
|
||||
value = questspecs.value })
|
||||
counter = counter + 1
|
||||
if (counter >= show_max + 1) then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
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"))
|
||||
if quests.hud[playername].autohide then
|
||||
if next(quests.active_quests[playername]) == nil then
|
||||
player:hud_change(quests.hud[playername].header, "text", S("No more Quests"))
|
||||
minetest.after(3, function(playername)
|
||||
if (next(quests.active_quests[playername]) ~= nil) then
|
||||
player:hud_change(quests.hud[playername].list[1].id, "text", S("Quests:"))
|
||||
if next(quests.active_quests[playername]) ~= nil then
|
||||
player:hud_change(quests.hud[playername].header, "text", S("Quests:"))
|
||||
quests.update_hud(playername)
|
||||
else
|
||||
quests.hide_hud(playername)
|
||||
end
|
||||
end, playername)
|
||||
end
|
||||
end
|
||||
|
||||
-- Check for changes in the hud
|
||||
local function table_diff(tab1, tab2)
|
||||
local result_tab
|
||||
for k, v in pairs(tab2) do
|
||||
if not tab1[k] or tab1[k] ~= v then
|
||||
if type(tab1[k]) == "table" and type(v) == "table" then
|
||||
local diff = table_diff(tab1[k], v)
|
||||
if diff ~= nil then
|
||||
if not result_tab then
|
||||
result_tab = {}
|
||||
end
|
||||
result_tab[k] = diff
|
||||
end
|
||||
else
|
||||
if not result_tab then
|
||||
result_tab = {}
|
||||
end
|
||||
result_tab[k] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
for k, _ in pairs(tab1) do
|
||||
if tab2[k] == nil then
|
||||
if not result_tab then
|
||||
result_tab = {}
|
||||
end
|
||||
result_tab[k] = DELETED
|
||||
end
|
||||
end
|
||||
return result_tab
|
||||
end
|
||||
-- Merge `from` into table `into`
|
||||
local function table_merge(from, into)
|
||||
for k, v in pairs(from) do
|
||||
if type(v) == "table" and type(into[k]) == "table" then
|
||||
table_merge(v, into[k])
|
||||
else
|
||||
into[k] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
local old_hud = quests.hud[playername].list
|
||||
local new_hud = get_hud_list(playername)
|
||||
local diff = table_diff(old_hud, new_hud)
|
||||
-- Copy the HUD IDs from the old table to the new one, to avoid loosing them
|
||||
for questname, hud_elms in pairs(old_hud) do
|
||||
for elm_name, elm_def in pairs(hud_elms) do
|
||||
if new_hud[questname] and new_hud[questname][elm_name] then
|
||||
new_hud[questname][elm_name].id = elm_def.id
|
||||
end
|
||||
end
|
||||
end
|
||||
if diff ~= nil then
|
||||
for questname, hud_elms in pairs(diff) do
|
||||
if hud_elms == DELETED then
|
||||
for elm_name, elm_def in pairs(old_hud[questname]) do
|
||||
player:hud_remove(elm_def.id)
|
||||
end
|
||||
else
|
||||
for elm_name, elm_def in pairs(hud_elms) do
|
||||
if not old_hud[questname] or not old_hud[questname][elm_name] or not old_hud[questname][elm_name].id then
|
||||
new_hud[questname][elm_name].id = player:hud_add(elm_def)
|
||||
else
|
||||
for elm_prop_name, elm_prop in pairs(elm_def) do
|
||||
if elm_prop_name ~= "id" then
|
||||
if type(elm_prop) == "table" then
|
||||
-- For table-based properties, MT expects a full table to be specified,
|
||||
-- so we must create a merged table. Just merge the changes with the old
|
||||
-- HUD table, since it will disappear.
|
||||
table_merge(elm_prop, old_hud[questname][elm_name][elm_prop_name])
|
||||
else
|
||||
old_hud[questname][elm_name][elm_prop_name] = elm_prop
|
||||
end
|
||||
player:hud_change(new_hud[questname][elm_name].id, elm_prop_name, old_hud[questname][elm_name][elm_prop_name])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
quests.hud[playername].list = new_hud
|
||||
end
|
||||
|
||||
|
||||
|
|
37
mods/quests/init.lua
Executable file → Normal file
|
@ -1,6 +1,5 @@
|
|||
-- reading previous quests
|
||||
local file = io.open(minetest.get_worldpath().."/quests", "r")
|
||||
quests = {}
|
||||
if file then
|
||||
minetest.log("action", "Reading quests...")
|
||||
quests = minetest.deserialize(file:read("*all"))
|
||||
|
@ -11,6 +10,7 @@ quests.registered_quests = {}
|
|||
quests.active_quests = quests.active_quests or {}
|
||||
quests.successfull_quests = quests.successfull_quests or {}
|
||||
quests.failed_quests = quests.failed_quests or {}
|
||||
quests.info_quests = quests.info_quests or {}
|
||||
quests.hud = quests.hud or {}
|
||||
for idx,_ in pairs(quests.hud) do
|
||||
quests.hud[idx].first = true
|
||||
|
@ -18,7 +18,7 @@ end
|
|||
|
||||
|
||||
quests.formspec_lists = {}
|
||||
function quests.round(num, n)
|
||||
function quests.round(num, n)
|
||||
local mult = 10^(n or 0)
|
||||
return math.floor(num * mult + .5) / mult
|
||||
end
|
||||
|
@ -26,12 +26,26 @@ end
|
|||
quests.colors = {
|
||||
new = "0xAAAA00",
|
||||
success = "0x00AD00",
|
||||
failed = "0xAD0000"
|
||||
failed = "0xAD0000",
|
||||
}
|
||||
|
||||
|
||||
local MP = minetest.get_modpath("quests")
|
||||
|
||||
function quests.sorted_pairs(t)
|
||||
local a = {}
|
||||
for n in pairs(t) do table.insert(a, n) end
|
||||
table.sort(a)
|
||||
local i = 0 -- iterator variable
|
||||
local iter = function () -- iterator function
|
||||
i = i + 1
|
||||
if a[i] == nil then return nil
|
||||
else return a[i], t[a[i]]
|
||||
end
|
||||
end
|
||||
return iter
|
||||
end
|
||||
|
||||
dofile(MP .. "/central_message.lua")
|
||||
dofile(MP .. "/core.lua")
|
||||
dofile(MP .. "/hud.lua")
|
||||
|
@ -47,21 +61,24 @@ end
|
|||
|
||||
-- write the quests to file
|
||||
minetest.register_on_shutdown(function()
|
||||
minetest.log("action", "Writing quests to file")
|
||||
for playername, quest in pairs(quests.active_quests) do
|
||||
for questname, questspecs in pairs(quest) do
|
||||
if (questspecs.finished) then
|
||||
if questspecs.finished then
|
||||
quests.active_quests[playername][questname] = nil -- make sure no finished quests are saved as unfinished
|
||||
end
|
||||
end
|
||||
end
|
||||
local file = io.open(minetest.get_worldpath().."/quests", "w")
|
||||
if (file) then
|
||||
file:write(minetest.serialize({ --registered_quests = quests.registered_quests,
|
||||
local file, err = io.open(minetest.get_worldpath().."/quests", "w")
|
||||
if file then
|
||||
file:write(minetest.serialize({
|
||||
active_quests = quests.active_quests,
|
||||
successfull_quests = quests.successfull_quests,
|
||||
failed_quests = quests.failed_quests,
|
||||
hud = quests.hud}))
|
||||
failed_quests = quests.failed_quests,
|
||||
info_quests = quests.info_quests,
|
||||
hud = quests.hud}))
|
||||
file:close()
|
||||
minetest.log("action", "Wrote quests to file")
|
||||
else
|
||||
minetest.log("action", "Failed writing quests to file: open failed: " .. err)
|
||||
end
|
||||
end)
|
||||
|
|
2
mods/quests/inventory_plus.lua
Executable file → Normal file
|
@ -1,4 +1,4 @@
|
|||
minetest.register_on_joinplayer(function(player)
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
inventory_plus.register_button(player, "quests")
|
||||
end)
|
||||
|
||||
|
|
0
mods/quests/locale/de.txt
Executable file → Normal file
0
mods/quests/locale/template.txt
Executable file → Normal file
0
mods/quests/sounds/quests_failed.ogg
Executable file → Normal file
0
mods/quests/sounds/quests_new.ogg
Executable file → Normal file
0
mods/quests/sounds/quests_success.ogg
Executable file → Normal file
BIN
mods/quests/textures/inventory_plus_quests.png
Executable file → Normal file
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 3.3 KiB |
BIN
mods/quests/textures/quests_default_quest_icon.png
Normal file
After Width: | Height: | Size: 873 B |
BIN
mods/quests/textures/quests_questbar.png
Executable file → Normal file
Before Width: | Height: | Size: 82 B After Width: | Height: | Size: 155 B |
BIN
mods/quests/textures/quests_questbar_background.png
Executable file → Normal file
Before Width: | Height: | Size: 220 B After Width: | Height: | Size: 337 B |
9
mods/quests/unified_inventory.lua
Executable file → Normal file
|
@ -8,7 +8,7 @@ unified_inventory.register_button("quests", {
|
|||
})
|
||||
|
||||
unified_inventory.register_page("quests", {
|
||||
get_formspec = function(player)
|
||||
get_formspec = function(player)
|
||||
local playername = player:get_player_name()
|
||||
local formspec = quests.create_formspec(playername, "1", true)
|
||||
return {formspec = formspec, draw_inventory=false}
|
||||
|
@ -16,7 +16,7 @@ unified_inventory.register_page("quests", {
|
|||
})
|
||||
|
||||
unified_inventory.register_page("quests_successfull", {
|
||||
get_formspec = function(player)
|
||||
get_formspec = function(player)
|
||||
local playername = player:get_player_name()
|
||||
local formspec = quests.create_formspec(playername, "2", true)
|
||||
return {formspec = formspec, draw_inventory=false}
|
||||
|
@ -24,7 +24,7 @@ unified_inventory.register_page("quests_successfull", {
|
|||
})
|
||||
|
||||
unified_inventory.register_page("quests_failed", {
|
||||
get_formspec = function(player)
|
||||
get_formspec = function(player)
|
||||
local playername = player:get_player_name()
|
||||
local formspec = quests.create_formspec(playername, "3", true)
|
||||
return {formspec = formspec, draw_inventory=false}
|
||||
|
@ -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
|
||||
})
|
||||
|
|