821 lines
30 KiB
Lua
821 lines
30 KiB
Lua
|
|
-- just some handling of variables
|
|
|
|
-- TODO: handle read (and write?) access for other players
|
|
-- TODO: add a function to check if the player has read/write access
|
|
-- TODO: mark some vars as "need to be saved" while others are less important (i.e. timestamps)
|
|
|
|
-- the keys are of the form:
|
|
-- $ <blank> <player name> <blank> <variable name> (makes it easier to grant read access)
|
|
-- the values are of the form:
|
|
-- <current player name as key> : <value of variable for that player as value>
|
|
yl_speak_up.player_vars = {}
|
|
|
|
-- store when player_vars was last saved to disc
|
|
yl_speak_up.player_vars_last_save_time = 0
|
|
|
|
-- save the data to disc; either if force_save is set or enough time has passed
|
|
yl_speak_up.save_quest_variables = function(force_save)
|
|
if(not(force_save)
|
|
and (yl_speak_up.player_vars_last_save_time + yl_speak_up.player_vars_min_save_time >
|
|
math.floor(minetest.get_us_time()/1000000))) then
|
|
return
|
|
end
|
|
local json = minetest.write_json( yl_speak_up.player_vars )
|
|
-- actually store it on disk
|
|
minetest.safe_file_write(yl_speak_up.worldpath..yl_speak_up.player_vars_save_file..".json", json)
|
|
end
|
|
|
|
|
|
-- load the data from disc
|
|
yl_speak_up.load_quest_variables = function()
|
|
-- load the data from the file
|
|
local file, err = io.open(yl_speak_up.worldpath..yl_speak_up.player_vars_save_file..".json", "r")
|
|
if err then
|
|
return
|
|
end
|
|
io.input(file)
|
|
local text = io.read()
|
|
-- all values saved in the tables as such are strings
|
|
local data = minetest.parse_json(text, -1)
|
|
io.close(file)
|
|
|
|
if(type(data) ~= "table") then
|
|
return
|
|
end
|
|
for k,v in pairs(data) do
|
|
if(v == -1) then
|
|
data[ k ] = {}
|
|
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()
|
|
|
|
|
|
-- new variables have to be added somehow
|
|
yl_speak_up.add_quest_variable = function(owner_name, variable_name)
|
|
local k = "$ "..tostring(owner_name).." "..tostring(variable_name)
|
|
if(not(owner_name) or not(variable_name)) then
|
|
return false
|
|
end
|
|
-- create a new empty table;
|
|
-- keys will be the names of players for which values are set
|
|
yl_speak_up.player_vars[ k ] = {}
|
|
-- a new variable was created - that deserves a forced save
|
|
yl_speak_up.save_quest_variables(true)
|
|
return true
|
|
end
|
|
|
|
|
|
-- accidentally created or no longer needed variables need to be deleted somehow
|
|
yl_speak_up.del_quest_variable = function(owner_name, variable_name)
|
|
local k = yl_speak_up.restore_complete_var_name(variable_name, owner_name)
|
|
if(not(owner_name) or not(variable_name)) then
|
|
return false
|
|
end
|
|
-- actually delete the variable
|
|
yl_speak_up.player_vars[ k ] = nil
|
|
-- a variable was deleted - that deserves a forced save
|
|
yl_speak_up.save_quest_variables(true)
|
|
return true
|
|
end
|
|
|
|
|
|
-- set the value of a variable used by a player in an NPC;
|
|
-- returns false if the variable cannot be set (i.e. does not exist)
|
|
yl_speak_up.set_quest_variable_value = function(player_name, variable_name, new_value)
|
|
-- the owner name is alrady encoded in the variable name
|
|
local k = tostring(variable_name)
|
|
if(not(variable_name) or not(player_name) or not(yl_speak_up.player_vars[ k ])) then
|
|
return false
|
|
end
|
|
if(new_value ~= nil) then
|
|
new_value = tostring(new_value)
|
|
end
|
|
yl_speak_up.player_vars[ k ][ player_name ] = new_value
|
|
-- a quest variable was changed - save that to disc (but no need to force it)
|
|
yl_speak_up.save_quest_variables(false)
|
|
return true
|
|
end
|
|
|
|
|
|
-- get the value of a variable used by a player in an NPC;
|
|
-- returns nil if the variable does not exist
|
|
yl_speak_up.get_quest_variable_value = function(player_name, variable_name)
|
|
-- the owner name is alrady encoded in the variable name
|
|
local k = tostring(variable_name)
|
|
if(not(variable_name) or not(player_name) or not(yl_speak_up.player_vars[ k ])) then
|
|
return nil
|
|
end
|
|
return yl_speak_up.player_vars[ k ][ player_name ]
|
|
end
|
|
|
|
|
|
yl_speak_up.get_quest_variables = function(pname, has_write_access)
|
|
if(not(pname)) then
|
|
return {}
|
|
end
|
|
local liste = {}
|
|
-- first: list the variables owned by the player
|
|
for k, v in pairs(yl_speak_up.player_vars) do
|
|
local parts = string.split(k, " ")
|
|
if(parts and parts[1] and parts[1] == "$" and parts[2] and parts[2] == pname) then
|
|
table.insert(liste, k)
|
|
end
|
|
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
|
|
for k, v in pairs(yl_speak_up.player_vars) do
|
|
local parts = string.split(k, " ")
|
|
-- variables owned by *other* players
|
|
if(parts and parts[1] and parts[1] == "$" and parts[2] and parts[2] ~= pname) then
|
|
table.insert(liste, k)
|
|
end
|
|
end
|
|
else
|
|
local right = "read_access"
|
|
if(has_write_access) then
|
|
right = "write_access"
|
|
end
|
|
-- insert those vars owned by other players where this one has access
|
|
for k, v in pairs(yl_speak_up.player_vars) do
|
|
if( k[ "$META$"]
|
|
and k[ "$META$"][ right ]
|
|
and k[ "$META$"][ right ][ pname ]) then
|
|
table.insert(liste, k)
|
|
end
|
|
end
|
|
end
|
|
table.sort(liste)
|
|
return liste
|
|
end
|
|
|
|
|
|
-- which variables can player pname read and use in preconditions?
|
|
-- returns a sorted list
|
|
yl_speak_up.get_quest_variables_with_read_access = function(pname)
|
|
return yl_speak_up.get_quest_variables(pname, false)
|
|
end
|
|
|
|
|
|
-- which variables can player pname write and use in effects/results?
|
|
yl_speak_up.get_quest_variables_with_write_access = function(pname)
|
|
return yl_speak_up.get_quest_variables(pname, true)
|
|
end
|
|
|
|
|
|
yl_speak_up.input_fs_manage_variables = function(player, formname, fields)
|
|
local pname = player:get_player_name()
|
|
if(fields and fields.back_from_msg) then
|
|
yl_speak_up.show_fs(player, "manage_variables")
|
|
return
|
|
end
|
|
-- leave this formspec
|
|
if(fields and (fields.quit or fields.exit or fields.back)) then
|
|
local last_fs = yl_speak_up.speak_to[pname][ "working_at" ]
|
|
yl_speak_up.show_fs(player, last_fs)
|
|
return
|
|
-- add a new variable?
|
|
elseif(fields and fields.add_variable) then
|
|
local error_msg = ""
|
|
if(not(fields.add_variable_name) or fields.add_variable_name == ""
|
|
or fields.add_variable_name:trim() == "") then
|
|
error_msg = "Please enter the name of your variable!"
|
|
-- limit names to something more sensible
|
|
elseif(string.len(fields.add_variable_name) > 30) then
|
|
error_msg = "The name of your variable name is too long.\n"..
|
|
"Only up to 30 characters are allowed."
|
|
elseif(string.len(fields.add_variable_name:trim()) < 2) then
|
|
error_msg = "The name of your variable name is too short.\n"..
|
|
"It has to be at least 2 characters long."
|
|
else
|
|
fields.add_variable_name = fields.add_variable_name:trim()
|
|
local res = yl_speak_up.add_quest_variable(pname, fields.add_variable_name)
|
|
-- not really an error msg here - but fascilitates output
|
|
error_msg = "A new variable named\n \""..
|
|
minetest.formspec_escape(fields.add_variable_name)..
|
|
"\"\nhas been created."
|
|
if(not(res)) then
|
|
error_msg = "Failed to create variable named\n \""..
|
|
minetest.formspec_escape(fields.add_variable_name).."\"."
|
|
else
|
|
-- slect this new variable
|
|
local var_list = yl_speak_up.get_quest_variables(pname, true)
|
|
-- make names of own variables shorter
|
|
yl_speak_up.strip_pname_from_varlist(var_list, pname)
|
|
table.sort(var_list)
|
|
local index = table.indexof(var_list, fields.add_variable_name)
|
|
if(index and index > -1) then
|
|
yl_speak_up.speak_to[pname].tmp_index_variable = index + 1
|
|
end
|
|
end
|
|
end
|
|
yl_speak_up.show_fs(player, "msg", {
|
|
input_to = "yl_speak_up:manage_variables",
|
|
formspec = "size[6,2]"..
|
|
"label[0.2,0.0;"..error_msg.."]"..
|
|
"button[1.5,1.5;2,0.9;back_from_msg;Back]"})
|
|
return
|
|
-- show where this variable is used
|
|
elseif(fields and fields.show_var_usage and fields.show_var_usage ~= "") then
|
|
yl_speak_up.show_fs(player, "msg", {
|
|
input_to = "yl_speak_up:manage_variables",
|
|
formspec = yl_speak_up.get_list_of_usage_of_variable(
|
|
fields.list_var_names, pname, true,
|
|
"back_from_msg",
|
|
"Back to manage variables",
|
|
-- not an internal variable
|
|
false)
|
|
})
|
|
return
|
|
end
|
|
|
|
-- which variable is currently selected?
|
|
local var_list = yl_speak_up.get_quest_variables(pname, true)
|
|
-- make names of own variables shorter
|
|
yl_speak_up.strip_pname_from_varlist(var_list, pname)
|
|
table.sort(var_list)
|
|
-- a var name was selected in the dropdown list
|
|
if(fields and fields.list_var_names and fields.list_var_names ~= "") then
|
|
local index = table.indexof(var_list, fields.list_var_names)
|
|
if(fields.list_var_names == "Add variable:") then
|
|
index = 0
|
|
end
|
|
if(index and index > -1) then
|
|
yl_speak_up.speak_to[pname].tmp_index_variable = index + 1
|
|
end
|
|
end
|
|
local var_name = var_list[ yl_speak_up.speak_to[pname].tmp_index_variable ]
|
|
|
|
-- revoke read or write access to a variable
|
|
if(fields
|
|
and ((fields.revoke_player_var_read_access and fields.revoke_player_var_read_access ~= "")
|
|
or (fields.revoke_player_var_write_access and fields.revoke_player_var_write_access ~= ""))
|
|
and var_name) then
|
|
local right = "read"
|
|
if(fields.revoke_player_var_write_access and fields.revoke_player_var_write_access ~= "") then
|
|
right = "write"
|
|
end
|
|
-- which player are we talking about?
|
|
local selected = yl_speak_up.speak_to[pname]["tmp_index_var_"..right.."_access"]
|
|
local pl_with_access = yl_speak_up.get_access_list_for_var(var_name, pname, right.."_access")
|
|
local tmp_list = {}
|
|
for k, v in pairs(pl_with_access) do
|
|
table.insert(tmp_list, k)
|
|
end
|
|
table.sort(tmp_list)
|
|
local grant_to = ""
|
|
if(selected > 1) then
|
|
grant_to = tmp_list[ selected-1 ]
|
|
end
|
|
local error_msg = ""
|
|
local pl_with_access = yl_speak_up.get_access_list_for_var(var_name, pname, right.."_access")
|
|
if(not(grant_to) or grant_to == "") then
|
|
error_msg = "For which player do you want to revoke "..right.." access?"
|
|
elseif(pname ~= yl_speak_up.npc_owner[ n_id ]
|
|
and not(minetest.check_player_privs(pname, {npc_talk_master=true}))) then
|
|
error_msg = "Only the owner of the NPC or players with\n"..
|
|
"the npc_talk_master priv can change this."
|
|
elseif(not(pl_with_access[ grant_to ])) then
|
|
error_msg = minetest.formspec_escape(grant_to).." doesn't have "..right..
|
|
" access\nto this variable. Nothing changed."
|
|
-- try to revoke access
|
|
elseif(not(yl_speak_up.manage_access_to_quest_variable(var_name, pname, grant_to,
|
|
right.."_access", nil))) then
|
|
error_msg = "An internal error occoured."
|
|
else
|
|
-- not really an error message here...rather a success message
|
|
error_msg = "Revoked "..right.." access to variable\n\""..
|
|
minetest.formspec_escape(var_name)..
|
|
"\"\nfor player "..minetest.formspec_escape(grant_to)..".\n"..
|
|
"Note: This will *not* affect existing preconditions/effects!"
|
|
end
|
|
yl_speak_up.show_fs(player, "msg", {
|
|
input_to = "yl_speak_up:manage_variables",
|
|
formspec = "size[6,2]"..
|
|
"label[0.2,0.0;"..error_msg.."]"..
|
|
"button[1.5,1.5;2,0.9;back_from_msg;Back]"})
|
|
return
|
|
|
|
-- grant read or write access to a variable
|
|
elseif(fields
|
|
and ((fields.grant_player_var_read_access and fields.grant_player_var_read_access ~= "")
|
|
or (fields.grant_player_var_write_access and fields.grant_player_var_write_access ~= ""))
|
|
and var_name) then
|
|
local right = "read"
|
|
if(fields.grant_player_var_write_access and fields.grant_player_var_write_access ~= "") then
|
|
right = "write"
|
|
end
|
|
local grant_to = fields[ "grant_player_var_"..right.."_access"]
|
|
local error_msg = ""
|
|
local pl_with_access = yl_speak_up.get_access_list_for_var(var_name, pname, right.."_access")
|
|
if(pname ~= yl_speak_up.npc_owner[ n_id ]
|
|
and not(minetest.check_player_privs(pname, {npc_talk_master=true}))) then
|
|
error_msg = "Only the owner of the NPC or players with\n"..
|
|
"the npc_talk_master priv can change this."
|
|
elseif(grant_to == pname) then
|
|
error_msg = "You already have "..right.." access to this variable."
|
|
elseif(pl_with_access[ grant_to ]) then
|
|
error_msg = minetest.formspec_escape(grant_to).." already has "..right..
|
|
" access\nto this variable."
|
|
elseif(not(minetest.check_player_privs(grant_to, {interact=true}))) then
|
|
error_msg = "Player \""..minetest.formspec_escape(grant_to).."\" not found."
|
|
-- try to grant access
|
|
elseif(not(yl_speak_up.manage_access_to_quest_variable(var_name, pname, grant_to,
|
|
right.."_access", true))) then
|
|
error_msg = "An internal error occoured."
|
|
else
|
|
-- not really an error message here...rather a success message
|
|
error_msg = "Granted "..right.." access to variable\n\""..
|
|
minetest.formspec_escape(var_name)..
|
|
"\"\nto player "..minetest.formspec_escape(grant_to).."."
|
|
end
|
|
yl_speak_up.show_fs(player, "msg", {
|
|
input_to = "yl_speak_up:manage_variables",
|
|
formspec = "size[6,2]"..
|
|
"label[0.2,0.0;"..error_msg.."]"..
|
|
"button[1.5,1.5;2,0.9;back_from_msg;Back]"})
|
|
return
|
|
|
|
-- the player clicked on a name in the list of players with read or write access
|
|
elseif(fields
|
|
and ((fields.list_var_read_access and fields.list_var_read_access ~= "")
|
|
or (fields.list_var_write_access and fields.list_var_write_access ~= ""))
|
|
and var_name) then
|
|
local right = "read"
|
|
if(fields.list_var_write_access and fields.list_var_write_access ~= "") then
|
|
right = "write"
|
|
end
|
|
local selected = fields[ "list_var_"..right.."_access"]
|
|
local pl_with_access = yl_speak_up.get_access_list_for_var(var_name, pname, right.."_access")
|
|
local tmp_list = {}
|
|
for k, v in pairs(pl_with_access) do
|
|
table.insert(tmp_list, k)
|
|
end
|
|
table.sort(tmp_list)
|
|
local index = table.indexof(tmp_list, selected)
|
|
if(selected == "Add player:") then
|
|
index = 0
|
|
end
|
|
if(index and index > -1) then
|
|
yl_speak_up.speak_to[pname]["tmp_index_var_"..right.."_access"] = index + 1
|
|
end
|
|
yl_speak_up.show_fs(player, "manage_variables")
|
|
return
|
|
|
|
-- TODO: delete variable
|
|
-- a var name was selected in the dropdown list
|
|
elseif(fields and fields.list_var_names and fields.list_var_names ~= "") then
|
|
-- show the same formspec again, with a diffrent variable selected
|
|
yl_speak_up.show_fs(player, "manage_variables")
|
|
return
|
|
end
|
|
-- try to go back to the last formspec shown before this one
|
|
if(not(yl_speak_up.speak_to[pname])) then
|
|
return
|
|
end
|
|
local last_fs = yl_speak_up.speak_to[pname][ "working_at" ]
|
|
yl_speak_up.show_fs(player, last_fs)
|
|
end
|
|
|
|
|
|
yl_speak_up.get_fs_manage_variables = function(player, param)
|
|
local pname = player:get_player_name()
|
|
-- variables owned by the player - including those with write access
|
|
local var_list = yl_speak_up.get_quest_variables(pname, true)
|
|
-- make names of own variables shorter
|
|
yl_speak_up.strip_pname_from_varlist(var_list, pname)
|
|
-- the yl_speak_up.create_dropdown_playerlist function needs a table - not a list
|
|
local table_of_vars = {}
|
|
for i, k in ipairs(var_list) do
|
|
table_of_vars[ k ] = true
|
|
end
|
|
-- "Add variable:" is currently selected
|
|
local additional_buttons = ""
|
|
if(not(yl_speak_up.speak_to[pname].tmp_index_variable)
|
|
or yl_speak_up.speak_to[pname].tmp_index_variable == 1) then
|
|
yl_speak_up.speak_to[pname].tmp_index_variable = 1
|
|
additional_buttons = "button[11.4,1.9;2.5,0.9;add_variable;Create variable]"..
|
|
"tooltip[add_variable;Create a new varialbe with the name\n"..
|
|
"you entered in the field to the left.]"
|
|
else
|
|
local k = var_list[ yl_speak_up.speak_to[pname].tmp_index_variable ]
|
|
local pl_with_read_access = yl_speak_up.get_access_list_for_var(k, pname, "read_access")
|
|
local pl_with_write_access = yl_speak_up.get_access_list_for_var(k, pname, "write_access")
|
|
local add_read_button = ""
|
|
local add_write_button = ""
|
|
if(not(yl_speak_up.speak_to[pname].tmp_index_var_read_access)
|
|
or yl_speak_up.speak_to[pname].tmp_index_var_read_access == 1) then
|
|
yl_speak_up.speak_to[pname].tmp_index_var_read_access = 1
|
|
add_read_button = "button[12.9,2.9;1.0,0.9;add_read_access;Add]"..
|
|
"tooltip[add_read_access;Grant the player whose name you entered\n"..
|
|
"you entered in the field to the left read access\n"..
|
|
"to your variable.]"
|
|
end
|
|
if(not(yl_speak_up.speak_to[pname].tmp_index_var_write_access)
|
|
or yl_speak_up.speak_to[pname].tmp_index_var_write_access == 1) then
|
|
yl_speak_up.speak_to[pname].tmp_index_var_write_access = 1
|
|
add_write_button = "button[12.9,3.9;1.0,0.9;add_write_access;Add]"..
|
|
"tooltip[add_write_access;Grant the player whose name you entered\n"..
|
|
"you entered in the field to the left *write* access\n"..
|
|
"to your variable.]"
|
|
end
|
|
additional_buttons = "button[11.4,1.9;2.5,0.9;show_var_usage;Where is it used?]"..
|
|
"tooltip[show_var_usage;Show which NPC use this variable in which context.]"..
|
|
-- offer a dropdown list and a text input field for new varialbe names for adding
|
|
"label[0.2,3.05;Players with read access to this variable:]"..
|
|
yl_speak_up.create_dropdown_playerlist(player, pname,
|
|
pl_with_read_access,
|
|
yl_speak_up.speak_to[pname].tmp_index_var_read_access,
|
|
5.5, 2.9, 0.0, "list_var_read_access", "player", "Remove player from list",
|
|
"grant_player_var_read_access",
|
|
"Enter the name of the player that shall\n"..
|
|
"have read access to this variable.",
|
|
"revoke_player_var_read_access",
|
|
"If you click here, the selected player\n"..
|
|
"will no longer be able to add new\n"..
|
|
"pre(C)onditions which read your variable."
|
|
)..add_read_button..
|
|
"label[0.2,4.05;Players with *write* access to this variable:]"..
|
|
yl_speak_up.create_dropdown_playerlist(player, pname,
|
|
pl_with_write_access,
|
|
yl_speak_up.speak_to[pname].tmp_index_var_write_access,
|
|
5.5, 3.9, 0.0, "list_var_write_access", "player", "Remove player from list",
|
|
"grant_player_var_write_access",
|
|
"Enter the name of the player that shall\n"..
|
|
"have *write* access to this variable.",
|
|
"revoke_player_var_write_access",
|
|
"If you click here, the selected player\n"..
|
|
"will no longer be able to *write* new\n"..
|
|
"values into this variable."
|
|
)..add_write_button..
|
|
"label[0.2,5.05;Type of variable: "..
|
|
-- TODO: show actual type
|
|
minetest.colorize("#FFFF00","String/text or numerical value, depending "..
|
|
"on how you use it")..".]"
|
|
end
|
|
return "size[14,6.5]"..
|
|
"label[5.0,0.0;* Manage your variables *]"..
|
|
"label[0.2,0.8;Note: Each variable will store a diffrent value for each player who "..
|
|
"interacts with the NPC.\n"..
|
|
"You can grant read and write access to other players for your "..
|
|
"variables so that they can also use them as well.]"..
|
|
"label[0.2,2.05;Your variables:]"..
|
|
-- offer a dropdown list and a text input field for new varialbe names for adding
|
|
yl_speak_up.create_dropdown_playerlist(player, pname,
|
|
table_of_vars, yl_speak_up.speak_to[pname].tmp_index_variable,
|
|
2.2, 1.9, 1.0, "list_var_names", "variable", "Delete selected variable",
|
|
"add_variable_name",
|
|
"Enter the name of the new variable you\n"..
|
|
"want to create.",
|
|
"delete_variable",
|
|
"If you click here, the selected variable\n"..
|
|
"will be deleted."
|
|
)..
|
|
additional_buttons..
|
|
"button[0.0,0.2;1.0,0.6;back;Back]"..
|
|
"button[6.0,6.0;1.0,0.6;back;Back]"
|
|
end
|
|
|
|
|
|
-- variables are personalized; they are prefixed by "$ <PLAYER_NAME> <VAR_NAME>"
|
|
|
|
-- helper function;
|
|
-- strip "$ PNAME " from variable names (but only for those owned by player with name pname)
|
|
yl_speak_up.strip_pname_from_var = function(var_name, pname)
|
|
local parts = string.split(var_name, " ")
|
|
if(parts and parts[1] and parts[1] == "$" and parts[2] and parts[2] == pname) then
|
|
table.remove(parts, 1) -- remove "$"
|
|
table.remove(parts, 1) -- remove pname
|
|
return table.concat(parts, " ")
|
|
end
|
|
return var_name
|
|
end
|
|
|
|
|
|
-- does the opposite of the function above; adds "$ PNAME " if needed
|
|
yl_speak_up.add_pname_to_var = function(var_name, pname)
|
|
if(not(var_name)) then
|
|
return ""
|
|
end
|
|
local parts = string.split(var_name, " ")
|
|
if(parts and parts[1] and parts[1] ~= "$") then
|
|
return "$ "..tostring(pname).." "..tostring(var_name)
|
|
end
|
|
return var_name
|
|
end
|
|
|
|
|
|
-- helper function for yl_speak_up.input_fs_edit_option_related
|
|
-- and yl_speak_up.get_fs_edit_option_p_and_e_state
|
|
yl_speak_up.strip_pname_from_varlist = function(var_list, pname)
|
|
local var_list_text = ""
|
|
-- strip pname from the variable names
|
|
for i, v in ipairs(var_list) do
|
|
var_list[i] = yl_speak_up.strip_pname_from_var(v, pname)
|
|
-- useful for presenting a list
|
|
var_list_text = var_list_text..","..minetest.formspec_escape(tostring(var_list[i]))
|
|
end
|
|
return var_list_text
|
|
end
|
|
|
|
|
|
-- (partly) the opposite of the function above - add the name of the player to a variable
|
|
-- name again if needed
|
|
yl_speak_up.restore_complete_var_name = function(var_name, pname)
|
|
local vparts = string.split(var_name or "", " ")
|
|
-- has the player name been stripped from the variable name for better readability?
|
|
if(vparts and #vparts > 0 and vparts[1] ~= "$") then
|
|
return "$ "..tostring(pname).." "..table.concat(vparts, " ")
|
|
end
|
|
return var_name
|
|
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
|
|
|
|
|
|
-- add or revoke read or write access to a variable
|
|
--
|
|
-- k: name of the variable
|
|
-- pname: the name of the player trying to grant or revoke the right
|
|
-- grant_to_pname: the name of the player who shall have that access right
|
|
-- grant_write_access:
|
|
-- if false: grant read access
|
|
-- if true: grant write access
|
|
-- do_grant:
|
|
-- if false: revoke acces
|
|
-- if true: grant access
|
|
-- returns true if the variable was found
|
|
yl_speak_up.manage_access_to_quest_variable = function(k, pname, grant_to_pname, what_to_grant, do_grant)
|
|
k = yl_speak_up.add_pname_to_var(k, pname)
|
|
-- grant or revoke priv
|
|
if(not(do_grant)) then
|
|
do_grant = nil
|
|
end
|
|
-- only read and write access can be granted
|
|
if(not(what_to_grant) or (what_to_grant ~= "read_access" and what_to_grant ~= "write_access")) then
|
|
return false
|
|
end
|
|
-- the variable needs to exist
|
|
if(not(yl_speak_up.player_vars[ k ])) then
|
|
return false
|
|
end
|
|
-- make sure all the necessary tables exist
|
|
if(not(yl_speak_up.player_vars[ k ][ "$META$" ])) then
|
|
yl_speak_up.player_vars[ k ][ "$META$"] = { what_to_grant = {} }
|
|
end
|
|
if(not(yl_speak_up.player_vars[ k ][ "$META$" ][ what_to_grant ])) then
|
|
yl_speak_up.player_vars[ k ][ "$META$" ][ what_to_grant ] = {}
|
|
end
|
|
yl_speak_up.player_vars[ k ][ "$META$"][ what_to_grant ][ grant_to_pname ] = do_grant
|
|
yl_speak_up.save_quest_variables(true)
|
|
return true
|
|
end
|
|
|
|
|
|
-- get a list of all players who have read or write access to variable k (belonging to pname)
|
|
-- (technically a table and not a list)
|
|
yl_speak_up.get_access_list_for_var = function(k, pname, access_what)
|
|
k = yl_speak_up.add_pname_to_var(k, pname)
|
|
if(not(k)
|
|
or not(yl_speak_up.player_vars[ k ])
|
|
or not(yl_speak_up.player_vars[ k ][ "$META$"])
|
|
or not(yl_speak_up.player_vars[ k ][ "$META$"][ access_what ])) then
|
|
return {}
|
|
end
|
|
return yl_speak_up.player_vars[ k ][ "$META$"][ access_what ]
|
|
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
|
|
-- TODO: show this data in a formspec to admins for maintenance
|
|
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 ]),
|
|
may_edit = dialog.n_may_edit or {},
|
|
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
|
|
|
|
|
|
-- which NPC do use this variable?
|
|
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
|
|
|
|
|
|
-- find out where this variable is used in NPCs
|
|
yl_speak_up.get_list_of_usage_of_variable = function(var_name, pname, check_preconditions,
|
|
back_button_name, back_button_text, is_internal_var)
|
|
-- TODO: check if the player really has read access to this variable
|
|
if(not(is_internal_var)) then
|
|
var_name = yl_speak_up.restore_complete_var_name(var_name, pname)
|
|
end
|
|
-- which NPC (might be several) is using this variable?
|
|
-- TODO: ..or if the player at least is owner of these NPC or has extended privs
|
|
local npc_list = yl_speak_up.get_npc_users_of_variable(var_name)
|
|
-- list of all relevant preconditions, actions and effects
|
|
local res = {}
|
|
local count_read = 0
|
|
local count_changed = 0
|
|
for i, n_id in ipairs(npc_list) do
|
|
-- the NPC may not even be loaded
|
|
local dialog = yl_speak_up.load_dialog(n_id)
|
|
if(dialog and dialog.n_dialogs) then
|
|
for d_id, d in pairs(dialog.n_dialogs) do
|
|
if(d and d.d_options) then
|
|
for o_id, o in pairs(d.d_options) do
|
|
local p_text = ""
|
|
local r_text = ""
|
|
local sort_value = 0
|
|
if(o and o.o_prerequisites and check_preconditions) then
|
|
for p_id, p in pairs(o.o_prerequisites) do
|
|
if(p and p.p_type and p.p_type == "state"
|
|
and p.p_variable and p.p_variable == var_name) then
|
|
p_text = p_text..yl_speak_up.print_as_table_precon(p,pname)
|
|
sort_value = (p.p_var_cmp_value or 0)
|
|
count_read = count_read + 1
|
|
end
|
|
end
|
|
end
|
|
if(o and o.o_results) then
|
|
for r_id, r in pairs(o.o_results) do
|
|
if(r and r.r_type and r.r_type == "state"
|
|
and r.r_variable and r.r_variable == var_name) then
|
|
r_text = r_text..yl_speak_up.print_as_table_effect(r,pname)
|
|
-- values set in the results are more important than
|
|
-- those set in preconditions
|
|
sort_value = (r.r_var_cmp_value or 0)
|
|
count_changed = count_changed + 1
|
|
end
|
|
end
|
|
end
|
|
-- if preconditions or effects apply: show the action as well
|
|
if(o and o.actions and (p_text ~= "" or r_text ~= "")) then
|
|
for a_id, a in pairs(o.actions) do
|
|
-- no need to introduce an a_text; this will follow
|
|
-- directly after p_text, and p_text is finished
|
|
p_text = p_text..yl_speak_up.print_as_table_action(a, pname)
|
|
end
|
|
end
|
|
yl_speak_up.print_as_table_dialog(p_text, r_text, dialog,
|
|
n_id, d_id, o_id, res, o, sort_value)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local formspec = yl_speak_up.print_as_table_prepare_formspec(res, "table_of_variable_uses",
|
|
back_button_name, back_button_text)
|
|
table.insert(formspec,
|
|
"label[20.0,1.8;"..
|
|
minetest.formspec_escape("Variable \""..
|
|
minetest.colorize("#FFFF00", tostring(var_name or "- ? -"))..
|
|
"\" is used here:").."]")
|
|
|
|
if(count_read > 0 or count_changed > 0) then
|
|
table.insert(formspec,
|
|
"label[16.0,31.0;The variable is accessed in "..
|
|
minetest.colorize("#FFFF00", tostring(count_read).." pre(C)onditions")..
|
|
" and changed in "..
|
|
minetest.colorize("#55FF55", tostring(count_changed).." (Ef)fects")..
|
|
".]")
|
|
elseif(not(is_internal_var)) then
|
|
-- TODO: make delete_unused_variable work
|
|
table.insert(formspec,
|
|
"button[0.2,30.6;56.6,1.2;delete_unused_variable;"..
|
|
minetest.formspec_escape("Delete this unused variable \""..
|
|
tostring(var_name or "- ? -")).."\".]")
|
|
else
|
|
table.insert(formspec,
|
|
"label[16.0,31.0;This is an internal variable and cannot be deleted.]")
|
|
end
|
|
return table.concat(formspec, "\n")
|
|
end
|