yl_speak_up/fs_properties.lua

222 lines
8.3 KiB
Lua

-- Properties for NPC --
-- This is used when an NPC doesn't have a specific dialog but still wants to
-- make use of a (or some) generic dialog(es)
-- helper function:
-- get one property value of the NPC
yl_speak_up.get_one_npc_property = function(pname, property_name)
if(not(pname)) then
return nil
end
-- get just the property data
return yl_speak_up.get_npc_properties(pname, false)[property_name]
end
-- helper function;
-- adds "normal" properties of the npc with a self.<property_name> prefix as well
-- if long_version is not set, a table containing all properties is returned;
-- if long_version *is* set, a table containing the table above plus additional entries is returned
yl_speak_up.get_npc_properties_long_version = function(pname, long_version)
if(not(pname) or not(yl_speak_up.speak_to[pname])) then
return {}
end
local obj = yl_speak_up.speak_to[pname].obj
if(not(obj)) then
return {}
end
local entity = obj:get_luaentity()
if(not(entity)) then
return {}
end
if(not(entity.yl_speak_up)) then
return {}
end
local properties = entity.yl_speak_up.properties
if(not(properties)) then
properties = {}
entity.yl_speak_up.properties = properties
end
-- copy other property data that is stored under self.* over as well (like i.e. self.order for mobs_redo)
for k, v in pairs(entity) do
local t = type(v)
if(t == "string" or t == "number" or t == "boolean") then
properties["self."..tostring(k)] = tostring(v)
end
end
properties["self.name"] = tostring(entity.name)
if(not(long_version)) then
return properties
end
-- the long version contains additional information
local prop_names = {}
for k, v in pairs(properties) do
table.insert(prop_names, k)
end
table.sort(prop_names)
return {obj = obj, entity = entity, properties = properties, prop_names = prop_names}
end
-- most of the time we don't need object, entity or a list of the names of properties;
-- this returns just the properties themshelves
yl_speak_up.get_npc_properties = function(pname)
return yl_speak_up.get_npc_properties_long_version(pname, false)
end
yl_speak_up.set_npc_property = function(pname, property_name, property_value, reason)
if(not(pname) or not(property_name) or property_name == "") then
return "No player name or property name given. Cannot load property data."
end
-- here we want a table with additional information
local property_data = yl_speak_up.get_npc_properties_long_version(pname, true)
if(not(property_data)) then
return "Failed to load property data of NPC."
end
-- it is possible to react to property changes with special custom handlers
if(yl_speak_up.custom_property_handler[property_name]) then
-- the table contains the pointer to a fucntion
local fun = yl_speak_up.custom_property_handler[property_name]
-- call that function with the current values
return fun(pname, property_name, property_value, property_data)
end
-- properties of type self. are not set directly
if(string.sub(property_name, 1, 5) == "self.") then
return "Properties of the type \"self.\" cannot be modified."
end
-- properites starting with "server" can only be changed or added manually by
-- players with the npc_talk_admin priv
if(string.sub(property_name, 1, 6) == "server") then
if(not(reason) or reason ~= "manually" or not(pname)
or not(minetest.check_player_privs(pname, {npc_talk_admin=true}))) then
return "Properties starting with \"server\" can only be changed by players "..
"who have the \"npc_talk_admin\" priv."
end
end
-- store it
if(property_data.entity) then
property_data.entity.yl_speak_up.properties[property_name] = property_value
local n_id = yl_speak_up.speak_to[pname].n_id
yl_speak_up.log_change(pname, n_id, "Property \""..tostring(property_name)..
"\" set to \""..tostring(property_value).."\".")
end
-- TODO: handle non-npc (blocks etc)
return "OK"
end
yl_speak_up.input_properties = function(player, formname, fields)
local pname = player:get_player_name()
if(not(pname) or not(yl_speak_up.speak_to[pname])) then
return
end
local n_id = yl_speak_up.speak_to[pname].n_id
if(fields and fields.back and fields.back ~= "") then
yl_speak_up.show_fs(player, "initial_config",
{n_id = n_id, d_id = yl_speak_up.speak_to[pname].d_id, false})
return
end
local selected_row = nil
if(fields and fields.store_new_val and fields.store_new_val ~= "" and fields.prop_val) then
yl_speak_up.set_npc_property(pname, fields.prop_name, fields.prop_val, "manually")
elseif(fields and fields.delete_prop and fields.delete_prop ~= "") then
-- delete the old property
yl_speak_up.set_npc_property(pname, fields.prop_name, nil, "manually")
elseif(fields and fields.table_of_properties) then
local selected = minetest.explode_table_event(fields.table_of_properties)
if(selected.type == "CHG" or selected.type == "DLC") then
selected_row = selected.row
end
end
yl_speak_up.show_fs(player, "properties", {selected = selected_row})
end
yl_speak_up.get_fs_properties = function(pname, selected)
if(not(pname)) then
return ""
end
local n_id = yl_speak_up.speak_to[pname].n_id
-- is the player editing this npc? if not: abort
if(not(yl_speak_up.edit_mode[pname])
or (yl_speak_up.edit_mode[pname] ~= n_id)) then
return ""
end
-- we want the long version with additional information
local property_data = yl_speak_up.get_npc_properties_long_version(pname, true)
if(not(property_data)) then
-- something went wrong - there really is nothing useful we can do
-- if the NPC we want to interact with doesn't exist or is broken
return
end
local s = ""
if(not(property_data.prop_names)) then
property_data.prop_names = {}
end
local anz_prop = #property_data.prop_names
for i, k in ipairs(property_data.prop_names) do
local v = property_data.properties[k]
s = s.."#BBBBFF,"..minetest.formspec_escape(k)..","..minetest.formspec_escape(v)..","
end
s = s.."#00FF00,add,Add a new property"
if(not(selected) or selected == "") then
selected = -1
end
local add_selected = "label[3.5,6.5;No property selected.]"
selected = tonumber(selected)
if(selected > anz_prop + 1 or selected < 1) then
selected = -1
elseif(selected > anz_prop) then
add_selected = "label[0.2,6.5;Add new property:]"..
"field[3.0,6.5;3.5,1.0;prop_name;;]"..
"label[6.5,6.5;with value:]"..
"field[8.2,6.5;4.5,1.0;prop_val;;]"..
"button[8.2,7.8;2.0,1.0;store_new_val;Store]"
-- external properties can usually only be read but not be changed
elseif(string.sub(property_data.prop_names[selected], 1, 5) == "self."
and not(yl_speak_up.custom_property_handler[property_data.prop_names[selected]])) then
add_selected = "label[3.5,6.5;Properties of the type \"self.\" usually cannot be modified.]"
elseif(string.sub(property_data.prop_names[selected], 1, 6) == "server"
and not(minetest.check_player_privs(pname, {npc_talk_admin=true}))) then
add_selected = "label[3.5,6.5;Properties starting with \"server\" can only be "..
"changed by players\nwho have the \"npc_talk_admin\" priv."
else
local name = property_data.prop_names[selected]
local val = minetest.formspec_escape(property_data.properties[name])
local name_esc = minetest.formspec_escape(name)
add_selected = "label[0.2,6.5;Change property:]"..
"field[3.0,6.5;3.5,1.0;prop_name;;"..name_esc.."]"..
"label[6.5,6.5;to value:]"..
"field[8.2,6.5;4.5,1.0;prop_val;;"..val.."]"..
"button[8.2,7.8;2.0,1.0;store_new_val;Store]"..
"button[10.4,7.8;2.0,1.0;delete_prop;Delete]"
end
if(selected < 1) then
selected = ""
end
local dialog = yl_speak_up.speak_to[pname].dialog
local npc_name = minetest.formspec_escape(dialog.n_npc or "- nameless -")
return "size[12.5,8.5]" ..
"label[2,0;Properties of "..npc_name.." (ID: "..tostring(n_id).."):]"..
"tablecolumns[color,span=1;text;text]"..
"table[0.2,0.5;12,4.0;table_of_properties;"..s..";"..tostring(selected).."]"..
"tooltip[0.2,0.5;12,4.0;"..
"Click on \"add\" to add a new property.\n"..
"Click on the name of a property to change or delete it.]"..
"label[2.0,4.5;"..
"Properties are important for NPC that want to make use of generic dialogs.\n"..
"Properties can be used to determine which generic dialog(s) shall apply to\n"..
"this particular NPC and how they shall be configured. You need the\n"..
"\"npc_talk_admin\" priv to edit properties starting with the text \"server\".]"..
"button[5.0,7.8;2.0,0.9;back;Back]"..
add_selected
end