1
0
mirror of https://github.com/sys4-fr/server-nalc.git synced 2024-12-25 02:00:37 +01:00

Add quest framework and basic periodic quest support

This commit is contained in:
Wouters Dorian 2015-07-22 00:04:54 +02:00
parent 873e874563
commit 69ce8e8266
23 changed files with 1090 additions and 0 deletions

5
mods/mff/README.md Normal file
View File

@ -0,0 +1,5 @@
* MFF-specific mods folder
** Code convention
All MFF mods must be in the `mff` global table, and thus shall depend on the mff_core mod first defining it.
The reason for this is to allow introspection using mff_introspect to track bugs at runtime, and more generally to define a code namespace.

View File

@ -0,0 +1,2 @@
mff = {}
mff.core = {}

View File

View File

@ -0,0 +1,3 @@
mff_core
default
quests

View File

@ -0,0 +1,119 @@
--- 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.quests.quests = {
testdiggydiggyhole = {
title = "Dig 10 nodes",
max = 10,
desc = "As long as you can not dig, you are not a real miner.",
periodicity = 10,
objective = {
dig = {"default:stone"}
}
}
}
mff.quests.quest_status = {}
function table.contains(table, element)
for _, value in pairs(table) do
if value == element then
return true
end
end
return false
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
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
})
end
-- For quests where you have to dig something, the updates happen here
minetest.register_on_dignode(function(pos, oldnode, digger)
local qstatus = mff.quests.quest_status[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)
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)

0
mods/mff/modpack.txt Normal file
View File

82
mods/quests/README Normal file
View File

@ -0,0 +1,82 @@
quests 1.1
quests is a simple quest framework for minetest that lets you define your own quests and handels the representation.
Dependencies:
intllib (optional)
unified_inventory or inventory_plus (optional)
central_message (optional)
License: WTFPL
Sounds: CC-BY
Textures: CC-BY
-------------------------------------------------------------------------------
You can see a full list of your active quests with the chatcommand /quests
API:
quests.register_quest(questname,quest)
-- 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
quests.start_quest(playername, questname)
-- 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
quests.update_quest(playername, questname, value)
-- 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
quests.accept_quest(playername, questname)
-- When the mod handels 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
quests.abort_quest(playername, questname)
-- 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
quests.show_hud(playername)
-- shows the hud to player playername
quests.hide_hud(playername)
-- hides the hud for player playername
quests.show_formspec(playername)
-- shows the player playername his/her questlog
quests.get_metadata(playername, questname)
-- get metadata of the quest if the quest exists, else return nil
quests.set_metadata(playername, questname, metadata)
-- set metadata of the quest

View File

@ -0,0 +1,12 @@
if (cmsg) then
function quests.show_message(t, playername, text)
if (quests.hud[playername].central_message_enabled) then
local player = minetest.get_player_by_name(playername)
cmsg.push_message_player(player, text, quests.colors[t])
minetest.sound_play("quests_" .. t, {to_player = playername})
end
end
else
function quests.show_message(...)
end
end

184
mods/quests/core.lua Normal file
View File

@ -0,0 +1,184 @@
-- Boilerplate to support localized strings if intllib mod is installed.
local S
if minetest.get_modpath("intllib") then
S = intllib.Getter()
else
-- If you don't use insertions (@1, @2, etc) you can use this:
S = function(s) return s end
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
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
function quests.start_quest(playername, questname, metadata)
if (quests.registered_quests[questname] == nil) then
return false
end
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
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)
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
function quests.update_quest(playername, questname, value)
if (quests.active_quests[playername] == nil) then
quests.active_quests[playername] = {}
end
if (quests.active_quests[playername][questname] == nil) then
return false -- there is no such quest
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
quests.accept_quest(playername,questname)
quests.update_hud(playername)
end
return true -- the quest is finished
end
quests.update_hud(playername)
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,
-- 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
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
quests.successfull_quests[playername] = {}
end
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
local player = minetest.get_player_by_name(playername)
player:hud_change(quest.id, "number", quests.colors.success)
end
end
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
quests.update_hud(playername)
end, playername, questname)
return true -- the quest is finished, the mod can give a reward
end
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
function quests.abort_quest(playername, questname)
if (questname == nil) then
return false
end
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
quests.failed_quests[playername][questname].count = quests.failed_quests[playername][questname].count + 1
else
quests.failed_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
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)
minetest.after(3, function(playername, questname)
quests.active_quests[playername][questname] = nil
quests.update_hud(playername)
end, playername, questname)
end
-- get metadata of the quest if the quest exists, else return nil
function quests.get_metadata(playername, questname)
if (quests.active_quests[playername] == nil or quests.active_quests[playername][questname] == nil) then
return nil
end
return quests.active_quests[playername][questname].metadata
end
-- set metadata of the quest
function quests.set_metadata(playername, questname, metadata)
if (quests.active_quests[playername] == nil or quests.active_quests[playername][questname] == nil) then
return
end
quests.active_quests[playername][questname].metadata = metadata
end

