From e2ecb7de4b23feb1bdb752af48d4a63d1f433f39 Mon Sep 17 00:00:00 2001 From: Sokomine Date: Fri, 21 Jul 2023 01:10:46 +0200 Subject: [PATCH] prepared for /npc_talk list command --- chat_commands.lua | 3 + fs_npc_list.lua | 148 ++++++++++++++++++++++++++++++++++++++++++++++ functions.lua | 3 + init.lua | 3 + 4 files changed, 157 insertions(+) create mode 100644 fs_npc_list.lua diff --git a/chat_commands.lua b/chat_commands.lua index 25866e2..f531a40 100644 --- a/chat_commands.lua +++ b/chat_commands.lua @@ -12,6 +12,8 @@ yl_speak_up.command_npc_talk = function(pname, param) if( cmd and cmd == "style") then -- implemented in fs_decorated.lua: return yl_speak_up.command_npc_talk_style(pname, rest) + elseif(cmd and cmd == "list") then + return yl_speak_up.command_npc_talk_list(pname, rest) -- debug mode only makes sense if the player can edit that NPC; the command checks for this elseif(cmd and cmd == "debug") then -- implemented in npc_talk_debug.lua: @@ -49,6 +51,7 @@ yl_speak_up.command_npc_talk = function(pname, param) "Usage: \"/npc_talk \" with beeing:\n".. " help this help here\n".. " style display talk menu in a way better suited for very old versions of MT\n".. + " list shows a list of NPC that you can edit\n".. " debug debug a particular NPC\n".. " force_edit forces edit mode for any NPC you talk to\n".. " generic [requores npc_talk_admin priv] list, add or remove NPC as generic NPC\n".. diff --git a/fs_npc_list.lua b/fs_npc_list.lua new file mode 100644 index 0000000..d0cccb8 --- /dev/null +++ b/fs_npc_list.lua @@ -0,0 +1,148 @@ +-- keeps a list of NPC with some data; Index: n_id +-- is saved to disk +yl_speak_up.npc_list = {} + +-- list of objects of the NPC; Index: n_id +-- no point in saving this to disk +yl_speak_up.npc_list_objects = {} + +-- file to store the list of NPC for the "/npc_talk list" command +yl_speak_up.npc_list_path = minetest.get_worldpath().."/yl_speak_up_npc_list.data" + +-- add/update data about NPC self with dialog dialog (optional) +-- force_store ought to be true if something important has been changed +yl_speak_up.update_npc_data = function(self, dialog, force_store) + -- is this a properly indexed npc? + if(not(self) or not(self.yl_speak_up) or not(self.yl_speak_up.id)) then + return + end + local is_known = not(not(yl_speak_up.npc_list[self.yl_speak_up.id])) + -- who else may edit this NPC - that is stored in the dialog + local may_edit = {} + local desc = "" + local trades = {} + if(dialog) then + may_edit = dialog.n_may_edit + desc = dialog.n_description + -- maybe update this only when the trades are updated? + if(dialog.trades) then + for k, v in pairs(dialog.trades) do + if(v.buy and v.pay and v.buy[1] and v.pay[1]) then + table.insert(trades, {v.buy[1], v.pay[1]}) + end + end + end + elseif(is_knwon) then + local old = yl_speak_up.npc_list[self.yl_speak_up.id] + may_edit = old.may_edit + desc = old.desc + trades = old.trades + end + local created_at = 0 + if(is_known) then + created_at = yl_speak_up.npc_list[self.yl_speak_up.id].created_at + else + created_at = os.time() + end + local pos = {} + if(self.object) then + pos = self.object:get_pos() + pos.x = math.floor(pos.x or 0) + pos.y = math.floor(pos.y or 0) + pos.z = math.floor(pos.z or 0) + end + -- only store real, important properties + local properties = {} + for k, v in pairs(self.yl_speak_up.properties or {}) do + if(string.sub(k, 1, 5) ~= "self.") then + properties[k] = v + end + end + -- update the information we have on the NPC + yl_speak_up.npc_list[self.yl_speak_up.id] = { + typ = self.name, + name = self.yl_speak_up.npc_name, + desc = desc, + owner = self.owner, + may_edit = may_edit, + trades = trades, + pos = pos, + properties = properties, + } + -- the current object will change after deactivate; there is no point in storing + -- it over server restart + yl_speak_up.npc_list_objects[self.yl_speak_up.id] = self.object + -- if we didn't know about this NPC before then by all means store the data + if(not(is_known) or force_store) then + yl_speak_up.npc_list_store() + end +end + + +yl_speak_up.npc_list_load = function() + local file,err = io.open( yl_speak_up.npc_list_path, "rb") + if (file == nil) then + yl_speak_up.npc_list = {} + return + end + local data = file:read("*all") + file:close() + yl_speak_up.npc_list = minetest.deserialize(data) +end + + +yl_speak_up.npc_list_store = function() + local file,err = io.open( yl_speak_up.npc_list_path, "wb") + if (file == nil) then + return + end + file:write(minetest.serialize(yl_speak_up.npc_list)) + file:close() +end + + +-- provides a list of NPC the player can edit +yl_speak_up.command_npc_talk_list = function(pname, rest) + if(not(pname)) then + return + end + local level = 0 + if( minetest.check_player_privs(pname, {npc_master=true}) + or minetest.check_player_privs(pname, {npc_talk_master=true}) + or minetest.check_player_privs(pname, {npc_talk_admin=true})) then + level = 2 + elseif(minetest.check_player_privs(pname, {npc_talk_owner=true})) then + level = 1 + end + if(level < 1) then + minetest.chat_send_player(pname, "This command requires the npc_talk_owner priv or above.") + return + end + + minetest.chat_send_player(pname, "OK...building list.") + + -- sort by default by id descending? + + -- check if there are any loaded entities handled by yl_speak_up that + -- are *not* in the list yet + local liste = {} + for k,v in pairs(minetest.luaentities) do + if(v and v.yl_speak_up and v.yl_speak_up.id + and not(yl_speak_up.npc_list[v.yl_speak_up.id])) then + local dialog = yl_speak_up.load_dialog(v.yl_speak_up.id, nil) + yl_speak_up.update_npc_data(v, dialog, true) + end + end + -- TODO: blocks may also be talked to + + for k, v in pairs(yl_speak_up.npc_list) do + -- possible editors: dialog.n_may_edit[pname] + minetest.chat_send_player(pname, tostring(k).." ".. + tostring(v.name).." "..tostring(v.owner).. + " "..minetest.pos_to_string(v.pos)) + end +end + + +-- at load/reload of the mod: read the list of existing NPC +yl_speak_up.npc_list_load() diff --git a/functions.lua b/functions.lua index f4cb84f..e7b2124 100644 --- a/functions.lua +++ b/functions.lua @@ -674,6 +674,9 @@ function yl_speak_up.talk(self, clicker) self.object:set_animation(self.yl_speak_up.animation) end + -- maintain a list of existing NPC, but do not force saving + yl_speak_up.update_npc_data(self, dialog, false) + yl_speak_up.show_fs(clicker, "talk", {n_id = n_id}) end diff --git a/init.lua b/init.lua index 28b29b4..79ebefa 100644 --- a/init.lua +++ b/init.lua @@ -227,6 +227,9 @@ yl_speak_up.reload = function(modpath, log_entry) -- creating and maintaining quests dofile(modpath .. "fs_quest_gui.lua") + -- show a list of all NPC the player can edit + dofile(modpath .. "fs_npc_list.lua") + -- some general functions that are useful for mobs_redo -- (react to right-click, nametag color etc.) -- only gets loaded if mobs_redo (mobs) exists as mod