added basic quest management formspec

This commit is contained in:
Sokomine 2022-11-14 18:18:33 +01:00
parent 3f458bf448
commit 8b24e9b52f
5 changed files with 285 additions and 4 deletions

79
fs_manage_quests.lua Normal file
View File

@ -0,0 +1,79 @@
-- helper functions for yl_speak_up.input_fs_manage_quests(..)
-- returns the index of the new quest
yl_speak_up.input_fs_manage_quests_add_new_entry = function(pname, entry_name)
local res = yl_speak_up.add_quest(pname, entry_name,
"Name of your quest",
"Enter a longer description here for describing the quest "..
"to players who search for one.",
"Enter a short description here describing what the quest is about.",
"Room for comments/notes")
-- TODO: might make sense to show the error message somewhere
if(res ~= "OK") then
return -1
end
local quest_list = yl_speak_up.get_sorted_quest_list(pname)
return table.indexof(quest_list, entry_name)
end
-- helper functions for yl_speak_up.input_fs_manage_quests(..)
-- returns a text describing if deleting the quest worked
yl_speak_up.input_fs_manage_quests_del_old_entry = function(pname, entry_name)
return "NOT IMPLEMENTED YET"
-- delete (empty) variable
-- return yl_speak_up.del_quest_variable(pname, entry_name, nil)
end
-- helper functions for yl_speak_up.input_fs_manage_quests(..)
-- implements all the functions that are specific to managing quests and not part of
-- general item management
yl_speak_up.input_fs_manage_quests_check_fields = function(player, formname, fields, quest_name, list_of_entries)
local pname = player:get_player_name()
if(not(quest_name)) then
quest_name = ""
end
-- this function didn't have anything to do
return "NOTHING FOUND"
end
-- makes use of yl_speak_up.input_fs_manage_general and is thus pretty short
yl_speak_up.input_fs_manage_quests = function(player, formname, fields)
local pname = player:get_player_name()
local quest_list = yl_speak_up.get_sorted_quest_list(pname)
local res = yl_speak_up.input_fs_manage_general(player, formname, fields,
-- what_is_the_list_about, min_length, max_length, function_add_new_entry,
"quest", 2, 80,
yl_speak_up.input_fs_manage_quests_add_new_entry,
quest_list,
yl_speak_up.input_fs_manage_quests_del_old_entry,
yl_speak_up.input_fs_manage_quests_check_fields)
return true
end
yl_speak_up.get_fs_manage_quests = function(player, param)
local pname = player:get_player_name()
local quest_list = yl_speak_up.get_sorted_quest_list(pname)
local formspec = {}
table.insert(formspec, "size[18,12]"..
"label[0.2,1.2;A quest is a linear sequence of quest steps. Quests can "..
"depend on and influence other quests.\n"..
"Progress for each player is stored in a variable. The name of "..
"that variable cannot be changed after creation.]")
local selected = yl_speak_up.get_fs_manage_general(player, param,
formspec, quest_list,
"Create quest",
"Create a new varialbe with the name\n"..
"you entered in the field to the left.",
"quest",
"Enter the name of the new quest you want to create.\n"..
"You can't change this name afterwards. But you *can*\n"..
"add and change a human readable description later on.",
"If you click here, the selected quest will be deleted.\n"..
"This will only be possible if it's not used anywhere.")
if(selected and selected ~= "") then
local k = selected
-- index 1 is "Add variable:"
end
return table.concat(formspec, "")
end

View File

@ -14,6 +14,10 @@ yl_speak_up.input_quest_gui = function(player, formname, fields)
yl_speak_up.speak_to[pname][ "working_at" ] = "quest_gui"
yl_speak_up.show_fs(player, "manage_variables")
return ret
elseif(fields.manage_quests) then
yl_speak_up.speak_to[pname][ "working_at" ] = "quest_gui"
yl_speak_up.show_fs(player, "manage_quests")
return ret
end
-- the calling NPC shall no longer do anything
return ret
@ -22,8 +26,8 @@ end
yl_speak_up.get_fs_quest_gui = function(player, param)
local pname = player:get_player_name()
return "size[10,2]"..
return "size[24,20]"..
"label[0,0.5;Hi. This is a quest admin gui.]"..
"button[0.2,1.0;4.0,0.6;manage_variables;Manage variables]"
"button[0.2,1.0;4.0,0.6;manage_variables;Manage variables]"..
"button[6.2,1.0;4.0,0.6;manage_quests;Manage quests]"
end

View File

