From 445e664f0dc84ea3e17a73400dad429b76678db4 Mon Sep 17 00:00:00 2001 From: Noodlemire Date: Sat, 15 Aug 2020 18:43:47 -0500 Subject: [PATCH] Update 1.0.1 --- api.txt | 7 ++- changelog.txt | 5 ++ init.lua | 168 ++++++++++++++++++++++++++------------------------ 3 files changed, 97 insertions(+), 83 deletions(-) create mode 100644 changelog.txt diff --git a/api.txt b/api.txt index 4f08443..08aefad 100644 --- a/api.txt +++ b/api.txt @@ -8,13 +8,16 @@ node_damage.damage(pos, node, digger, num) --or left on the ground. pos: The location of the node to damage node: The node itself to damage. This is optional. It can be provided if available, but this function can get the node itself. - digger: Optional; the person who is damaging this node. + digger: Optional; the person who is damaging this node. Used to determine protection permission. num: Optional; the amount of times to damage this node. If its 3 or more, the node will always be destroyed. + --Returns a boolean indicating success. -node_damage.repair(pos, node, num) +node_damage.repair(pos, node, fixer, num) --Remove damage from this node, and set it into the previous stage of cracking. --For reference, there are four stages in total, including the stage without damage at all. --If the node is already fully repaired, nothing will happen. pos: The location of the node to repair node: The node itself to damage. This is optional. It can be provided if available, but this function can get the node itself. + fixer: Optional; A person (ObjectRef) who is repairing this node. Used to determine protection permission. num: Optional; the amount of times to repair this node. If its 3 or more, the node will always be fully repaired. + --Returns a boolean indicating success. diff --git a/changelog.txt b/changelog.txt new file mode 100644 index 0000000..d15c634 --- /dev/null +++ b/changelog.txt @@ -0,0 +1,5 @@ +1.0.1: + +node_damage.damage() and node_damage.repair() now return a boolean value to indicate success. + -Removed the need to reload the world a second time whenever new nodes are introduced. Now, the override character ":" is used to skip prohibitive modname checks. + -Prevented the use of node damaging and repair tools on nodes that are protected from the user, or are otherwise not meant to be broken. + -Fixed issue where node_damage.repair() with a num greater than 1 would start damaging nodes. diff --git a/init.lua b/init.lua index 3c7c327..8eaf59a 100644 --- a/init.lua +++ b/init.lua @@ -20,73 +20,45 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA --mod-specific global storage node_damage = {} ---Get mod-private storage, which is used to remember what nodes will exist. -local store = minetest.get_mod_storage() - ---A list of nodes to define. Nodes added by this mod are initialized with an empty definition, ---so that override_item can be used when all other nodes are registered. -local queue = {} - --Get the node_damage version of an item's name. --In the original name, the comma is gsubbed into an underscore in order to comply with naming standards. local function get_node_damage_name(name, i) return "node_damage:"..(name:gsub(":", "_")).."_"..i end ---For each item name that was previously saved... -for name in pairs(store:to_table().fields) do - --Add it to the queue. - queue[name] = true - - --Also, add the three other stages of cracking to the queue after registering them with blank definitions. - for i = 1, 3 do - minetest.register_node(get_node_damage_name(name, i), {}) - queue[get_node_damage_name(name, i)] = true - end -end - --Check if any particular node is valid for crackification. -local function node_is_valid(name, can_be_in_queue) +local function node_is_valid(name) --Get the existing definition for this item. local def = minetest.registered_items[name] - --If this item isn't in the queue, it is nil, rather than false. - --So, if can_be_in_queue was left as false, this function would always return false. - if can_be_in_queue == false then - can_be_in_queue = nil - end - --Return true if all of the following is true: --The definition exists - --Either an entry in the queue exists and it can be in the queue, or there is no queue entry and it can't be in the queue. --This item is not something that would immediately be dug up anyways --This item isn't already cracked --This item is a node --This item doesn't originate from this mod. --This item can be destroyed --This item is visible - return (def and queue[name] == can_be_in_queue and minetest.get_item_group(name, "dig_immediate") == 0 + return (def and minetest.get_item_group(name, "dig_immediate") == 0 and minetest.get_item_group(name, "node_damage") == 0 and def.type == "node" and def.mod_origin ~= "node_damage" and def.diggable and def.drawtype ~= "airlike") end --Once every mod has loaded and therefore every node has been registered... minetest.register_on_mods_loaded(function() - --For each node name in the queue... - for name in pairs(queue) do - --As long as the node is still valid - if node_is_valid(name, true) then - --Override the node to tell it which node to place when damaged. - local def = {node_damaged_name = get_node_damage_name(name, 1)} - minetest.override_item(name, def) + --For each registered item... + for name, def in pairs(minetest.registered_items) do + --If there's a valid node... + if node_is_valid(name) then + local ndef = {node_damaged_name = get_node_damage_name(name, 1)} + minetest.override_item(name, ndef) --For each of the cracked stages... for i = 1, 3 do --Copy the base node's definition and remove information from the copy that can't be overridden. def = table.copy(minetest.registered_items[name]) - def.name = nil - def.type = nil - def.mod_origin = nil + --def.name = get_node_damage_name(name, i) + --def.mod_origin = "node_damage" --Give it the not_in_creative_inventory and node_damage groups --The exact number of node_damage can be used to know how damaged a node is. @@ -139,31 +111,12 @@ minetest.register_on_mods_loaded(function() break end - --Finally, override the cracked node's empty definition with the base node's altered definition. - minetest.override_item(get_node_damage_name(name, i), def) + --Finally, forcefully register a new node while skipping the mod name prefix check, + --in order for it to work after all mods have been loaded. + minetest.register_node(":"..get_node_damage_name(name, i), def) end end end - - --This remembers if the player should be told to reload the world or not. - local reload_msg = false - - --For each registered item... - for name, def in pairs(minetest.registered_items) do - --If there's a valid node that wasn't in the queue... - if node_is_valid(name) then - --Know that the reload message should be displayed. - reload_msg = true - - --Remember the name of this newly added node. - store:set_int(name, 1) - end - end - - --If a reload message should be displayed, show it. - if reload_msg then - minetest.log("New nodes have been added to the game. Please reload to enable them to use the Node Damage and Repair System.") - end end) @@ -171,64 +124,117 @@ end) --A function to damage a given node, as long as that's possible. --pos: The location of the node to damage. --node: Optional; the node itself. It there's already data, you can pass it along to save time, but this function can grab the data itself. ---digger: Optional; A person who is attacking this node. If its destroyed, that person will pick it up. +--digger: Optional; A person (ObjectRef) who is attacking this node. If its destroyed, that person will pick it up. --num: Optional, defaults to 1; The amount of times to damage this node. 3 will destroy any node_damage node. +--Returns a boolean indicating success. function node_damage.damage(pos, node, digger, num) --If the node itself wasn't provided, grab it from the provided position if not node then node = minetest.get_node(pos) end + --By default, assume that there is no player directly causing the damage. + local pname = "" + + --If there is a player, get that player's name instead. + if digger then + pname = digger:get_player_name() + end + + --If this node is protected, fail. + if minetest.is_protected(pos, pname) then + return false + end + --Get the node's definition local def = minetest.registered_items[node.name] - --If the definition exists... - if def then - --If it defines a next stage of damage, swap to that next stage. - if def.node_damaged_name and minetest.registered_items[def.node_damaged_name] then - minetest.swap_node(pos, {name = def.node_damaged_name}) - --Otherwise, if it doesn't because it's in the last stage of damage, destroy the node. - elseif def.groups.node_damage == 3 then - --If a digger was provided, use node_dig to give the node to them. - if digger then - minetest.node_dig(pos, node, digger) - --Otherwise, use the standard dig_node. This leaves the drops on the ground. - else - minetest.dig_node(pos, node) - end + --If the def has no definition or specifies that it can't be dug right now, fail. + if not def or (def.can_dig and def.can_dig()) then + return false + end + + --If it defines a next stage of damage, swap to that next stage. + if def.node_damaged_name and minetest.registered_items[def.node_damaged_name] then + minetest.swap_node(pos, {name = def.node_damaged_name, param1 = node.param1, param2 = node.param2}) + --Otherwise, if it doesn't because it's in the last stage of damage, destroy the node. + elseif def.groups.node_damage == 3 then + --If a digger was provided, use node_dig to give the node to them. + if digger then + minetest.node_dig(pos, node, digger) + --Otherwise, use the standard dig_node. This leaves the drops on the ground. + else + minetest.dig_node(pos, node) end + + --If the node was dug up and left nothing behind, there's no need to apply more damage. + if minetest.get_node(pos).name == "air" then + return true + end + else + --If it's not possible to damage this node, fail. + return false end --If num was provided and it was more than 1... if num and num > 1 then --Call damage again, but with 1 less num. - node_damage.damage(pos, node, digger, num - 1) + return node_damage.damage(pos, node, digger, num - 1) end + + --Getting to the end of the function is only possible upon success. + return true end --The opposite of damage. Removes damage from a node, as long as its possible. --pos: The location of the node to repair. --node: Optional; the node itself. It there's already data, you can pass it along to save time, but this function can grab the data itself. +--fixer: Optional; A person (ObjectRef) who is repairing this node. Used to determine protection permission. --num: Optional, defaults to 1; The amount of times to repair this node. 3 will repair any node that still exists. -function node_damage.repair(pos, node, num) +--Returns a boolean indicating success. +function node_damage.repair(pos, node, fixer, num) --If the node itself wasn't provided, grab it from the provided position if not node then node = minetest.get_node(pos) end + --By default, assume that there is no player directly causing the repair. + local pname = "" + + --If there is a player, get that player's name instead. + if fixer then + pname = fixer:get_player_name() + end + + --If this node is protected, fail. + if minetest.is_protected(pos, pname) then + return false + end + --Get the node's definition local def = minetest.registered_items[node.name] - --If the definition exists and has the name of a less damaged node to switch to, swap the node. - if def and def.node_repaired_name and minetest.registered_items[def.node_repaired_name] then - minetest.swap_node(pos, {name = def.node_repaired_name}) + --If there is no definition for this node, fail. + if not def then + return false + end + + --If the definition has the name of a less damaged node to switch to, swap the node. + if def.node_repaired_name and minetest.registered_items[def.node_repaired_name] then + minetest.swap_node(pos, {name = def.node_repaired_name, param1 = node.param1, param2 = node.param2}) + else + --If it's not possible to repair this node, fail. + return false end --If num was provided and it was more than 1... if num and num > 1 then --Call repair again, but with 1 less num. - node_damage.damage(pos, node, digger, num - 1) + return node_damage.repair(pos, node, fixer, num - 1) end + + --Getting to the end of the function is only possible upon success. + return true end