prepared for /npc_talk list command

This commit is contained in:
Sokomine 2023-07-21 01:10:46 +02:00
parent 124f3cd482
commit e2ecb7de4b
4 changed files with 157 additions and 0 deletions

View File

@ -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 <command>\" with <command> 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"..

148
fs_npc_list.lua Normal file
View File

@ -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()

View File

@ -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

View File

@ -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