@ -118,6 +118,8 @@ yl_speak_up.reload = function(modpath, log_entry)
dofile(modpath .. "fs_manage_variables.lua")
-- handle variables for quests for player-owned NPC
dofile(modpath .. "quest_api.lua")
-- GUI for adding/editing quests
dofile(modpath .. "fs_manage_quests.lua")
-- setting skin, wielded item etc.
dofile(modpath .. "fs_fashion.lua")
-- properties for NPC without specific dialogs that want to make use of

View File

@ -524,3 +524,191 @@ end
yl_speak_up.get_time_in_seconds = function()
return math.floor(minetest.get_us_time()/1000000)
end
-----------------------------------------------------------------------------
-- Quests as such (up until here we mostly dealt with variables)
-----------------------------------------------------------------------------
-- uses yl_speak_up.quest_path
-- uses yl_speak_up.number_of_quests = yl_speak_up.modstorage:get_int("max_quest_id") or 0
-- table containing the quest data with q_id as index
yl_speak_up.quests = {}
-- store quest q_id to disc
yl_speak_up.save_quest = function(q_id)
local json = minetest.write_json(yl_speak_up.quests[q_id])
-- actually store it on disk
local file_name = yl_speak_up.worldpath..yl_speak_up.quest_path..DIR_DELIM..q_id..".json"
minetest.safe_file_write(file_name, json)
end
-- read quest q_id from disc
yl_speak_up.load_quest = function(q_id)
-- load the data from the file
local file_name = yl_speak_up.worldpath..yl_speak_up.quest_path..DIR_DELIM..q_id..".json"
local file, err = io.open(file_name, "r")
if err then
return
end
io.input(file)
local text = io.read()
-- all values saved in the tables as such are strings
local data = minetest.parse_json(text, "$NIL_VALUE$")
io.close(file)
if(type(data) ~= "table") then
return
end
for k,v in pairs(data) do
if(v == "$NIL_VALUE$") then
data[ k ] = {}
end
end
yl_speak_up.quests[q_id] = data
return
end
-- get data of quest q_id
yl_speak_up.get_quest = function(q_id)
if(not(yl_speak_up.quests[q_id])) then
load_quest(q_id)
end
return yl_speak_up.quests[q_id]
end
-- add/create a new quest
-- a quest is based on a variable; the variable is needed to store quest progress;
-- as this variable is of type integer, quests can only be linear;
-- in order to offer alternatives, players can add as many quests as they want and
-- make them depend on each other
yl_speak_up.add_quest = function(owner_name, variable_name, quest_name, descr_long, descr_short, comment)
-- add a special variable (if needed) for saving quest meta data
if(not(yl_speak_up.player_vars[ "$QUEST_META_DATA$" ])) then
yl_speak_up.player_vars[ "$QUEST_META_DATA$" ] = {}
yl_speak_up.save_quest_variables(true)
end
if(not(variable_name) or variable_name == "") then
return "Missing name of variable."
end
-- determine the full name of the variable used to store quest progress
local var_name = yl_speak_up.add_pname_to_var(variable_name, owner_name)
-- if it is a new variable: make sure it gets created
if(not(yl_speak_up.player_vars[var_name])) then
-- create the new varialbe
yl_speak_up.add_quest_variable(owner_name, variable_name)
else
-- if it exists already: make sure it is of a type that can be used
local var_type = yl_speak_up.get_variable_metadata(var_name, "var_type")
if("var_type" == "time_based") then
return "Variable already used as a timer."
elseif("var_type" == "quest") then
return "Variable already used by another quest."
end
end
-- set the variable for the quest creator to 0 - so that it's possible to check for
-- var_name is set (to a value) in a precondition and thus only allow the quest creator
-- to test the quest in the beginning
yl_speak_up.set_quest_variable_value(owner_name, var_name, 0)
-- set the variable type to quest
yl_speak_up.set_variable_metadata(var_name, owner_name, "var_type", nil, "quest")
-- get a uniq ID for storing this quest (mostly needed for creating a safe file name)
local quest_nr = yl_speak_up.number_of_quests + 1
yl_speak_up.number_of_quests = quest_nr
yl_speak_up.modstorage:set_int("max_quest_nr", yl_speak_up.number_of_quests)
-- store this number in the variable $META$ data
yl_speak_up.set_variable_metadata(var_name, owner_name, "quest_data", "quest_nr", quest_nr)
-- the list of quest steps is stored in the variables' metadata for quicker access
-- (this way we won't have to load the quest file if we want to check a precondition
-- or update the variable value to the next quest step)
yl_speak_up.set_variable_metadata(var_name, owner_name, "quest_data", "steps", {"start","finish"})
-- create the quest data structure
local quest = {}
quest.nr = quest_nr
quest.id = "q_"..quest_nr -- quest ID
quest.name = quest_name -- human-readable name of the quest
quest.description = (descr_long or "")
-- long description of what the quest is about
quest.short_desc = (descr_short or "")
-- a short description of this quest which may later be used to
-- advertise for the quest in a quest log
quest.comment = (comment or "")
-- comment to other programmers who might want to maintain the
-- quest later on
quest.owner = owner_name -- creator of the quest
quest.var_name = var_name -- name of the variable where progress is stored for each player
-- quest.steps = { -- list of names (strings) of the quest steps
-- "start", -- the quest needs to start somehow
-- "finish"} -- and it needs to finish somehow
-- the following things can be determined automaticly, BUT: in order to PLAN a future
-- quest, it is easier to gather information here first
quest.step_data = {} -- table containing information about a quest step (=key)
-- this may also be information about WHERE a quest step shall
-- take place
quest.subquests = {} -- list of other quest_ids that contribute to this quest
-- -> determined from quests.npcs and quests.locations
quest.is_subquest_of = {} -- list of quest_ids this quest contributes to
-- -> determined from quests.npcs and quests.locations
quest.npcs = {} -- list of NPC that contribute to this quest
-- -> derived from quest.var_name
quest.locations = {} -- list of locations that contribute to this quest
-- -> derived from quest.var_name
quest.items = {} -- data of quest items created and accepted
-- -> derived from the quest steps
quest.rewards = {} -- list of rewards (item stacks) for this ques
quest.testers = {} -- list of player names that can test the quest
-- -> during the created/testing phase: any player for which
-- quest.var_name is set to a value
quest.solved_by = {} -- list of names of players that solved the quest at least once
quest.state = "created" -- state of the quest:
-- created: only the creator can do it
-- testing: players listed in quest.testers can do the quest
-- open: *all* players with interact can try to solve the quest
-- *AND* changes to the quest are now impossible (apart from
-- changing texts in the NPC)
-- official: official server quest; NPC can create items out of thin air
-- store the new quest in the quest table
yl_speak_up.quests[quest.id] = quest
-- and store it on disc
yl_speak_up.save_quest(quest.id)
return "OK"
end
-- returns a list of all quest IDs to which the player has write access
yl_speak_up.get_quest_owner_list = function(pname)
local var_list = yl_speak_up.get_quest_variables_with_write_access(pname)
local quest_id_list = {}
for i, var_name in ipairs(var_list) do
local t = yl_speak_up.get_variable_metadata(var_name, "var_type")
if(t and t == "quest") then
local data = yl_speak_up.get_variable_metadata(var_name, "quest_data", true)
if(data and data["quest_nr"]) then
table.insert(quest_id_list, "q_"..tostring(data["quest_nr"]))
end
end
end
return quest_id_list
end
yl_speak_up.get_sorted_quest_list = function(pname)
local var_list = yl_speak_up.get_quest_variables_with_write_access(pname)
local quest_list = {}
for i, var_name in ipairs(var_list) do
local t = yl_speak_up.get_variable_metadata(var_name, "var_type")
if(t and t == "quest") then
table.insert(quest_list, var_name)
end
end
yl_speak_up.strip_pname_from_varlist(quest_list, pname)
table.sort(quest_list)
return quest_list
end