4
mods/quests/depends.txt Normal file
View File

@ -0,0 +1,4 @@
intllib?
unified_inventory?
inventory_plus?
central_message?

284
mods/quests/formspecs.lua Normal file
View File

@ -0,0 +1,284 @@
-- Boilerplate to support localized strings if intllib mod is installed.
local S
if minetest.get_modpath("intllib") then
S = intllib.Getter()
else
-- If you don't use insertions (@1, @2, etc) you can use this:
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].list = {}
tab = tab or quests.formspec_lists[playername].tab or "1"
if (tab == "1") then
questlist = quests.active_quests[playername] or {}
elseif (tab == "2") then
questlist = quests.successfull_quests[playername] or {}
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"] .. ")"
end
table.insert(queststringlist, queststring)
table.insert(quests.formspec_lists[playername].list, questname)
no_quests = false
end
end
local formspec = ""
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
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
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") .. "]"..
"button[.25,8;3,.7;quests_info;" .. S("Info") .. "]"..
"button_exit[3.75,8;3,.7;quests_exit;" .. S("Exit") .. "]"
return formspec
end
-- construct the configuration
function quests.create_config(playername, integrated)
local formspec = ""
if (not integrated) then
formspec = formspec .. "size[7,3]"
end
formspec = formspec .. "checkbox[.25,.25;quests_config_enable;" .. S("Enable HUD") .. ";"
if(quests.hud[playername] ~= nil and quests.hud[playername].list ~= nil) then
formspec = formspec .. "true"
else
formspec = formspec .. "false"
end
formspec = formspec .. "]checkbox[.25,.75;quests_config_autohide;" .. S("Autohide HUD") .. ";"
if(quests.hud[playername] ~= nil and quests.hud[playername].autohide) then
formspec = formspec .. "true"
else
formspec = formspec .. "false"
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"
else
formspec = formspec .. "false"
end
formspec = formspec .. "]" ..
"button[.25,2.25;3,.7;quests_config_return;" .. S("Return") .. "]"
return formspec
end
local function wordwrap(text, linelength)
local lines = text:split("\n")
local ret = ""
for i = 1,#lines do
local line = lines[i]
while (#line > linelength) do
local split = false
local j = linelength
while (not split) do
if (string.sub(line, j, j) == " ") then
split = true
ret = ret .. string.sub(line, 1, j) .. "\n"
line = string.sub(line, j + 1)
end
if (j <= 1) then
break
end
j = j - 1
end
if (not split) then
ret = ret .. string.sub(line, 1, linelength) .. "\n"
line = string.sub(line, linelength);
end
end
ret = ret .. line .. "\n"
end
return ret
end
-- construct the info formspec
function quests.create_info(playername, questname, integrated)
local formspec = ""
if (not integrated) then
formspec = formspec .. "size[9,6.5]"
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 (quests.formspec_lists[playername].tab == "1") then
formspec = formspec .. "button[.5,6;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") .. "]"
return formspec
end
-- show the player playername his/her questlog
function quests.show_formspec(playername)
minetest.show_formspec(playername, "quests:questlog", quests.create_formspec(playername))
end
-- chatcommand to see a full list of quests:
minetest.register_chatcommand("quests", {
params = "",
description = S("Show all open quests"),
func = function(name, param)
minetest.show_formspec(name, "quests:questlog", quests.create_formspec(name))
return true
end
})
-- Handle the return fields of the questlog
minetest.register_on_player_receive_fields(function(player, formname, fields)
if (player == nil) then
return
end
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"]))
else
if (fields["quests_header"] == "1") then
unified_inventory.set_inventory_formspec(player, "quests")
elseif (fields["quests_header"] == "2") then
unified_inventory.set_inventory_formspec(player, "quests_successfull")
return
else
unified_inventory.set_inventory_formspec(player, "quests_failed")
return
end
end
return
end
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
end
end
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
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
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]))
else
unified_inventory.set_inventory_formspec(player, "quests_info")
end
end
-- config
if (fields["quests_config_enable"]) then
quests.hud[playername].autohide = false
if (fields["quests_config_enable"] == "true") then
quests.show_hud(playername)
else
quests.hide_hud(playername)
end
if (formname == "quests:config") 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_config_autohide"]) then
if (fields["quests_config_autohide"] == "true") then
quests.hud[playername].autohide = true
quests.update_hud(playername)
else
quests.hud[playername].autohide = false
end
if (formname == "quests:config") 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_config_central_message"]) then
if (fields["quests_config_central_message"] == "true") then
quests.hud[playername].central_message_enabled = true
else
quests.hud[playername].central_message_enabled = false
end
if (formname == "quests:config") 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_config_return"]) then
if (formname == "quests:config") then
minetest.show_formspec(playername, "quests:questlog", quests.create_formspec(playername))
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
return
end
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
minetest.show_formspec(playername, "quests:questlog", quests.create_formspec(playername))
else
unified_inventory.set_inventory_formspec(player, "quests")
end
end
end)

