From c3c7b7e2daae53f4115c1c75b0debb84e44dca81 Mon Sep 17 00:00:00 2001 From: Sokomine Date: Mon, 5 Jul 2021 19:31:29 +0200 Subject: [PATCH] added yl_speak_up.get_npc_users_of_variable and modified saving of npc data so that the necessary data is stored --- functions.lua | 2 + quest_api.lua | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) diff --git a/functions.lua b/functions.lua index 751cda1..8fee3bd 100644 --- a/functions.lua +++ b/functions.lua @@ -152,6 +152,8 @@ yl_speak_up.save_dialog = function(n_id, dialog) return false end local p = save_path(n_id) + -- save some data (in particular usage of quest variables) + yl_speak_up.update_stored_npc_data(n_id, dialog) local content = minetest.write_json(dialog) return minetest.safe_file_write(p, content) end diff --git a/quest_api.lua b/quest_api.lua index 88ad077..e8322ea 100644 --- a/quest_api.lua +++ b/quest_api.lua @@ -49,6 +49,9 @@ yl_speak_up.load_quest_variables = function() end end yl_speak_up.player_vars = data + if(not(yl_speak_up.player_vars.meta)) then + yl_speak_up.player_vars["meta"] = {} + end end -- do so when this file is parsed yl_speak_up.load_quest_variables() @@ -237,3 +240,138 @@ yl_speak_up.strip_pname_from_varlist = function(var_list, pname) end return var_list_text end + + +-- helper function for saving NPC data; +-- this only works if *someone* is currently talking to that NPC +yl_speak_up.get_pname_for_n_id = function(n_id) + for k, v in pairs(yl_speak_up.speak_to) do + if(v and v.n_id and v.n_id == n_id) then + return k + end + end +end + + +-- the dialog data of an NPC is saved - use this to save some statistical data +-- plus store which variables are used by this NPC +yl_speak_up.update_stored_npc_data = function(n_id, dialog) + -- in order to determine the position of the NPC, we need its object + local pname = yl_speak_up.get_pname_for_n_id(n_id) + local npc_pos = "" + if(pname) then + local obj = yl_speak_up.speak_to[pname].obj + if(obj and obj:get_pos()) then + npc_pos = minetest.pos_to_string(obj:get_pos()) + end + end + -- gather statistical data about the NPC and find out which variables it uses + local anz_dialogs = 0 + local anz_options = 0 + local anz_preconditions = 0 + local anz_actions = 0 + local anz_effects = 0 + local anz_trades = 0 + local variables_p = {} + local variables_e = {} + if(dialog and dialog.n_dialogs) then + for d_id, d in pairs(dialog.n_dialogs) do + anz_dialogs = anz_dialogs + 1 + if(d and d.d_options) then + for o_id, o in pairs(d.d_options) do + anz_options = anz_options + 1 + if(o and o.o_prerequisites) then + for p_id, p in pairs(o.o_prerequisites) do + anz_preconditions = anz_preconditions + 1 + if(p and p.p_type and p.p_type == "state" + and p.p_variable and p.p_variable ~= "") then + variables_p[ p.p_variable ] = true + end + end + end + if(o and o.actions) then + for a_id, a_data in pairs(o.actions) do + anz_actions = anz_actions + 1 + end + end + if(o and o.o_results) then + for r_id, r in pairs(o.o_results) do + anz_effects = anz_effects + 1 + if(r and r.r_type and r.r_type == "state" + and r.r_variable and r.r_variable ~= "") then + variables_e[ r.r_variable ] = true + end + end + end + end + end + end + end + if(dialog and dialog.trades) then + for trade_id, t_data in pairs(dialog.trades) do + -- not a trade that is the action of a dialog option; only trade list trades count + if(not(t_data.d_id)) then + anz_trades = anz_trades + 1 + end + end + end + -- add a special variable (if needed) for saving the NPC meta data + if(not(yl_speak_up.player_vars[ "$NPC_META_DATA$" ])) then + yl_speak_up.player_vars[ "$NPC_META_DATA$" ] = {} + end + yl_speak_up.player_vars[ "$NPC_META_DATA$" ][ n_id ] = { + n_id = n_id, + name = tostring(dialog.n_npc), + owner = tostring(yl_speak_up.npc_owner[ n_id ]), + pos = tostring(npc_pos), + anz_dialogs = anz_dialogs, + anz_options = anz_options, + anz_preconditions = anz_preconditions, + anz_actions = anz_actions, + anz_effects = anz_effects, + anz_trades = anz_trades, + last_modified = os.date(), + } + + -- save in the variables' metadata which NPC uses it + -- (this is what we're mostly after - know which variable is used in which NPC) + for k, v in pairs(variables_p) do + -- if the variable does not exist: create it + if(not(yl_speak_up.player_vars[ k ])) then + yl_speak_up.player_vars[ k ] = {} + end + if(not(yl_speak_up.player_vars[ k ][ "$META$" ])) then + yl_speak_up.player_vars[ k ][ "$META$"] = { used_by_npc = {} } + end + yl_speak_up.player_vars[ k ][ "$META$"][ "used_by_npc" ][ n_id ] = true + end + for k, v in pairs(variables_e) do + -- if the variable does not exist: create it + if(not(yl_speak_up.player_vars[ k ])) then + yl_speak_up.player_vars[ k ] = {} + end + if(not(yl_speak_up.player_vars[ k ][ "$META$" ])) then + yl_speak_up.player_vars[ k ][ "$META$"] = { used_by_npc = {} } + end + yl_speak_up.player_vars[ k ][ "$META$"][ "used_by_npc" ][ n_id ] = true + end + -- force writing the data + yl_speak_up.save_quest_variables(true) +end + + +yl_speak_up.get_npc_users_of_variable = function(var_name) + -- no variable, or nothing stored? then it's not used by any NPC either + if(not(var_name) + or not(yl_speak_up.player_vars[ var_name ]) + or not(yl_speak_up.player_vars[ var_name ][ "$META$"]) + or not(yl_speak_up.player_vars[ var_name ][ "$META$"][ "used_by_npc" ])) then + return {} + end + local npc_list = {} + for n_id, v in pairs(yl_speak_up.player_vars[ var_name ][ "$META$"][ "used_by_npc" ]) do + table.insert(npc_list, n_id) + end + table.sort(npc_list) + return npc_list +end