Cristiano Magro
2020-10-14 e628760d271b2a28b32ddf31a18463e8d63e9362
technic/tools/xno_tree_tap.lua
@@ -1,13 +1,115 @@
-- A simple special-purpose class, this is used for building up sets of three-dimensional points for fast reference
Pointset = {}
Pointset.__index = Pointset
function Pointset.create()
  local set = {}
  setmetatable(set,Pointset)
  set.points = {}
  return set
end
function Pointset:set(x, y, z, value)
  -- sets a value in the 3D array "points".
  if self.points[x] == nil then
    self.points[x] = {}
  end
  if self.points[x][y] == nil then
    self.points[x][y] = {}
  end
  self.points[x][y][z] = value
end
function Pointset:set_if_not_in(excluded, x, y, z, value)
  -- If a value is not already set for this point in the 3D array "excluded", set it in "points"
  if excluded:get(x, y, z) ~= nil then
    return
  end
  self:set(x, y, z, value)
end
function Pointset:get(x, y, z)
  -- return a value from the 3D array "points"
  if self.points[x] == nil or self.points[x][y] == nil then
    return nil
  end
  return self.points[x][y][z]
end
function Pointset:set_pos(pos, value)
  self:set(pos.x, pos.y, pos.z, value)
end
function Pointset:set_pos_if_not_in(excluded, pos, value)
  self:set_if_not_in(excluded, pos.x, pos.y, pos.z, value)
end
function Pointset:get_pos(pos)
  return self:get(pos.x, pos.y, pos.z)
end
function Pointset:pop()
  -- returns a point that's in the 3D array, and then removes it.
  local pos = {}
  local ytable
  local ztable
  local val
  local count = 0
  for _ in pairs(self.points) do count = count + 1 end
  if count == 0 then
    return nil
  end
  pos.x, ytable = next(self.points)
  pos.y, ztable = next(ytable)
  pos.z, val = next(ztable)
  self.points[pos.x][pos.y][pos.z] = nil
  count = 0
  for _ in pairs(self.points[pos.x][pos.y]) do count = count + 1 end
  if count == 0 then
    self.points[pos.x][pos.y] = nil
  end
  count = 0
  for _ in pairs(self.points[pos.x]) do count = count + 1 end
  if count == 0 then
    self.points[pos.x] = nil
  end
  return pos, val
end
function Pointset:get_pos_list(value)
  -- Returns a list of all points with the given value in standard Minetest vector format. If no value is provided, returns all points
  local outlist = {}
  for x, ytable in ipairs(self.points) do
    for y, ztable in ipairs(ytable) do
      for z, val in ipairs(ztable) do
        if (value == nil and val ~= nil ) or val == value then
          table.insert(outlist, {x=x, y=y, z=z})
        end
      end
    end
  end
  return outlist
end
-- 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},
@@ -15,26 +117,33 @@
  {"moretrees:rubber_tree_leaves", false},
}
-- Remember node visited recursive and not dig twice
local nodeVisited = Pointset.create()
local timber_nodenames = {}
for _, node in pairs(nodes) do
  if chainsaw_leaves or node[2] then
  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
  local node = minetest.get_node(pos)
  local node_name = node.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
    minetest.log("action", "[Xno Tree Tap] "..node_name.." good node to collect.") --print to log
    return true
  end
@@ -43,6 +152,10 @@
-- Table for saving what was sawed down
local produced = {}
local function myString (v)
  return v.x.." "..v.y.." "..v.z.." "
end
-- Save the items sawed down so that we can drop them in a nice single stack
local function handle_drops(drops)
@@ -109,8 +222,35 @@
  end
end
-- inserisco un valore in tabella
local function add_table(table, toadd)
  table:set(toadd.x, toadd.y, toadd.z, true)
end
-- bool controllo se un valore è presente in tabella
local function in_table(table, pos)
  local val = table:get(pos.x, pos.y, pos.z)
  local visited = 'NO'
  if val ~= nil then
    if val then
      visited = 'SI'
    end
    minetest.log("action", "[Xno Tree Tap] "..myString(pos).." visited? " .. visited) --print to log
    return val
  end
  return false
end
-- verifico se un nodo è nella tabella visitato
local function check_if_node_visited (pos)
  return in_table(nodeVisited, pos)
end
local function set_node_visited (pos)
  minetest.log("action", "[Xno Tree Tap] "..myString(pos).." set node visited.") --print to log
  add_table(nodeVisited, 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.
@@ -118,35 +258,38 @@
  if remaining_charge < xnotreetap_charge_per_node then
    return remaining_charge
  end
  local node = minetest.get_node(pos)
  if check_if_node_visited(pos) then
    return remaining_charge
  end
  if not check_if_node_sawed(pos) then
    return remaining_charge
  end
  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)
    minetest.handle_node_drops(pointed_thing.above, {"technic:raw_latex"}, user)
    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
  end
  if node.name == "moretrees:rubber_tree_leaves" then
    -- Leaves 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
@@ -225,9 +368,12 @@
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
@@ -255,22 +401,6 @@
      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)
    --
    --      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)
@@ -292,21 +422,18 @@
  },
})
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
--})