233
mods/quests/hud.lua Normal file
View File

@ -0,0 +1,233 @@
-- Boilerplate to support localized strings if intllib mod is installed.
local S
if minetest.get_modpath("intllib") then
S = intllib.Getter()
else
-- If you don't use insertions (@1, @2, etc) you can use this:
S = function(s) return s end
end
local show_max = 10 -- the maximum visible quests.
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
function quests.show_hud(playername, autohide)
if (quests.hud[playername] == nil) then
quests.hud[playername] = { autohide = autohide}
end
if (quests.hud[playername].list ~= nil) then
return
end
local hud = {
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},
number = hud_config.number,
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
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
return
end
for _,quest in pairs(quests.hud[playername].list) do
player:hud_remove(quest.id)
if (quest.id_background ~= nil) then
player:hud_remove(quest.id_background)
end
if (quest.id_bar ~= nil) then
player:hud_remove(quest.id_bar)
end
end
quests.hud[playername].list = nil
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
end
-- only for internal use
-- updates the hud
function quests.update_hud(playername)
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
quests.show_hud(playername)
end
return
end
local player = minetest.get_player_by_name(playername)
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"))
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:"))
else
quests.hide_hud(playername)
end
end, playername)
end
end
end
-- show the HUDs
--for playername,id in pairs(quests.hud) do
-- if (id ~= nil) then
-- quests.hud[playername] = nil
-- minetest.after(10, function(playername)
-- quests.show_hud(playername)
-- quests.update_hud(playername)
-- end, playername)
-- end
--end
minetest.register_on_joinplayer(function(player)
local playername = player:get_player_name()
if (quests.hud[playername] ~= nil) then
if (not(quests.hud[playername].first)) then
return
end
local list = quests.hud[playername].list
local autohide = quests.hud[playername].autohide
local central_message_enabled = quests.hud[playername].central_message_enabled
quests.hud[playername] = {
autohide = autohide,
central_message_enabled = central_message_enabled
}
if (list ~= nil) then
minetest.after(1, function(playername)
quests.show_hud(playername)
end, playername)
end
else -- new player
quests.hud[playername] = {
autohide = true,
central_message_enabled = true
}
quests.active_quests[playername] = {}
end
end)

66
mods/quests/init.lua Normal file
View File

