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