From 187416396bfcabaf1c44e9abcab204b952dc62cb Mon Sep 17 00:00:00 2001 From: Sokomine Date: Sun, 19 Jun 2022 19:32:30 +0200 Subject: [PATCH] implemented effect 'property' and prepared effect 'evaluate' --- exec_apply_effects.lua | 144 ++++++++++++++++++++++++++--------------- fs_edit_effects.lua | 89 +++++++++++++++++-------- fs_edit_general.lua | 11 +++- 3 files changed, 162 insertions(+), 82 deletions(-) diff --git a/exec_apply_effects.lua b/exec_apply_effects.lua index 32e80b4..df8958a 100644 --- a/exec_apply_effects.lua +++ b/exec_apply_effects.lua @@ -121,6 +121,68 @@ yl_speak_up.execute_all_relevant_effects = function(player, effects, o_id, actio end +-- helper function for yl_speak_up.execute_effect +-- used by "state" (pname is nil) and "property" (pname is nil) +yl_speak_up.execute_effect_get_new_value = function(r, var_val, pname) + -- for "state" - but not for "property" + if(pname + and (r.r_operator == "quest_step" + or r.r_operator == "maximum" or r.r_operator == "minimum" + or r.r_operator == "increment" or r.r_operator == "decrement")) then + var_val = yl_speak_up.get_quest_variable_value(pname, r.r_variable) + end + -- set the value of the variable + local new_value = nil + if( r.r_operator and r.r_operator == "set_to") then + new_value = r.r_var_cmp_value + elseif(r.r_operator and r.r_operator == "unset") then + new_value = nil + elseif(r.r_operator and r.r_operator == "set_to_current_time") then + -- we store the time in seconds - because microseconds would just + -- confuse the users and be too fine grained anyway + new_value = math.floor(minetest.get_us_time()/1000000) + elseif(r.r_operator and r.r_operator == "quest_step") then + -- quest_step and maximum are effectively the same + -- TODO: later on, quest steps may be strings + if(var_val and tonumber(var_val) and tonumber(r.r_var_cmp_value)) then + new_value = math.max(tonumber(var_val), tonumber(r.r_var_cmp_value)) + else + new_value = r.r_var_cmp_value + end + elseif(r.r_operator and r.r_operator == "maximum") then + if(var_val and tonumber(var_val) and tonumber(r.r_var_cmp_value)) then + new_value = math.max(tonumber(var_val), tonumber(r.r_var_cmp_value)) + else + new_value = r.r_var_cmp_value + end + elseif(r.r_operator and r.r_operator == "minimum") then + if(var_val and tonumber(var_val) and tonumber(r.r_var_cmp_value)) then + new_value = math.min(tonumber(var_val), tonumber(r.r_var_cmp_value)) + else + new_value = r.r_var_cmp_value + end + elseif(r.r_operator and r.r_operator == "increment") then + if(var_val and tonumber(var_val) and tonumber(r.r_var_cmp_value)) then + new_value = tonumber(var_val) + tonumber(r.r_var_cmp_value) + else + new_value = r.r_var_cmp_value + end + elseif(r.r_operator and r.r_operator == "decrement") then + if(var_val and tonumber(var_val) and tonumber(r.r_var_cmp_value)) then + new_value = tonumber(var_val) - tonumber(r.r_var_cmp_value) + else + new_value = -1 * r.r_var_cmp_value + end + else + yl_speak_up.debug_msg(player, n_id, o_id, tostring(r.r_id).." ".. + "state: Unsupported type: "..tostring(r.r_value)..".") + -- keep the old value + new_value = var_val + end + return new_value +end + + -- executes an effect/result r for the player and npc n_id; -- returns true on success (relevant for on_failure) -- Note: In edit mode, this function does not get called. @@ -431,65 +493,43 @@ yl_speak_up.execute_effect = function(player, n_id, o_id, r) return false end local pname = player:get_player_name() - local owner = yl_speak_up.npc_owner[ n_id ] -- set the value of the variable - local new_value = nil - if( r.r_operator and r.r_operator == "set_to") then - new_value = r.r_var_cmp_value - elseif(r.r_operator and r.r_operator == "unset") then - new_value = nil - elseif(r.r_operator and r.r_operator == "set_to_current_time") then - -- we store the time in seconds - because microseconds would just - -- confuse the users and be too fine grained anyway - new_value = math.floor(minetest.get_us_time()/1000000) - elseif(r.r_operator and r.r_operator == "quest_step") then - -- quest_step and maximum are effectively the same - -- TODO: later on, quest steps may be strings - local var_val = yl_speak_up.get_quest_variable_value(pname, r.r_variable) - if(var_value and tonumber(var_val) and tonumber(r.r_var_cmp_value)) then - new_value = math.max(tonumber(var_val), tonumber(r.r_var_cmp_value)) - else - new_value = r.r_var_cmp_value - end - elseif(r.r_operator and r.r_operator == "maximum") then - local var_val = yl_speak_up.get_quest_variable_value(pname, r.r_variable) - if(var_value and tonumber(var_val) and tonumber(r.r_var_cmp_value)) then - new_value = math.max(tonumber(var_val), tonumber(r.r_var_cmp_value)) - else - new_value = r.r_var_cmp_value - end - elseif(r.r_operator and r.r_operator == "minimum") then - local var_val = yl_speak_up.get_quest_variable_value(pname, r.r_variable) - if(var_value and tonumber(var_val) and tonumber(r.r_var_cmp_value)) then - new_value = math.min(tonumber(var_val), tonumber(r.r_var_cmp_value)) - else - new_value = r.r_var_cmp_value - end - elseif(r.r_operator and r.r_operator == "increment") then - local var_val = yl_speak_up.get_quest_variable_value(pname, r.r_variable) - if(var_value and tonumber(var_val) and tonumber(r.r_var_cmp_value)) then - new_value = tonumber(var_val) + tonumber(r.r_var_cmp_value) - else - new_value = r.r_var_cmp_value - end - elseif(r.r_operator and r.r_operator == "decrement") then - local var_val = yl_speak_up.get_quest_variable_value(pname, r.r_variable) - if(var_value and tonumber(var_val) and tonumber(r.r_var_cmp_value)) then - new_value = tonumber(var_val) + tonumber(r.r_var_cmp_value) - else - new_value = -1 * r.r_var_cmp_value - end - else - yl_speak_up.debug_msg(player, n_id, o_id, tostring(r.r_id).." ".. - "state: Unsupported type: "..tostring(r.r_value)..".") - return false - end + local new_value = yl_speak_up.execute_effect_get_new_value(r, nil, pname) -- the owner is already encoded in the variable name local ret = yl_speak_up.set_quest_variable_value(pname, r.r_variable, new_value) yl_speak_up.debug_msg(player, n_id, o_id, tostring(r.r_id).." ".. "state: Success: "..tostring(ret).." for setting "..tostring(r.r_variable).." to ".. tostring(new_value)..".") return ret + -- "the value of a property of the NPC (for generic NPC)", -- property + elseif(r.r_type == "property") then + local pname = player:get_player_name() + local property_data = yl_speak_up.get_npc_properties(pname) + if(not(property_data)) then + yl_speak_up.debug_msg(player, n_id, o_id, tostring(r.r_id).." ".. + "property: Failed to access properties of NPC "..tostring(n_id)) + return false + end + if(not(r.r_value) or r.r_value == "") then + yl_speak_up.debug_msg(player, n_id, o_id, tostring(r.r_id).." ".. + "property: No name of property given") + return false + end + local var_val = property_data.properties[r.r_value] + -- set the value of the variable + local new_value = yl_speak_up.execute_effect_get_new_value(r, var_val, nil) + -- add the new property or change an existing one + property_data.properties[r.r_value] = new_value + -- store it + property_data.entity.yl_speak_up.properties = property_data.properties + yl_speak_up.debug_msg(player, n_id, o_id, tostring(r.r_id).." ".. + "state: Success: Set property "..tostring(r.r_value).." to ".. + tostring(new_value)..".") + return true + -- "something that has to be calculated or evaluated (=call a function)", -- evaluate + elseif(r.r_type == "evaluate") then + -- TODO + return true -- "a block somewhere" -- 3 elseif(r.r_type == "block") then -- is the position given correctly? diff --git a/fs_edit_effects.lua b/fs_edit_effects.lua index c304ac0..c562f7b 100644 --- a/fs_edit_effects.lua +++ b/fs_edit_effects.lua @@ -15,6 +15,17 @@ -- r_var_cmp_value can be set freely by the player (the variable will be -- set to this value) -- +-- the value of a property of the NPC (for generic NPC) ("property"): +-- r_value name of the property that is to be changed +-- r_operator how shall the property be changed? +-- r_var_cmp_value the new value (or increment/decrement) for this property +-- +-- something that has to be calculated or evaluated (=call a function) ("evaluate"): +-- r_value the name of the function that is to be called +-- r_param1 the first paramter (optional; depends on function) +-- .. +-- r_param9 the 9th parameter (optional; depends on function) +-- -- a block in the world ("block"): -- r_pos a position in the world; determined by asking the player -- to punch the block @@ -69,6 +80,8 @@ local check_what = { "- please select -", "an internal state (i.e. of a quest)", -- 2 + "the value of a property of the NPC (for generic NPC)", -- property + "something that has to be calculated or evaluated (=call a function)", -- evaluate "a block somewhere", -- 3 "put item from the NPC's inventory into a chest etc.", -- 4 "take item from a chest etc. and put it into the NPC's inventory", @@ -85,7 +98,8 @@ local check_what = { } -- how to store these as r_type in the precondition: -local values_what = {"", "state", "block", +local values_what = {"", "state", + "property", "evaluate", "block", -- interact with the inventory of blocks on the map "put_into_block_inv", "take_from_block_inv", -- the player gave an item to the NPC; now deal with it somehow @@ -145,6 +159,39 @@ yl_speak_up.get_sorted_player_var_list_write_access = function(pname) end +-- helper function for yl_speak_up.show_effect +-- used by "state" and "property" +yl_speak_up.show_effect_with_operator = function(r, var_name) + if(not(r.r_operator)) then + return "Error: Operator not defined." + elseif(r.r_operator == "set_to") then + return "set "..var_name.." to value \"".. + tostring(r.r_var_cmp_value).."\"" + elseif(r.r_operator == "unset") then + return "discard "..var_name.." (unset)" + elseif(r.r_operator == "set_to_current_time") then + return "set "..var_name.." to the current time" + elseif(r.r_operator == "quest_step") then + return "store that the player has completed quest step \"".. + tostring(r.r_var_cmp_value).."\"" + elseif(r.r_operator == "maximum") then + return "set "..var_name.." to value \"".. + tostring(r.r_var_cmp_value).."\" if its current value is larger than that" + elseif(r.r_operator == "minimum") then + return "set "..var_name.." to value \"".. + tostring(r.r_var_cmp_value).."\" if its current value is lower than that" + elseif(r.r_operator == "increment") then + return "increment the value of "..var_name.." by \"".. + tostring(r.r_var_cmp_value).."\"" + elseif(r.r_operator == "decrement") then + return "decrement the value of "..var_name.." by \"".. + tostring(r.r_var_cmp_value).."\"" + else + return "ERROR: Wrong operator \""..tostring(r.r_operator).."\" for "..var_name + end +end + + -- returns a human-readable text as description of the effects -- (as shown in the edit options dialog and in the edit effect formspec) yl_speak_up.show_effect = function(r, pname) @@ -168,33 +215,21 @@ yl_speak_up.show_effect = function(r, pname) var_name = "VARIABLE[ "..tostring( yl_speak_up.strip_pname_from_var(r.r_variable, pname)).." ]" end - if(not(r.r_operator)) then - return "Error: Operator not defined." - elseif(r.r_operator == "set_to") then - return "set "..var_name.." to value \"".. - tostring(r.r_var_cmp_value).."\"" - elseif(r.r_operator == "unset") then - return "discard "..var_name.." (unset)" - elseif(r.r_operator == "set_to_current_time") then - return "set "..var_name.." to the current time" - elseif(r.r_operator == "quest_step") then - return "store that the player has completed quest step \"".. - tostring(r.r_var_cmp_value).."\"" - elseif(r.r_operator == "maximum") then - return "set "..var_name.." to value \"".. - tostring(r.r_var_cmp_value).."\" if its current value is larger than that" - elseif(r.r_operator == "minimum") then - return "set "..var_name.." to value \"".. - tostring(r.r_var_cmp_value).."\" if its current value is lower than that" - elseif(r.r_operator == "increment") then - return "increment the value of "..var_name.." by \"".. - tostring(r.r_var_cmp_value).."\"" - elseif(r.r_operator == "decrement") then - return "decrement the value of "..var_name.." by \"".. - tostring(r.r_var_cmp_value).."\"" - else - return "ERROR: Wrong operator \""..tostring(r.r_operator).."\" for "..var_name + return yl_speak_up.show_effect_with_operator(r, var_name) + -- the value of a property of the NPC (for generic NPC) ("property"): + elseif(r.r_type == "property") then + local var_name = "PROPERTY[ "..tostring(r.r_value or "- ? -").." ]" + return yl_speak_up.show_effect_with_operator(r, var_name) + -- something that has to be calculated or evaluated (=call a function) ("evaluate"): + elseif(r.r_type == "evaluate") then + local str = "" + for i = 1, 9 do + str = str..tostring(p["r_param" + str(i)]) + if(i < 9) then + str = str.."," + end end + return "FUNCTION["..tostring(r.r_value).."]("..str..")" elseif(r.r_type == "block") then if(not(r.r_pos) or type(r.r_pos) ~= "table" or not(r.r_pos.x) or not(r.r_pos.y) or not(r.r_pos.z)) then diff --git a/fs_edit_general.lua b/fs_edit_general.lua index b7e38b0..17c6479 100644 --- a/fs_edit_general.lua +++ b/fs_edit_general.lua @@ -1387,13 +1387,13 @@ yl_speak_up.get_fs_edit_option_related = function(player, table_click_result, values_operator, check_operator, get_sorted_player_var_list_function ) -- "the value of a property of the NPC (for generic NPC)" - elseif(data.what and what_type == "property" and id_prefix == "p_") then + elseif(data.what and what_type == "property" and id_prefix ~= "a_") then return yl_speak_up.get_fs_edit_option_p_and_e_property( pname, dialog, formspec, data, id_prefix, save_button, e, text_select_operator, values_operator, check_operator) -- "something that has to be calculated or evaluated (=call a function)" - elseif(data.what and what_type == "evaluate" and id_prefix == "p_") then + elseif(data.what and what_type == "evaluate" and id_prefix ~= "a_") then return yl_speak_up.get_fs_edit_option_p_and_e_evaluate( pname, dialog, formspec, data, id_prefix, save_button, e, text_select_operator, values_operator, check_operator) @@ -1611,6 +1611,11 @@ yl_speak_up.get_fs_edit_option_p_and_e_property = function( table.insert(operator_list, v) end end + local text_compare_with = "Compare property with this value:" + if(id_prefix == "r_") then + text_select_operator = "Set property to:" + text_compare_with = "New value:" + end -- the list of available variables needs to be extended with the ones return formspec.. "label[0.2,3.3;The NPC shall have the following property:]".. @@ -1621,7 +1626,7 @@ yl_speak_up.get_fs_edit_option_p_and_e_property = function( "dropdown[7.0,4.8;4.5,0.6;select_operator;".. table.concat(operator_list, ",")..";".. tostring(data.operator)..";]".. - "label[11.7,4.3;Compare property with this value:]".. + "label[11.7,4.3;"..text_compare_with..":]".. field_for_value.. "hypertext[1.2,7.0;16.0,2.5;some_text;".. "Note: Properties are useful for NPC that have a generic "..