@ -0,0 +1,66 @@
-- reading previous quests
local file = io.open(minetest.get_worldpath().."/quests", "r")
if file then
minetest.log("action", "Reading quests...")
quests = minetest.deserialize(file:read("*all"))
file:close()
end
quests = quests or {}
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.hud = quests.hud or {}
for idx,_ in pairs(quests.hud) do
quests.hud[idx].first = true
end
quests.formspec_lists = {}
function quests.round(num, n)
local mult = 10^(n or 0)
return math.floor(num * mult + .5) / mult
end
quests.colors = {
new = "0xAAAA00",
success = "0x00AD00",
failed = "0xAD0000"
}
local MP = minetest.get_modpath("quests")
dofile(MP .. "/central_message.lua")
dofile(MP .. "/core.lua")
dofile(MP .. "/hud.lua")
dofile(MP .. "/formspecs.lua")
-- support for unified_inventory
if (minetest.get_modpath("unified_inventory") ~= nil) then
dofile(minetest.get_modpath("quests") .. "/unified_inventory.lua")
elseif (minetest.get_modpath("inventory_plus") ~= nil) then
dofile(minetest.get_modpath("quests") .. "/inventory_plus.lua")
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
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,
active_quests = quests.active_quests,
successfull_quests = quests.successfull_quests,
failed_quests = quests.failed_quests,
hud = quests.hud}))
file:close()
end
end)

View File

@ -0,0 +1,9 @@
minetest.register_on_joinplayer(function(player)
inventory_plus.register_button(player, "quests")
end)
minetest.register_on_player_receive_fields(function(player, formname, fields)
if (fields.quests) then
quests.show_formspec(player:get_player_name())
end
end)

20
mods/quests/locale/de.txt Normal file
View File

@ -0,0 +1,20 @@
missing description = fehlende Beschreibung
missing title = fehlender Titel
Quests: = Quests:
No more Quests = Keine weiteren Quests
Abort quest = Quest abbrechen
Configure = Konfigurieren
Enable HUD = HUD einschalten
Autohide HUD = HUD automatisch verstecken
Exit = Verlassen
Failed quests = Gescheiterte Quests
Finished quests = Beendete Quests
Info = Info
No quest specified. = Keine Quest ausgewählt.
Open quests = Offene Quests
Return = Zurück
Show all open quests = Zeige alle offenen Quests
There are no quests in this category. = Es gibt keine Quests in dieser Kategorie.
New quest: = Neue Quest:
Quest completed: = Quest beendet:
Quest failed: = Quest gescheitert:

View File

@ -0,0 +1,20 @@
missing description =
missing title =
Quests: =
No more Quests =
Abort quest =
Configure =
Enable HUD =
Autohide HUD =
Exit =
Failed quests =
Finished quests =
Info =
No quest specified. =
Open quests =
Return =
Show all open quests =
There are no quests in this category. =
New quest: =
Quest completed: =
Quest failed: =

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

View File

@ -0,0 +1,47 @@
unified_inventory.register_button("quests", {
type = "image",
image = "inventory_plus_quests.png",
tooltip = "Show the questlog",
-- action = function(player)
-- quests.show_formspec(player:get_player_name())
-- end
})
unified_inventory.register_page("quests", {
get_formspec = function(player)
local playername = player:get_player_name()
local formspec = quests.create_formspec(playername, "1", true)
return {formspec = formspec, draw_inventory=false}
end
})
unified_inventory.register_page("quests_successfull", {
get_formspec = function(player)
local playername = player:get_player_name()
local formspec = quests.create_formspec(playername, "2", true)
return {formspec = formspec, draw_inventory=false}
end
})
unified_inventory.register_page("quests_failed", {
get_formspec = function(player)
local playername = player:get_player_name()
local formspec = quests.create_formspec(playername, "3", true)
return {formspec = formspec, draw_inventory=false}
end
})
unified_inventory.register_page("quests_config", {
get_formspec = function(player)
local playername = player:get_player_name()
local formspec = quests.create_config(playername, true)
return {formspec = formspec, draw_inventory = false }
end
})
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)
return {formspec = formspec, draw_inventory = false }
end
})