| | |
| | | -- Configuration |
| | | |
| | | local xnotreetrap_max_charge = 30000 -- Maximum charge of the saw |
| | | local xnotreetap_max_charge = 30000 -- Maximum charge of the saw |
| | | -- Gives 2500 nodes on a single charge (about 50 complete normal trees) |
| | | local xnotreetrap_charge_per_node = 12 |
| | | local xnotreetap_charge_per_node = 12 |
| | | -- Cut down tree leaves. Leaf decay may cause slowness on large trees |
| | | -- if this is disabled. |
| | | local xnotreetrap_leaves = true |
| | | local xnotreetap_leaves = true |
| | | |
| | | -- First value is node name; second is whether the node is considered even if chainsaw_leaves is false. |
| | | -- First value is node name; second is whether the node is considered even if xnotreetap_leaves is false. |
| | | local nodes = { |
| | | -- Rubber trees from moretrees or technic_worldgen if moretrees isn't installed |
| | | {"moretrees:rubber_tree_trunk_empty", true}, |
| | | {"moretrees:rubber_tree_trunk", true}, |
| | | {"moretrees:rubber_tree_leaves", false}, |
| | | -- Rubber trees from moretrees or technic_worldgen if moretrees isn't installed |
| | | {"moretrees:rubber_tree_trunk_empty", true}, |
| | | {"moretrees:rubber_tree_trunk", true}, |
| | | {"moretrees:rubber_tree_leaves", false}, |
| | | } |
| | | |
| | | -- Remember node visited recursive and not dig twice |
| | | local node_visited = {} |
| | | |
| | | local timber_nodenames = {} |
| | | for _, node in pairs(nodes) do |
| | | if chainsaw_leaves or node[2] then |
| | | timber_nodenames[node[1]] = true |
| | | end |
| | | if xnotreetap_leaves or node[2] then |
| | | timber_nodenames[node[1]] = true |
| | | end |
| | | end |
| | | |
| | | |
| | | local S = technic.getter |
| | | local mesecons_materials = minetest.get_modpath("mesecons_materials") |
| | | |
| | | technic.register_power_tool("technic:xnotreetap", xnotreetap_max_charge) |
| | | |
| | | local mesecons_materials = minetest.get_modpath("mesecons_materials") |
| | | |
| | | |
| | | -- This function checks if the specified node should be sawed |
| | | local function check_if_node_sawed(pos) |
| | | local node_name = minetest.get_node(pos).name |
| | | if timber_nodenames[node_name] |
| | | or (xnotreetap_leaves and minetest.get_item_group(node_name, "leaves") ~= 0) |
| | | or minetest.get_item_group(node_name, "tree") ~= 0 then |
| | | return true |
| | | end |
| | | local node = minetest.get_node(pos) |
| | | local node_name = node.name |
| | | |
| | | return false |
| | | |
| | | if timber_nodenames[node_name] |
| | | or (xnotreetap_leaves and minetest.get_item_group(node_name, "leaves") ~= 0) |
| | | or minetest.get_item_group(node_name, "tree") ~= 0 then |
| | | minetest.log("action", "[Xno Tree Tap] "..node_name.." good node to collect.") --print to log |
| | | return true |
| | | end |
| | | |
| | | return false |
| | | end |
| | | |
| | | -- Table for saving what was sawed down |
| | |
| | | |
| | | -- Save the items sawed down so that we can drop them in a nice single stack |
| | | local function handle_drops(drops) |
| | | for _, item in ipairs(drops) do |
| | | local stack = ItemStack(item) |
| | | local name = stack:get_name() |
| | | local p = produced[name] |
| | | if not p then |
| | | produced[name] = stack |
| | | else |
| | | p:set_count(p:get_count() + stack:get_count()) |
| | | end |
| | | end |
| | | for _, item in ipairs(drops) do |
| | | local stack = ItemStack(item) |
| | | local name = stack:get_name() |
| | | local p = produced[name] |
| | | if not p then |
| | | produced[name] = stack |
| | | else |
| | | p:set_count(p:get_count() + stack:get_count()) |
| | | end |
| | | end |
| | | end |
| | | |
| | | --- Iterator over positions to try to saw around a sawed node. |
| | |
| | | -- the chainsaw from cutting down nodes below the cutting position. |
| | | -- @param pos Sawing position. |
| | | local function iterSawTries(pos) |
| | | -- Copy position to prevent mangling it |
| | | local pos = vector.new(pos) |
| | | local i = 0 |
| | | -- Copy position to prevent mangling it |
| | | local pos = vector.new(pos) |
| | | local i = 0 |
| | | |
| | | return function() |
| | | i = i + 1 |
| | | -- Given a (top view) area like so (where 5 is the starting position): |
| | | -- X --> |
| | | -- Z 123 |
| | | -- | 456 |
| | | -- V 789 |
| | | -- This will return positions 1, 4, 7, 2, 8 (skip 5), 3, 6, 9, |
| | | -- and the position above 5. |
| | | if i == 1 then |
| | | -- Move to starting position |
| | | pos.x = pos.x - 1 |
| | | pos.z = pos.z - 1 |
| | | elseif i == 4 or i == 7 then |
| | | -- Move to next X and back to start of Z when we reach |
| | | -- the end of a Z line. |
| | | pos.x = pos.x + 1 |
| | | pos.z = pos.z - 2 |
| | | elseif i == 5 then |
| | | -- Skip the middle position (we've already run on it) |
| | | -- and double-increment the counter. |
| | | pos.z = pos.z + 2 |
| | | i = i + 1 |
| | | elseif i <= 9 then |
| | | -- Go to next Z. |
| | | pos.z = pos.z + 1 |
| | | elseif i == 10 then |
| | | -- Move back to center and up. |
| | | -- The Y+ position must be last so that we don't dig |
| | | -- straight upward and not come down (since the Y- |
| | | -- position isn't checked). |
| | | pos.x = pos.x - 1 |
| | | pos.z = pos.z - 1 |
| | | pos.y = pos.y + 1 |
| | | else |
| | | return nil |
| | | end |
| | | return pos |
| | | end |
| | | return function() |
| | | i = i + 1 |
| | | -- Given a (top view) area like so (where 5 is the starting position): |
| | | -- X --> |
| | | -- Z 123 |
| | | -- | 456 |
| | | -- V 789 |
| | | -- This will return positions 1, 4, 7, 2, 8 (skip 5), 3, 6, 9, |
| | | -- and the position above 5. |
| | | if i == 1 then |
| | | -- Move to starting position |
| | | pos.x = pos.x - 1 |
| | | pos.z = pos.z - 1 |
| | | elseif i == 4 or i == 7 then |
| | | -- Move to next X and back to start of Z when we reach |
| | | -- the end of a Z line. |
| | | pos.x = pos.x + 1 |
| | | pos.z = pos.z - 2 |
| | | elseif i == 5 then |
| | | -- Skip the middle position (we've already run on it) |
| | | -- and double-increment the counter. |
| | | pos.z = pos.z + 2 |
| | | i = i + 1 |
| | | elseif i <= 9 then |
| | | -- Go to next Z. |
| | | pos.z = pos.z + 1 |
| | | elseif i == 10 then |
| | | -- Move back to center and up. |
| | | -- The Y+ position must be last so that we don't dig |
| | | -- straight upward and not come down (since the Y- |
| | | -- position isn't checked). |
| | | pos.x = pos.x - 1 |
| | | pos.z = pos.z - 1 |
| | | pos.y = pos.y + 1 |
| | | else |
| | | return nil |
| | | end |
| | | return pos |
| | | end |
| | | end |
| | | |
| | | -- inserisco un valore in tabella |
| | | local function add_table(table, toadd) |
| | | local i = 1 |
| | | while true do |
| | | local o = table[i] |
| | | if o == toadd then return end |
| | | if o == nil then break end |
| | | i = i + 1 |
| | | end |
| | | table[i] = toadd |
| | | end |
| | | |
| | | -- bool controllo se un valore è presente in tabella |
| | | local function in_table(table, value) |
| | | local i = 1 |
| | | while true do |
| | | local o = table[i] |
| | | if o == value then |
| | | minetest.log("action", "[Xno Tree Tap] "..value.." visited.") --print to log |
| | | return true |
| | | end |
| | | if o == nil then break end |
| | | i = i + 1 |
| | | end |
| | | return false |
| | | end |
| | | |
| | | -- verifico se un nodo è nella tabella visitato |
| | | local function check_if_node_visited (pos) |
| | | return in_table(node_visited, pos) |
| | | end |
| | | |
| | | local function myString (v) |
| | | return v.x.." "..v.y.." "..v.z.." " |
| | | end |
| | | |
| | | local function set_node_visited (pos) |
| | | minetest.log("action", "[Xno Tree Tap] "..myString(pos).." set node visited.") --print to log |
| | | |
| | | add_table(node_visited, pos) |
| | | end |
| | | |
| | | -- This function does all the hard work. Recursively we dig the node at hand |
| | | -- if it is in the table and then search the surroundings for more stuff to dig. |
| | | local function recursive_dig(pos, remaining_charge) |
| | | if remaining_charge < xnotreetap_charge_per_node then |
| | | return remaining_charge |
| | | end |
| | | local node = minetest.get_node(pos) |
| | | if remaining_charge < xnotreetap_charge_per_node then |
| | | return remaining_charge |
| | | end |
| | | |
| | | if not check_if_node_sawed(pos) then |
| | | return remaining_charge |
| | | end |
| | | if check_if_node_visited(pos) then |
| | | return remaining_charge |
| | | end |
| | | |
| | | -- Wood found - cut it |
| | | handle_drops(minetest.get_node_drops(node.name, "")) |
| | | minetest.remove_node(pos) |
| | | remaining_charge = remaining_charge - xnotreetap_charge_per_node |
| | | if not check_if_node_sawed(pos) then |
| | | return remaining_charge |
| | | end |
| | | |
| | | -- Check surroundings and run recursively if any charge left |
| | | for npos in iterSawTries(pos) do |
| | | if remaining_charge < xnotreetap_charge_per_node then |
| | | break |
| | | end |
| | | if check_if_node_sawed(npos) then |
| | | remaining_charge = recursive_dig(npos, remaining_charge) |
| | | else |
| | | minetest.check_for_falling(npos) |
| | | end |
| | | end |
| | | return remaining_charge |
| | | local node = minetest.get_node(pos) |
| | | |
| | | if node.name == "moretrees:rubber_tree_trunk" then |
| | | --raccolta gomma |
| | | node.name = "moretrees:rubber_tree_trunk_empty" |
| | | minetest.swap_node(pos, node) |
| | | handle_drops(minetest.get_node_drops("technic:raw_latex", "")) |
| | | remaining_charge = remaining_charge - xnotreetap_charge_per_node |
| | | |
| | | -- Wood found - cut it |
| | | handle_drops(minetest.get_node_drops(node.name, "")) |
| | | minetest.remove_node(pos) |
| | | remaining_charge = remaining_charge - xnotreetap_charge_per_node |
| | | |
| | | -- if not technic.creative_mode then |
| | | -- local item_wear = tonumber(itemstack:get_wear()) |
| | | -- item_wear = item_wear + 819 |
| | | -- if item_wear > 65535 then |
| | | -- itemstack:clear() |
| | | -- return itemstack |
| | | -- end |
| | | -- itemstack:set_wear(item_wear) |
| | | -- end |
| | | end |
| | | |
| | | set_node_visited(pos) |
| | | |
| | | -- Check surroundings and run recursively if any charge left |
| | | for npos in iterSawTries(pos) do |
| | | if remaining_charge < xnotreetap_charge_per_node then |
| | | break |
| | | end |
| | | if check_if_node_sawed(npos) then |
| | | remaining_charge = recursive_dig(npos, remaining_charge) |
| | | else |
| | | minetest.check_for_falling(npos) |
| | | end |
| | | end |
| | | return remaining_charge |
| | | end |
| | | |
| | | -- Function to randomize positions for new node drops |
| | | local function get_drop_pos(pos) |
| | | local drop_pos = {} |
| | | local drop_pos = {} |
| | | |
| | | for i = 0, 8 do |
| | | -- Randomize position for a new drop |
| | | drop_pos.x = pos.x + math.random(-3, 3) |
| | | drop_pos.y = pos.y - 1 |
| | | drop_pos.z = pos.z + math.random(-3, 3) |
| | | for i = 0, 8 do |
| | | -- Randomize position for a new drop |
| | | drop_pos.x = pos.x + math.random(-3, 3) |
| | | drop_pos.y = pos.y - 1 |
| | | drop_pos.z = pos.z + math.random(-3, 3) |
| | | |
| | | -- Move the randomized position upwards until |
| | | -- the node is air or unloaded. |
| | | for y = drop_pos.y, drop_pos.y + 5 do |
| | | drop_pos.y = y |
| | | local node = minetest.get_node_or_nil(drop_pos) |
| | | -- Move the randomized position upwards until |
| | | -- the node is air or unloaded. |
| | | for y = drop_pos.y, drop_pos.y + 5 do |
| | | drop_pos.y = y |
| | | local node = minetest.get_node_or_nil(drop_pos) |
| | | |
| | | if not node then |
| | | -- If the node is not loaded yet simply drop |
| | | -- the item at the original digging position. |
| | | return pos |
| | | elseif node.name == "air" then |
| | | -- Add variation to the entity drop position, |
| | | -- but don't let drops get too close to the edge |
| | | drop_pos.x = drop_pos.x + (math.random() * 0.8) - 0.5 |
| | | drop_pos.z = drop_pos.z + (math.random() * 0.8) - 0.5 |
| | | return drop_pos |
| | | end |
| | | end |
| | | end |
| | | if not node then |
| | | -- If the node is not loaded yet simply drop |
| | | -- the item at the original digging position. |
| | | return pos |
| | | elseif node.name == "air" then |
| | | -- Add variation to the entity drop position, |
| | | -- but don't let drops get too close to the edge |
| | | drop_pos.x = drop_pos.x + (math.random() * 0.8) - 0.5 |
| | | drop_pos.z = drop_pos.z + (math.random() * 0.8) - 0.5 |
| | | return drop_pos |
| | | end |
| | | end |
| | | end |
| | | |
| | | -- Return the original position if this takes too long |
| | | return pos |
| | | -- Return the original position if this takes too long |
| | | return pos |
| | | end |
| | | |
| | | -- Chainsaw entry point |
| | | local function xnotreetap_dig(pos, current_charge) |
| | | -- Start sawing things down |
| | | local remaining_charge = recursive_dig(pos, current_charge) |
| | | minetest.sound_play("chainsaw", {pos = pos, gain = 1.0, |
| | | max_hear_distance = 10}) |
| | | -- Start sawing things down |
| | | local remaining_charge = recursive_dig(pos, current_charge) |
| | | minetest.sound_play("chainsaw", {pos = pos, gain = 1.0, |
| | | max_hear_distance = 10}) |
| | | |
| | | -- Now drop items for the player |
| | | for name, stack in pairs(produced) do |
| | | -- Drop stacks of stack max or less |
| | | local count, max = stack:get_count(), stack:get_stack_max() |
| | | stack:set_count(max) |
| | | while count > max do |
| | | minetest.add_item(get_drop_pos(pos), stack) |
| | | count = count - max |
| | | end |
| | | stack:set_count(count) |
| | | minetest.add_item(get_drop_pos(pos), stack) |
| | | end |
| | | -- Now drop items for the player |
| | | for name, stack in pairs(produced) do |
| | | -- Drop stacks of stack max or less |
| | | local count, max = stack:get_count(), stack:get_stack_max() |
| | | stack:set_count(max) |
| | | while count > max do |
| | | minetest.add_item(get_drop_pos(pos), stack) |
| | | count = count - max |
| | | end |
| | | stack:set_count(count) |
| | | minetest.add_item(get_drop_pos(pos), stack) |
| | | end |
| | | |
| | | -- Clean up |
| | | produced = {} |
| | | -- Clean up |
| | | produced = {} |
| | | |
| | | return remaining_charge |
| | | return remaining_charge |
| | | end |
| | | |
| | | minetest.register_tool("technic:xnotreetap", { |
| | | description = S("Xno Tree Tap"), |
| | | inventory_image = "technic_tree_tap.png", |
| | | stack_max = 1, |
| | | wear_represents = "technic_RE_charge", |
| | | on_refill = technic.refill_RE_charge, |
| | | on_use = function(itemstack, user, pointed_thing) |
| | | if pointed_thing.type ~= "node" then |
| | | return itemstack |
| | | end |
| | | description = S("Xno Tree Tap"), |
| | | inventory_image = "technic_tree_tap.png", |
| | | |
| | | //check tool charge |
| | | local meta = minetest.deserialize(itemstack:get_metadata()) |
| | | if not meta or not meta.charge or |
| | | meta.charge < xnotreetap_charge_per_node then |
| | | return |
| | | end |
| | | stack_max = 1, |
| | | |
| | | //check node protection |
| | | local pos = pointed_thing.under |
| | | if minetest.is_protected(pos, user:get_player_name()) then |
| | | minetest.record_protection_violation(pos, user:get_player_name()) |
| | | return |
| | | end |
| | | wear_represents = "technic_RE_charge", |
| | | on_refill = technic.refill_RE_charge, |
| | | |
| | | on_use = function(itemstack, user, pointed_thing) |
| | | if pointed_thing.type ~= "node" then |
| | | return itemstack |
| | | end |
| | | |
| | | --check tool charge |
| | | local meta = minetest.deserialize(itemstack:get_metadata()) |
| | | if not meta or not meta.charge or |
| | | meta.charge < xnotreetap_charge_per_node then |
| | | return |
| | | end |
| | | |
| | | --check node protection |
| | | local pos = pointed_thing.under |
| | | if minetest.is_protected(pos, user:get_player_name()) then |
| | | minetest.record_protection_violation(pos, user:get_player_name()) |
| | | return |
| | | end |
| | | |
| | | |
| | | local node = minetest.get_node(pos) |
| | | local node_name = node.name |
| | | if node_name ~= "moretrees:rubber_tree_trunk" then |
| | | return |
| | | end |
| | | --can collect only from rubber |
| | | local node = minetest.get_node(pos) |
| | | local node_name = node.name |
| | | if node_name ~= "moretrees:rubber_tree_trunk" then |
| | | return |
| | | end |
| | | |
| | | //raccolta gomma |
| | | node.name = "moretrees:rubber_tree_trunk_empty" |
| | | minetest.swap_node(pos, node) |
| | | minetest.handle_node_drops(pointed_thing.above, {"technic:raw_latex"}, user) |
| | | -- Send current charge to digging function so that the |
| | | -- chainsaw will stop after digging a number of nodes |
| | | meta.charge = xnotreetap_dig(pointed_thing.under, meta.charge) |
| | | if not technic.creative_mode then |
| | | technic.set_RE_wear(itemstack, meta.charge, xnotreetap_max_charge) |
| | | itemstack:set_metadata(minetest.serialize(meta)) |
| | | end |
| | | return itemstack |
| | | |
| | | if not technic.creative_mode then |
| | | local item_wear = tonumber(itemstack:get_wear()) |
| | | item_wear = item_wear + 819 |
| | | if item_wear > 65535 then |
| | | itemstack:clear() |
| | | return itemstack |
| | | end |
| | | itemstack:set_wear(item_wear) |
| | | end |
| | | return itemstack |
| | | |
| | | -- Send current charge to digging function so that the |
| | | -- chainsaw will stop after digging a number of nodes |
| | | meta.charge = xnotreetap_dig(pointed_thing.under, meta.charge) |
| | | if not technic.creative_mode then |
| | | technic.set_RE_wear(itemstack, meta.charge, xnotreetap_max_charge) |
| | | itemstack:set_metadata(minetest.serialize(meta)) |
| | | end |
| | | return itemstack |
| | | |
| | | end, |
| | | end, |
| | | }) |
| | | |
| | | minetest.register_craft({ |
| | | output = "technic:xnotreetap", |
| | | recipe = { |
| | | {"pipeworks:tube_1", "group:wood", "default:stick"}, |
| | | {"technic:battery", "default:stick", "default:stick"} |
| | | {"technic:battery", "default:stick", "default:stick"} |
| | | }, |
| | | output = "technic:xnotreetap", |
| | | recipe = { |
| | | {"pipeworks:tube_1", "group:wood", "default:stick"}, |
| | | {"technic:battery", "default:stick", "default:stick"}, |
| | | {"technic:battery", "default:stick", "default:stick"}, |
| | | }, |
| | | }) |
| | | |
| | | minetest.register_abm({ |
| | | label = "Tools: xno tree tap", |
| | | nodenames = {"moretrees:rubber_tree_trunk_empty"}, |
| | | interval = 60, |
| | | chance = 15, |
| | | action = function(pos, node) |
| | | if minetest.find_node_near(pos, (moretrees and moretrees.leafdecay_radius) or 5, {"moretrees:rubber_tree_leaves"}) then |
| | | node.name = "moretrees:rubber_tree_trunk" |
| | | minetest.swap_node(pos, node) |
| | | end |
| | | end |
| | | }) |
| | | |
| | | |
| | | |
| | | --minetest.register_abm({ |
| | | -- label = "Tools: xno tree tap", |
| | | -- nodenames = {"moretrees:rubber_tree_trunk_empty"}, |
| | | -- interval = 60, |
| | | -- chance = 15, |
| | | -- action = function(pos, node) |
| | | -- if minetest.find_node_near(pos, (moretrees and moretrees.leafdecay_radius) or 5, {"moretrees:rubber_tree_leaves"}) then |
| | | -- node.name = "moretrees:rubber_tree_trunk" |
| | | -- minetest.swap_node(pos, node) |
| | | -- end |
| | | -- end |
| | | --}) |
| | | |
| | | |
| | | |