Cristiano Magro
2020-10-11 767b74753d22cc8cf89107e6f483b8b40e0e6911
commit | author | age
08b09a 1 -- Configuration
CM 2
3190d2 3 local xnotreetap_max_charge      = 30000 -- Maximum charge of the saw
08b09a 4 -- Gives 2500 nodes on a single charge (about 50 complete normal trees)
3190d2 5 local xnotreetap_charge_per_node = 12
08b09a 6 -- Cut down tree leaves.  Leaf decay may cause slowness on large trees
CM 7 -- if this is disabled.
3190d2 8 local xnotreetap_leaves = true
08b09a 9
767b74 10 -- First value is node name; second is whether the node is considered even if xnotreetap_leaves is false.
08b09a 11 local nodes = {
0fb44d 12   -- Rubber trees from moretrees or technic_worldgen if moretrees isn't installed
CM 13   {"moretrees:rubber_tree_trunk_empty", true},
14   {"moretrees:rubber_tree_trunk", true},
15   {"moretrees:rubber_tree_leaves", false},
08b09a 16 }
0fb44d 17
08b09a 18
CM 19 local timber_nodenames = {}
20 for _, node in pairs(nodes) do
767b74 21   if xnotreetap_leaves or node[2] then
0fb44d 22     timber_nodenames[node[1]] = true
CM 23   end
08b09a 24 end
CM 25
482cb1 26
CM 27 local S = technic.getter
28
08b09a 29 technic.register_power_tool("technic:xnotreetap", xnotreetap_max_charge)
3190d2 30
CM 31 local mesecons_materials = minetest.get_modpath("mesecons_materials")
32
08b09a 33
CM 34 -- This function checks if the specified node should be sawed
35 local function check_if_node_sawed(pos)
0fb44d 36   local node_name = minetest.get_node(pos).name
CM 37   if timber_nodenames[node_name]
38     or (xnotreetap_leaves and minetest.get_item_group(node_name, "leaves") ~= 0)
39     or minetest.get_item_group(node_name, "tree") ~= 0 then
40     return true
41   end
08b09a 42
0fb44d 43   return false
08b09a 44 end
CM 45
46 -- Table for saving what was sawed down
47 local produced = {}
48
49 -- Save the items sawed down so that we can drop them in a nice single stack
50 local function handle_drops(drops)
0fb44d 51   for _, item in ipairs(drops) do
CM 52     local stack = ItemStack(item)
53     local name = stack:get_name()
54     local p = produced[name]
55     if not p then
56       produced[name] = stack
57     else
58       p:set_count(p:get_count() + stack:get_count())
59     end
60   end
08b09a 61 end
CM 62
63 --- Iterator over positions to try to saw around a sawed node.
64 -- This returns positions in a 3x1x3 area around the position, plus the
65 -- position above it.  This does not return the bottom position to prevent
66 -- the chainsaw from cutting down nodes below the cutting position.
67 -- @param pos Sawing position.
68 local function iterSawTries(pos)
0fb44d 69   -- Copy position to prevent mangling it
CM 70   local pos = vector.new(pos)
71   local i = 0
08b09a 72
0fb44d 73   return function()
CM 74     i = i + 1
75     -- Given a (top view) area like so (where 5 is the starting position):
76     -- X -->
77     -- Z 123
78     -- | 456
79     -- V 789
80     -- This will return positions 1, 4, 7, 2, 8 (skip 5), 3, 6, 9,
81     -- and the position above 5.
82     if i == 1 then
83       -- Move to starting position
84       pos.x = pos.x - 1
85       pos.z = pos.z - 1
86     elseif i == 4 or i == 7 then
87       -- Move to next X and back to start of Z when we reach
88       -- the end of a Z line.
89       pos.x = pos.x + 1
90       pos.z = pos.z - 2
91     elseif i == 5 then
92       -- Skip the middle position (we've already run on it)
93       -- and double-increment the counter.
94       pos.z = pos.z + 2
95       i = i + 1
96     elseif i <= 9 then
97       -- Go to next Z.
98       pos.z = pos.z + 1
99     elseif i == 10 then
100       -- Move back to center and up.
101       -- The Y+ position must be last so that we don't dig
102       -- straight upward and not come down (since the Y-
103       -- position isn't checked).
104       pos.x = pos.x - 1
105       pos.z = pos.z - 1
106       pos.y = pos.y + 1
107     else
108       return nil
109     end
110     return pos
111   end
08b09a 112 end
CM 113
114
115
116
117 -- This function does all the hard work. Recursively we dig the node at hand
118 -- if it is in the table and then search the surroundings for more stuff to dig.
119 local function recursive_dig(pos, remaining_charge)
0fb44d 120   if remaining_charge < xnotreetap_charge_per_node then
CM 121     return remaining_charge
122   end
123   local node = minetest.get_node(pos)
08b09a 124
0fb44d 125   if not check_if_node_sawed(pos) then
CM 126     return remaining_charge
127   end
08b09a 128
CM 129
0fb44d 130   if node.name == "moretrees:rubber_tree_trunk" then
CM 131     --raccolta gomma
132     node.name = "moretrees:rubber_tree_trunk_empty"
133     minetest.swap_node(pos, node)
767b74 134 --    minetest.handle_node_drops(pointed_thing.above, {"technic:raw_latex"}, user)
CM 135     handle_drops({"technic:raw_latex"})
0fb44d 136     remaining_charge = remaining_charge - xnotreetap_charge_per_node
CM 137
138     -- Wood found - cut it
139     handle_drops(minetest.get_node_drops(node.name, ""))
140     minetest.remove_node(pos)
141     remaining_charge = remaining_charge - xnotreetap_charge_per_node
142
767b74 143 --    if not technic.creative_mode then
CM 144 --      local item_wear = tonumber(itemstack:get_wear())
145 --      item_wear = item_wear + 819
146 --      if item_wear > 65535 then
147 --        itemstack:clear()
148 --        return itemstack
149 --      end
150 --      itemstack:set_wear(item_wear)
151 --    end
0fb44d 152   end
CM 153
154   -- Check surroundings and run recursively if any charge left
155   for npos in iterSawTries(pos) do
156     if remaining_charge < xnotreetap_charge_per_node then
157       break
158     end
159     if check_if_node_sawed(npos) then
160       remaining_charge = recursive_dig(npos, remaining_charge)
161     else
162       minetest.check_for_falling(npos)
163     end
164   end
165   return remaining_charge
08b09a 166 end
CM 167
168 -- Function to randomize positions for new node drops
169 local function get_drop_pos(pos)
0fb44d 170   local drop_pos = {}
08b09a 171
0fb44d 172   for i = 0, 8 do
CM 173     -- Randomize position for a new drop
174     drop_pos.x = pos.x + math.random(-3, 3)
175     drop_pos.y = pos.y - 1
176     drop_pos.z = pos.z + math.random(-3, 3)
08b09a 177
0fb44d 178     -- Move the randomized position upwards until
CM 179     -- the node is air or unloaded.
180     for y = drop_pos.y, drop_pos.y + 5 do
181       drop_pos.y = y
182       local node = minetest.get_node_or_nil(drop_pos)
08b09a 183
0fb44d 184       if not node then
CM 185         -- If the node is not loaded yet simply drop
186         -- the item at the original digging position.
187         return pos
188       elseif node.name == "air" then
189         -- Add variation to the entity drop position,
190         -- but don't let drops get too close to the edge
191         drop_pos.x = drop_pos.x + (math.random() * 0.8) - 0.5
192         drop_pos.z = drop_pos.z + (math.random() * 0.8) - 0.5
193         return drop_pos
194       end
195     end
196   end
08b09a 197
0fb44d 198   -- Return the original position if this takes too long
CM 199   return pos
08b09a 200 end
CM 201
202 -- Chainsaw entry point
203 local function xnotreetap_dig(pos, current_charge)
0fb44d 204   -- Start sawing things down
CM 205   local remaining_charge = recursive_dig(pos, current_charge)
206   minetest.sound_play("chainsaw", {pos = pos, gain = 1.0,
207     max_hear_distance = 10})
08b09a 208
0fb44d 209   -- Now drop items for the player
CM 210   for name, stack in pairs(produced) do
211     -- Drop stacks of stack max or less
212     local count, max = stack:get_count(), stack:get_stack_max()
213     stack:set_count(max)
214     while count > max do
215       minetest.add_item(get_drop_pos(pos), stack)
216       count = count - max
217     end
218     stack:set_count(count)
219     minetest.add_item(get_drop_pos(pos), stack)
220   end
08b09a 221
0fb44d 222   -- Clean up
CM 223   produced = {}
08b09a 224
0fb44d 225   return remaining_charge
08b09a 226 end
CM 227
482cb1 228 minetest.register_tool("technic:xnotreetap", {
0fb44d 229   description = S("Xno Tree Tap"),
CM 230   inventory_image = "technic_tree_tap.png",
3190d2 231
0fb44d 232   stack_max = 1,
3190d2 233   
0fb44d 234   wear_represents = "technic_RE_charge",
CM 235   on_refill = technic.refill_RE_charge,
3190d2 236
0fb44d 237   on_use = function(itemstack, user, pointed_thing)
CM 238     if pointed_thing.type ~= "node" then
239       return itemstack
240     end
08b09a 241
0fb44d 242     --check tool charge
CM 243     local meta = minetest.deserialize(itemstack:get_metadata())
244     if not meta or not meta.charge or
245       meta.charge < xnotreetap_charge_per_node then
246       return
247     end
08b09a 248
0fb44d 249     --check node protection
CM 250     local pos = pointed_thing.under
251     if minetest.is_protected(pos, user:get_player_name()) then
252       minetest.record_protection_violation(pos, user:get_player_name())
253       return
254     end
08b09a 255
CM 256
0fb44d 257     --can collect only from rubber
CM 258     local node = minetest.get_node(pos)
259     local node_name = node.name
260     if node_name ~= "moretrees:rubber_tree_trunk" then
261       return
262     end
767b74 263  
0fb44d 264     -- Send current charge to digging function so that the
CM 265     -- chainsaw will stop after digging a number of nodes
266     meta.charge = xnotreetap_dig(pointed_thing.under, meta.charge)
267     if not technic.creative_mode then
268       technic.set_RE_wear(itemstack, meta.charge, xnotreetap_max_charge)
269       itemstack:set_metadata(minetest.serialize(meta))
270     end
271     return itemstack
08b09a 272
0fb44d 273   end,
482cb1 274 })
CM 275
276 minetest.register_craft({
0fb44d 277   output = "technic:xnotreetap",
CM 278   recipe = {
279     {"pipeworks:tube_1", "group:wood",    "default:stick"},
280     {"technic:battery",  "default:stick", "default:stick"},
281     {"technic:battery",  "default:stick", "default:stick"},
282   },
482cb1 283 })
CM 284
3190d2 285 --minetest.register_abm({
CM 286 --  label = "Tools: xno tree tap",
287 --  nodenames = {"moretrees:rubber_tree_trunk_empty"},
288 --  interval = 60,
289 --  chance = 15,
290 --  action = function(pos, node)
291 --    if minetest.find_node_near(pos, (moretrees and moretrees.leafdecay_radius) or 5, {"moretrees:rubber_tree_leaves"}) then
292 --      node.name = "moretrees:rubber_tree_trunk"
293 --      minetest.swap_node(pos, node)
294 --    end
295 --  end
296 --})
482cb1 297
08b09a 298
CM 299
300
301
302