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

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