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