View File

@ -92,10 +92,14 @@ yl_speak_up.input_handler = function(player, formname, fields)
elseif formname == "yl_speak_up:edit_effects" then
yl_speak_up.input_fs_edit_effects(player, formname, fields)
return true
-- handled in quest_api.lua
-- handled in fs_manage_variables.lua
elseif formname == "yl_speak_up:manage_variables" then
yl_speak_up.input_fs_manage_variables(player, formname, fields)
return true
-- handled in fs_manage_quests.lua
elseif formname == "yl_speak_up:manage_quests" then
yl_speak_up.input_fs_manage_quests(player, formname, fields)
return true
-- handled in fs_alternate_text.lua
elseif formname == "yl_speak_up:show_what_points_to_this_dialog" then
yl_speak_up.input_fs_show_what_points_to_this_dialog(player, formname, fields)
@ -386,6 +390,10 @@ yl_speak_up.show_fs = function(player, fs_name, param)
yl_speak_up.show_fs_ver(pname, "yl_speak_up:manage_variables",
yl_speak_up.get_fs_manage_variables(player, param))
elseif(fs_name == "manage_quests") then
yl_speak_up.show_fs_ver(pname, "yl_speak_up:manage_quests",
yl_speak_up.get_fs_manage_quests(player, param))
elseif(fs_name == "show_what_points_to_this_dialog") then
yl_speak_up.show_fs_ver(pname, "yl_speak_up:show_what_points_to_this_dialog",
yl_speak_up.show_what_points_to_this_dialog(player, param))