added first basic creation/delition of quest steps
This commit is contained in:
parent
263ec1ac86
commit
4ce6101bca
120
fs_manage_quest_steps.lua
Normal file
120
fs_manage_quest_steps.lua
Normal file
@ -0,0 +1,120 @@
|
||||
|
||||
-- Imposing an order on the quest steps is...tricky as best as what will
|
||||
-- be more important to the players will be the order in which the
|
||||
-- quest steps have to be solved/done - and not an alphabetical order.
|
||||
-- But we need an order here for a dropdown menu to select each
|
||||
-- quest step even if it hasn't been assigned any place in the chain
|
||||
-- of quest steps yet. So - alphabetical order.
|
||||
yl_speak_up.get_sorted_quest_step_list = function(pname, q_id)
|
||||
local quest_step_list = {}
|
||||
if(not(pname) or not(yl_speak_up.speak_to[pname])) then
|
||||
return {}
|
||||
end
|
||||
local q_id = yl_speak_up.speak_to[pname].q_id
|
||||
|
||||
if(q_id and yl_speak_up.quests[q_id] and yl_speak_up.quests[q_id].step_data) then
|
||||
for step_id, v in pairs(yl_speak_up.quests[q_id].step_data) do
|
||||
table.insert(quest_step_list, step_id)
|
||||
end
|
||||
end
|
||||
table.sort(quest_step_list)
|
||||
return quest_step_list
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- helper functions for yl_speak_up.input_fs_manage_quest_steps(..)
|
||||
-- returns the index of the new quest step
|
||||
yl_speak_up.input_fs_manage_quest_steps_add_new_entry = function(pname, entry_name)
|
||||
local q_id = yl_speak_up.speak_to[pname].q_id
|
||||
local res = yl_speak_up.quest_step_add_quest_step(pname, q_id, entry_name)
|
||||
-- might make sense to show the error message somewhere
|
||||
if(res ~= "OK") then
|
||||
return res
|
||||
end
|
||||
-- the new entry will be somewhere in it
|
||||
local quest_step_list = yl_speak_up.get_sorted_quest_step_list(pname)
|
||||
return table.indexof(quest_step_list, entry_name)
|
||||
end
|
||||
|
||||
|
||||
-- helper functions for yl_speak_up.input_fs_manage_quest_steps(..)
|
||||
-- returns a text describing if deleting the quest worked
|
||||
yl_speak_up.input_fs_manage_quest_steps_del_old_entry = function(pname, entry_name)
|
||||
local q_id = yl_speak_up.speak_to[pname].q_id
|
||||
return yl_speak_up.quest_step_del_quest_step(pname, q_id, entry_name)
|
||||
end
|
||||
|
||||
|
||||
-- helper functions for yl_speak_up.input_fs_manage_quest_steps(..)
|
||||
-- implements all the functions that are specific to managing quest steps and not part of
|
||||
-- general item management
|
||||
yl_speak_up.input_fs_manage_quest_steps_check_fields = function(player, formname, fields, quest_step_name, list_of_entries)
|
||||
local pname = player:get_player_name()
|
||||
if(not(quest_step_name)) then
|
||||
quest_step_name = ""
|
||||
end
|
||||
--[[ TODO: implement some back button functionality?
|
||||
if(fields and fields.show_variable) then
|
||||
yl_speak_up.show_fs(player, "manage_variables", {var_name = quest_name})
|
||||
return
|
||||
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_quest_steps = function(player, formname, fields)
|
||||
minetest.chat_send_player("singleplayer", "INPUT: "..minetest.serialize(fields))
|
||||
local pname = player:get_player_name()
|
||||
|
||||
local quest_step_list = yl_speak_up.get_sorted_quest_step_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 step", 2, 70,
|
||||
yl_speak_up.input_fs_manage_quest_steps_add_new_entry,
|
||||
quest_step_list,
|
||||
yl_speak_up.input_fs_manage_quest_steps_del_old_entry,
|
||||
yl_speak_up.input_fs_manage_quest_steps_check_fields)
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
yl_speak_up.get_fs_manage_quest_steps = function(player, param)
|
||||
local pname = player:get_player_name()
|
||||
local formspec = {}
|
||||
|
||||
local q_id = yl_speak_up.speak_to[pname].q_id
|
||||
local quest = yl_speak_up.quests[q_id]
|
||||
local step_data = quest.step_data
|
||||
|
||||
local quest_step_list = yl_speak_up.get_sorted_quest_step_list(pname)
|
||||
if(param and param ~= "") then
|
||||
local index = table.indexof(quest_step_list, param)
|
||||
yl_speak_up.speak_to[pname].tmp_index_general = index + 1
|
||||
end
|
||||
table.insert(formspec, "size[18,12]"..
|
||||
"label[0.2,1.2;A quest step is a single thing a player may do in a quest - "..
|
||||
"like talking to an NPC.\n"..
|
||||
"Usually not all quest steps can be done/solved at all times.]")
|
||||
local selected = yl_speak_up.get_fs_manage_general(player, param,
|
||||
formspec, quest_step_list,
|
||||
"Create quest step",
|
||||
"Create a new quest step for this quest.",
|
||||
"quest step",
|
||||
"Enter the name of the new quest step you want to create.\n"..
|
||||
"This is an internal text shown only to yourself.\n"..
|
||||
"Players cannot see the names of quest steps.",
|
||||
"If you click here, the selected quest step 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:"
|
||||
table.insert(formspec, "button[12,2.15;4.5,0.6;show_variable;Show and edit this variable]")
|
||||
end
|
||||
--]]
|
||||
return table.concat(formspec, "")
|
||||
end
|
2
init.lua
2
init.lua
@ -218,6 +218,8 @@ yl_speak_up.reload = function(modpath, log_entry)
|
||||
dofile(modpath .. "quest_api.lua")
|
||||
-- GUI for adding/editing quests
|
||||
dofile(modpath .. "fs_manage_quests.lua")
|
||||
-- GUI for adding/editing quest steps for the quests
|
||||
dofile(modpath .. "fs_manage_quest_steps.lua")
|
||||
-- setting skin, wielded item etc.
|
||||
dofile(modpath .. "fs_fashion.lua")
|
||||
-- properties for NPC without specific dialogs that want to make use of
|
||||
|
233
quest_api.lua
233
quest_api.lua
@ -25,6 +25,20 @@ yl_speak_up.save_quest_variables = function(force_save)
|
||||
end
|
||||
|
||||
|
||||
yl_speak_up.handle_json_nil_values = function(data)
|
||||
if(data and type(data) == "table") then
|
||||
for k,v in pairs(data) do
|
||||
if( type(v) == "string" and v == "$NIL_VALUE$") then
|
||||
data[ k ] = {}
|
||||
elseif(type(v) == "table") then
|
||||
data[ k ] = yl_speak_up.handle_json_nil_values(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
return data
|
||||
end
|
||||
|
||||
|
||||
-- load the data from disc
|
||||
yl_speak_up.load_quest_variables = function()
|
||||
-- load the data from the file
|
||||
@ -41,12 +55,7 @@ yl_speak_up.load_quest_variables = function()
|
||||
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.player_vars = data
|
||||
yl_speak_up.player_vars = yl_speak_up.handle_json_nil_values(data)
|
||||
if(not(yl_speak_up.player_vars.meta)) then
|
||||
yl_speak_up.player_vars["meta"] = {}
|
||||
end
|
||||
@ -195,7 +204,8 @@ yl_speak_up.get_quest_variables = function(pname, has_write_access)
|
||||
end
|
||||
-- if the player has the right privs: allow to access all other variables as well
|
||||
if( minetest.check_player_privs(pname, {npc_master=true})
|
||||
or minetest.check_player_privs(pname, {npc_talk_master=true})) then
|
||||
or minetest.check_player_privs(pname, {npc_talk_master=true})
|
||||
or minetest.check_player_privs(pname, {npc_talk_admin=true})) then
|
||||
for k, v in pairs(yl_speak_up.player_vars) do
|
||||
local parts = string.split(k, " ")
|
||||
-- variables owned by *other* players
|
||||
@ -546,6 +556,7 @@ yl_speak_up.save_quest = function(q_id)
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- read quest q_id from disc
|
||||
yl_speak_up.load_quest = function(q_id)
|
||||
-- load the data from the file
|
||||
@ -563,12 +574,7 @@ yl_speak_up.load_quest = function(q_id)
|
||||
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
|
||||
yl_speak_up.quests[q_id] = yl_speak_up.handle_json_nil_values(data)
|
||||
return
|
||||
end
|
||||
|
||||
@ -627,6 +633,7 @@ yl_speak_up.add_quest = function(owner_name, variable_name, quest_name, descr_lo
|
||||
-- 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)
|
||||
-- TODO: store those in the quest file
|
||||
yl_speak_up.set_variable_metadata(var_name, owner_name, "quest_data", "steps", {"start","finish"})
|
||||
|
||||
-- create the quest data structure
|
||||
@ -658,8 +665,10 @@ yl_speak_up.add_quest = function(owner_name, variable_name, quest_name, descr_lo
|
||||
-- -> determined from quests.npcs and quests.locations
|
||||
quest.npcs = {} -- list of NPC that contribute to this quest
|
||||
-- -> derived from quest.var_name
|
||||
-- --> or derived from quest.step_data.where
|
||||
quest.locations = {} -- list of locations that contribute to this quest
|
||||
-- -> derived from quest.var_name
|
||||
-- --> or derived from quest.step_data.where
|
||||
quest.items = {} -- data of quest items created and accepted
|
||||
-- -> derived from the quest steps
|
||||
quest.rewards = {} -- list of rewards (item stacks) for this ques
|
||||
@ -746,6 +755,186 @@ yl_speak_up.get_sorted_quest_list = function(pname)
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- quests have a name and a variable which stores their data
|
||||
-- this returns the q_id (index in the quest table) based on the variable name
|
||||
yl_speak_up.get_quest_id_by_var_name = function(var_name, owner_name)
|
||||
local var_name = yl_speak_up.add_pname_to_var(var_name, owner_name)
|
||||
-- find out which quest we're talking about
|
||||
for q_id, quest in pairs(yl_speak_up.quests) do
|
||||
if(quest.var_name == var_name) then
|
||||
return q_id
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
-- quests can also be identified by their name
|
||||
-- this returns the q_id (index in the quest table) based on the quest name
|
||||
yl_speak_up.get_quest_id_by_quest_name = function(quest_name)
|
||||
-- find out which quest we're talking about
|
||||
for q_id, quest in pairs(yl_speak_up.quests) do
|
||||
if(quest.name == quest_name) then
|
||||
return q_id
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
-- finds out if player pname is allowed to view (read_only is true)
|
||||
-- or edit (read_only is false) the quest q_id
|
||||
yl_speak_up.quest_allow_access = function(q_id, pname, read_only)
|
||||
-- no quest with that variable as base found
|
||||
if(not(q_id) or not(yl_speak_up.quests[q_id])) then
|
||||
return "Quest not found (id: "..tostring(q_id)..")."
|
||||
end
|
||||
local quest = yl_speak_up.quests[q_id]
|
||||
-- check if the player has access rights to that quest
|
||||
if(quest.owner ~= pname
|
||||
and not(minetest.check_player_privs(pname, {npc_master=true}))
|
||||
and not(minetest.check_player_privs(pname, {npc_talk_master=true}))
|
||||
and not(minetest.check_player_privs(pname, {npc_talk_admin=true}))) then
|
||||
-- the player may have suitable privs (check access to the variable)
|
||||
local access_what = "write_access"
|
||||
if(read_only) then
|
||||
access_what = "read_access"
|
||||
end
|
||||
local allowed = yl_speak_up.get_access_list_for_var(quest.var_name, "", access_what)
|
||||
if(table.indexof(allowed, pname) == -1) then
|
||||
return "Sorry. You have no write access to quest \""..tostring(quest.name).."\" "..
|
||||
"["..tostring(k).."]."
|
||||
end
|
||||
end
|
||||
-- quests that are already open to the public cannot be changed anymore
|
||||
-- as that would cause chaos; only in "created" and "testing" stage it's
|
||||
-- possible to change quest steps
|
||||
if(not(read_only) and (quest.state == "open" or quest.state == "official")) then
|
||||
return "The quest is in state \""..tostring(quest.state).."\". Quests in such "..
|
||||
"a state cannot be changed/extended as that would confuse players. "..
|
||||
"Reset quest state first if changes are unavoidable."
|
||||
end
|
||||
return "OK"
|
||||
end
|
||||
|
||||
|
||||
-- add a quest step to a quest
|
||||
yl_speak_up.quest_step_add_quest_step = function(pname, q_id, quest_step_name)
|
||||
local error_msg = yl_speak_up.quest_allow_access(q_id, pname, false)
|
||||
if(error_msg ~= "OK") then
|
||||
return error_msg
|
||||
end
|
||||
if(not(quest_step_name) or quest_step_name == ""
|
||||
or string.len(quest_step_name) < 2 or string.len(quest_step_name) > 70) then
|
||||
return "No name for this quest step given or too long (>70) or too short (<2 characters)."
|
||||
end
|
||||
if(not(yl_speak_up.quests[q_id].step_data)) then
|
||||
yl_speak_up.quests[q_id].step_data = {}
|
||||
end
|
||||
-- create an entry for the quest step if needed
|
||||
if(not(yl_speak_up.quests[q_id].step_data[quest_step_name])) then
|
||||
yl_speak_up.quests[q_id].step_data[quest_step_name] = {
|
||||
-- where (NPCs, locations) can this quest step be set?
|
||||
where = {}}
|
||||
yl_speak_up.save_quest(q_id)
|
||||
end
|
||||
-- return OK even if the quest step existed already
|
||||
return "OK"
|
||||
end
|
||||
|
||||
|
||||
-- delete a quest step - but only if it's not used
|
||||
yl_speak_up.quest_step_del_quest_step = function(pname, q_id, quest_step_name)
|
||||
local error_msg = yl_speak_up.quest_allow_access(q_id, pname, false)
|
||||
if(error_msg ~= "OK") then
|
||||
return error_msg
|
||||
end
|
||||
if(not(quest_step_name)
|
||||
or not(yl_speak_up.quests[q_id].step_data)
|
||||
or not(yl_speak_up.quests[q_id].step_data[quest_step_name])) then
|
||||
return "OK"
|
||||
end
|
||||
-- the quest step exists; can we delete it?
|
||||
local quest_step = yl_speak_up.quests[q_id].step_data[quest_step_name]
|
||||
local anz_where = 0
|
||||
for k, _ in pairs(quest_step.where or {}) do
|
||||
anz_where = anz_where + 1
|
||||
end
|
||||
if(anz_where > 0) then
|
||||
return "This quest step is used/set by "..tostring(anz_where)..
|
||||
" NPCs and/or locations.\nRemove them from this quest step first!"
|
||||
end
|
||||
-- is this the previous quest step of another step?
|
||||
for sn, step_data in pairs(yl_speak_up.quests[q_id].step_data) do
|
||||
if(step_data and step_data.previous_step and step_data.previous_step == quest_step_name) then
|
||||
return "Quest step \""..tostring(sn).."\" names this quest step that you want "..
|
||||
"to delete as its previous step. Please remove that requirement first "..
|
||||
"for quest step \""..tostring(sn).."\" before deleting this step here."
|
||||
end
|
||||
if(step_data and step_data.further_required_steps
|
||||
and table.indexof(step_data.further_required_steps, quest_step_name) ~= -1) then
|
||||
return "Quest step \""..tostring(sn).."\" gives this quest step that you want "..
|
||||
"to delete as one of the further steps required to reach it. Please "..
|
||||
"remove that requirement first "..
|
||||
"for quest step \""..tostring(sn).."\" before deleting this step here."
|
||||
end
|
||||
-- offered_until_quest_step_reached would be no problem/hinderance and doesn't need checking
|
||||
end
|
||||
yl_speak_up.quests[q_id].step_data[quest_step_name] = nil
|
||||
yl_speak_up.save_quest(q_id)
|
||||
return "OK"
|
||||
end
|
||||
|
||||
|
||||
-- add an NPC or location to a quest step (quest_step.where = list of such locations)
|
||||
-- Note: This is for NPC and locations that SET this very quest step. They ought to be listed here.
|
||||
-- new_location has to be a table, and new_loc_id an ID to avoid duplicates
|
||||
-- for NPC, new_loc_id ought to look like this: "NPC <n_id> <d_id> <o_id>"
|
||||
yl_speak_up.quest_step_add_where = function(pname, q_id, quest_step_name, new_location, new_loc_id) local error_msg = yl_speak_up.quest_allow_access(q_id, pname, false)
|
||||
if(error_msg ~= "OK") then
|
||||
return error_msg
|
||||
end
|
||||
local quest_step = yl_speak_up.quests[q_id].step_data[quest_step_name]
|
||||
if(not(quest_step)) then
|
||||
return "Quest step \""..tostring(quest_step_name).."\" does not exist."
|
||||
end
|
||||
if(not(step_data.where)) then
|
||||
step_data.where = {}
|
||||
end
|
||||
if(step_data.where[new_loc_id]) then
|
||||
return "OK"
|
||||
end
|
||||
yl_speak_up.quests[q_id].step_data[quest_step_name].where[new_loc_id] = new_location
|
||||
-- return OK even if the quest step existed already
|
||||
return "OK"
|
||||
end
|
||||
|
||||
|
||||
-- delete a quest step location with the id location_id
|
||||
yl_speak_up.quest_step_del_where = function(pname, q_id, quest_step_name, location_id)
|
||||
local error_msg = yl_speak_up.quest_allow_access(q_id, pname, false)
|
||||
if(error_msg ~= "OK") then
|
||||
return error_msg
|
||||
end
|
||||
local quest_step = yl_speak_up.quests[q_id].step_data[quest_step_name]
|
||||
if(not(quest_step)) then
|
||||
return "Quest step \""..tostring(quest_step_name).."\" does not exist."
|
||||
end
|
||||
if(not(step_data.where)) then
|
||||
step_data.where = {}
|
||||
end
|
||||
-- delete the quest step location
|
||||
yl_speak_up.quests[q_id].step_data[quest_step_name].where[location_id] = nil
|
||||
return "OK"
|
||||
end
|
||||
|
||||
|
||||
-- TODO: quest_step: previous_step
|
||||
-- TODO: quest_step: further_required_steps
|
||||
-- TODO: quest_step: offered_until_quest_step_reached
|
||||
|
||||
|
||||
-- called for example by yl_speak_up.eval_all_preconditions to see if the player
|
||||
-- can reach quest_step in quest quest_id
|
||||
yl_speak_up.quest_step_possible = function(player, quest_step, quest_id, n_id, d_id, o_id)
|
||||
@ -766,3 +955,21 @@ yl_speak_up.quest_step_reached = function(player, quest_step, quest_id, n_id, d_
|
||||
-- TODO: actually store the quest progress
|
||||
-- minetest.chat_send_player("singleplayer", "SETTING quest step "..tostring(quest_step).." for quest "..tostring(quest_id))
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- load all known quests
|
||||
yl_speak_up.load_all_quests = function()
|
||||
for var_name, var_data in pairs(yl_speak_up.player_vars) do
|
||||
local var_type = yl_speak_up.get_variable_metadata(var_name, "var_type")
|
||||
if(var_type == "quest") then
|
||||
local data = yl_speak_up.get_variable_metadata(var_name, "quest_data", true)
|
||||
if(data and data["quest_nr"]) then
|
||||
yl_speak_up.load_quest("q_"..tostring(data["quest_nr"]))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- do so on startup and reload
|
||||
yl_speak_up.load_all_quests()
|
||||
|
@ -107,6 +107,10 @@ yl_speak_up.input_handler = function(player, formname, fields)
|
||||
elseif formname == "yl_speak_up:manage_quests" then
|
||||
yl_speak_up.input_fs_manage_quests(player, formname, fields)
|
||||
return true
|
||||
-- handled in fs_manage_quest_steps.lua
|
||||
elseif formname == "yl_speak_up:manage_quest_steps" then
|
||||
yl_speak_up.input_fs_manage_quest_steps(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)
|
||||
@ -410,6 +414,10 @@ yl_speak_up.show_fs = function(player, fs_name, param)
|
||||
yl_speak_up.show_fs_ver(pname, "yl_speak_up:manage_quests",
|
||||
yl_speak_up.get_fs_manage_quests(player, param))
|
||||
|
||||
elseif(fs_name == "manage_quest_steps") then
|
||||
yl_speak_up.show_fs_ver(pname, "yl_speak_up:manage_quest_steps",
|
||||
yl_speak_up.get_fs_manage_quest_steps(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))
|
||||
|
Loading…
Reference in New Issue
Block a user