Update 1.0.1

master
Noodlemire 2020-08-15 18:43:47 -05:00
parent ca882ceb66
commit 445e664f0d
3 changed files with 97 additions and 83 deletions

View File

@ -8,13 +8,16 @@ node_damage.damage(pos, node, digger, num)
--or left on the ground. --or left on the ground.
pos: The location of the node to damage 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. 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. 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. --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. --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. --If the node is already fully repaired, nothing will happen.
pos: The location of the node to repair 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. 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. 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.

5
changelog.txt Normal file
View File

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

168
init.lua
View File

@ -20,73 +20,45 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
--mod-specific global storage --mod-specific global storage
node_damage = {} 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. --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. --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) local function get_node_damage_name(name, i)
return "node_damage:"..(name:gsub(":", "_")).."_"..i return "node_damage:"..(name:gsub(":", "_")).."_"..i
end 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. --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. --Get the existing definition for this item.
local def = minetest.registered_items[name] 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: --Return true if all of the following is true:
--The definition exists --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 is not something that would immediately be dug up anyways
--This item isn't already cracked --This item isn't already cracked
--This item is a node --This item is a node
--This item doesn't originate from this mod. --This item doesn't originate from this mod.
--This item can be destroyed --This item can be destroyed
--This item is visible --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 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") and def.diggable and def.drawtype ~= "airlike")
end end
--Once every mod has loaded and therefore every node has been registered... --Once every mod has loaded and therefore every node has been registered...
minetest.register_on_mods_loaded(function() minetest.register_on_mods_loaded(function()
--For each node name in the queue... --For each registered item...
for name in pairs(queue) do for name, def in pairs(minetest.registered_items) do
--As long as the node is still valid --If there's a valid node...
if node_is_valid(name, true) then if node_is_valid(name) then
--Override the node to tell it which node to place when damaged. local ndef = {node_damaged_name = get_node_damage_name(name, 1)}
local def = {node_damaged_name = get_node_damage_name(name, 1)} minetest.override_item(name, ndef)
minetest.override_item(name, def)
--For each of the cracked stages... --For each of the cracked stages...
for i = 1, 3 do for i = 1, 3 do
--Copy the base node's definition and remove information from the copy that can't be overridden. --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 = table.copy(minetest.registered_items[name])
def.name = nil --def.name = get_node_damage_name(name, i)
def.type = nil --def.mod_origin = "node_damage"
def.mod_origin = nil
--Give it the not_in_creative_inventory and node_damage groups --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. --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 break
end end
--Finally, override the cracked node's empty definition with the base node's altered definition. --Finally, forcefully register a new node while skipping the mod name prefix check,
minetest.override_item(get_node_damage_name(name, i), def) --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 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) end)
@ -171,64 +124,117 @@ end)
--A function to damage a given node, as long as that's possible. --A function to damage a given node, as long as that's possible.
--pos: The location of the node to damage. --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. --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. --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) function node_damage.damage(pos, node, digger, num)
--If the node itself wasn't provided, grab it from the provided position --If the node itself wasn't provided, grab it from the provided position
if not node then if not node then
node = minetest.get_node(pos) node = minetest.get_node(pos)
end 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 --Get the node's definition
local def = minetest.registered_items[node.name] local def = minetest.registered_items[node.name]
--If the definition exists... --If the def has no definition or specifies that it can't be dug right now, fail.
if def then if not def or (def.can_dig and def.can_dig()) then
--If it defines a next stage of damage, swap to that next stage. return false
if def.node_damaged_name and minetest.registered_items[def.node_damaged_name] then end
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. --If it defines a next stage of damage, swap to that next stage.
elseif def.groups.node_damage == 3 then if def.node_damaged_name and minetest.registered_items[def.node_damaged_name] then
--If a digger was provided, use node_dig to give the node to them. minetest.swap_node(pos, {name = def.node_damaged_name, param1 = node.param1, param2 = node.param2})
if digger then --Otherwise, if it doesn't because it's in the last stage of damage, destroy the node.
minetest.node_dig(pos, node, digger) elseif def.groups.node_damage == 3 then
--Otherwise, use the standard dig_node. This leaves the drops on the ground. --If a digger was provided, use node_dig to give the node to them.
else if digger then
minetest.dig_node(pos, node) minetest.node_dig(pos, node, digger)
end --Otherwise, use the standard dig_node. This leaves the drops on the ground.
else
minetest.dig_node(pos, node)
end 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 end
--If num was provided and it was more than 1... --If num was provided and it was more than 1...
if num and num > 1 then if num and num > 1 then
--Call damage again, but with 1 less num. --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 end
--Getting to the end of the function is only possible upon success.
return true
end end
--The opposite of damage. Removes damage from a node, as long as its possible. --The opposite of damage. Removes damage from a node, as long as its possible.
--pos: The location of the node to repair. --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. --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. --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 the node itself wasn't provided, grab it from the provided position
if not node then if not node then
node = minetest.get_node(pos) node = minetest.get_node(pos)
end 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 --Get the node's definition
local def = minetest.registered_items[node.name] 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 there is no definition for this node, fail.
if def and def.node_repaired_name and minetest.registered_items[def.node_repaired_name] then if not def then
minetest.swap_node(pos, {name = def.node_repaired_name}) 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 end
--If num was provided and it was more than 1... --If num was provided and it was more than 1...
if num and num > 1 then if num and num > 1 then
--Call repair again, but with 1 less num. --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 end
--Getting to the end of the function is only possible upon success.
return true
end end