coil
2019-12-30 da95be53ec5703e808233d7b45fc42fb500863dd
commit | author | age
8e03d7 1 -- Configuration
R 2
9019eb 3 local chainsaw_max_charge      = 30000 -- Maximum charge of the saw
S 4 -- Gives 2500 nodes on a single charge (about 50 complete normal trees)
5 local chainsaw_charge_per_node = 12
6 -- Cut down tree leaves.  Leaf decay may cause slowness on large trees
7 -- if this is disabled.
8 local chainsaw_leaves = true
9
e66bb2 10 -- First value is node name; second is whether the node is considered even if chainsaw_leaves is false.
C 11 local nodes = {
12     -- The default trees
13     {"default:acacia_tree", true},
14     {"default:aspen_tree", true},
15     {"default:jungletree", true},
16     {"default:papyrus", true},
17     {"default:cactus", true},
18     {"default:tree", true},
19     {"default:apple", true},
20     {"default:pine_tree", true},
21     {"default:acacia_leaves", false},
22     {"default:aspen_leaves", false},
23     {"default:leaves", false},
24     {"default:jungleleaves", false},
25     {"default:pine_needles", false},
26
27     -- Rubber trees from moretrees or technic_worldgen if moretrees isn't installed
28     {"moretrees:rubber_tree_trunk_empty", true},
29     {"moretrees:rubber_tree_trunk", true},
30     {"moretrees:rubber_tree_leaves", false},
31
32     -- Support moretrees
33     {"moretrees:acacia_trunk", true},
34     {"moretrees:apple_tree_trunk", true},
35     {"moretrees:beech_trunk", true},
36     {"moretrees:birch_trunk", true},
37     {"moretrees:fir_trunk", true},
38     {"moretrees:oak_trunk", true},
39     {"moretrees:palm_trunk", true},
40     {"moretrees:pine_trunk", true},
41     {"moretrees:sequoia_trunk", true},
42     {"moretrees:spruce_trunk", true},
43     {"moretrees:willow_trunk", true},
44     {"moretrees:jungletree_trunk", true},
45     {"moretrees:poplar_trunk", true},
46     {"moretrees:acacia_leaves", false},
47     {"moretrees:apple_tree_leaves", false},
48     {"moretrees:oak_leaves", false},
49     {"moretrees:fir_leaves", false},
50     {"moretrees:fir_leaves_bright", false},
51     {"moretrees:sequoia_leaves", false},
52     {"moretrees:birch_leaves", false},
53     {"moretrees:birch_leaves", false},
54     {"moretrees:palm_leaves", false},
55     {"moretrees:spruce_leaves", false},
56     {"moretrees:spruce_leaves", false},
57     {"moretrees:pine_leaves", false},
58     {"moretrees:willow_leaves", false},
59     {"moretrees:jungletree_leaves_green", false},
60     {"moretrees:jungletree_leaves_yellow", false},
61     {"moretrees:jungletree_leaves_red", false},
62     {"moretrees:acorn", false},
63     {"moretrees:coconut", false},
64     {"moretrees:spruce_cone", false},
65     {"moretrees:pine_cone", false},
66     {"moretrees:fir_cone", false},
67     {"moretrees:apple_blossoms", false},
68     {"moretrees:poplar_leaves", false},
69
70     -- Support growing_trees
71     {"growing_trees:trunk", true},
72     {"growing_trees:medium_trunk", true},
73     {"growing_trees:big_trunk", true},
74     {"growing_trees:trunk_top", true},
75     {"growing_trees:trunk_sprout", true},
76     {"growing_trees:branch_sprout", true},
77     {"growing_trees:branch", true},
78     {"growing_trees:branch_xmzm", true},
79     {"growing_trees:branch_xpzm", true},
80     {"growing_trees:branch_xmzp", true},
81     {"growing_trees:branch_xpzp", true},
82     {"growing_trees:branch_zz", true},
83     {"growing_trees:branch_xx", true},
84     {"growing_trees:leaves", false},
85
86     -- Support cool_trees
87     {"bamboo:trunk", true},
88     {"bamboo:leaves", false},
89     {"birch:trunk", true},
90     {"birch:leaves", false},
91     {"cherrytree:trunk", true},
92     {"cherrytree:blossom_leaves", false},
93     {"cherrytree:leaves", false},
94     {"chestnuttree:trunk", true},
95     {"chestnuttree:leaves", false},
96     {"clementinetree:trunk", true},
97     {"clementinetree:leaves", false},
98     {"ebony:trunk", true},
99     {"ebony:creeper", false},
100     {"ebony:creeper_leaves", false},
101     {"ebony:leaves", false},
102     {"jacaranda:trunk", true},
103     {"jacaranda:blossom_leaves", false},
104     {"larch:trunk", true},
105     {"larch:leaves", false},
106     {"lemontree:trunk", true},
107     {"lemontree:leaves", false},
108     {"mahogany:trunk", true},
109     {"mahogany:leaves", false},
110     {"palm:trunk", true},
111     {"palm:leaves", false},
112
113     -- Support growing_cactus
114     {"growing_cactus:sprout", true},
115     {"growing_cactus:branch_sprout_vertical", true},
116     {"growing_cactus:branch_sprout_vertical_fixed", true},
117     {"growing_cactus:branch_sprout_xp", true},
118     {"growing_cactus:branch_sprout_xm", true},
119     {"growing_cactus:branch_sprout_zp", true},
120     {"growing_cactus:branch_sprout_zm", true},
121     {"growing_cactus:trunk", true},
122     {"growing_cactus:branch_trunk", true},
123     {"growing_cactus:branch", true},
124     {"growing_cactus:branch_xp", true},
125     {"growing_cactus:branch_xm", true},
126     {"growing_cactus:branch_zp", true},
127     {"growing_cactus:branch_zm", true},
128     {"growing_cactus:branch_zz", true},
129     {"growing_cactus:branch_xx", true},
130
131     -- Support farming_plus
132     {"farming_plus:banana_leaves", false},
133     {"farming_plus:banana", false},
134     {"farming_plus:cocoa_leaves", false},
135     {"farming_plus:cocoa", false},
136
137     -- Support nature
138     {"nature:blossom", false},
139
140     -- Support snow
141     {"snow:needles", false},
142     {"snow:needles_decorated", false},
143     {"snow:star", false},
144
145     -- Support vines (also generated by moretrees if available)
146     {"vines:vines", false},
147
148     {"trunks:moss", false},
149     {"trunks:moss_fungus", false},
150     {"trunks:treeroot", false},
8e03d7 151 }
82cba9 152
e66bb2 153 local timber_nodenames = {}
C 154 for _, node in pairs(nodes) do
155     if chainsaw_leaves or node[2] then
156         timber_nodenames[node[1]] = true
72d541 157     end
T 158 end
159
5cf765 160 local S = technic.getter
S 161
162 technic.register_power_tool("technic:chainsaw", chainsaw_max_charge)
163
8e03d7 164 -- Table for saving what was sawed down
9019eb 165 local produced = {}
8e03d7 166
9019eb 167 -- Save the items sawed down so that we can drop them in a nice single stack
S 168 local function handle_drops(drops)
169     for _, item in ipairs(drops) do
170         local stack = ItemStack(item)
171         local name = stack:get_name()
172         local p = produced[name]
173         if not p then
174             produced[name] = stack
c63658 175         else
9019eb 176             p:set_count(p:get_count() + stack:get_count())
c63658 177         end
9019eb 178     end
S 179 end
180
181 --- Iterator over positions to try to saw around a sawed node.
ec069a 182 -- This returns positions in a 3x1x3 area around the position, plus the
S 183 -- position above it.  This does not return the bottom position to prevent
184 -- the chainsaw from cutting down nodes below the cutting position.
16302c 185 -- @param pos Sawing position.
9019eb 186 local function iterSawTries(pos)
16302c 187     -- Copy position to prevent mangling it
S 188     local pos = vector.new(pos)
ec069a 189     local i = 0
9019eb 190
S 191     return function()
ec069a 192         i = i + 1
S 193         -- Given a (top view) area like so (where 5 is the starting position):
194         -- X -->
195         -- Z 123
196         -- | 456
197         -- V 789
198         -- This will return positions 1, 4, 7, 2, 8 (skip 5), 3, 6, 9,
199         -- and the position above 5.
200         if i == 1 then
201             -- Move to starting position
202             pos.x = pos.x - 1
203             pos.z = pos.z - 1
204         elseif i == 4 or i == 7 then
205             -- Move to next X and back to start of Z when we reach
206             -- the end of a Z line.
9019eb 207             pos.x = pos.x + 1
ec069a 208             pos.z = pos.z - 2
S 209         elseif i == 5 then
210             -- Skip the middle position (we've already run on it)
211             -- and double-increment the counter.
212             pos.z = pos.z + 2
213             i = i + 1
214         elseif i <= 9 then
215             -- Go to next Z.
216             pos.z = pos.z + 1
217         elseif i == 10 then
218             -- Move back to center and up.
219             -- The Y+ position must be last so that we don't dig
220             -- straight upward and not come down (since the Y-
221             -- position isn't checked).
222             pos.x = pos.x - 1
223             pos.z = pos.z - 1
224             pos.y = pos.y + 1
9019eb 225         else
ec069a 226             return nil
9019eb 227         end
S 228         return pos
c63658 229     end
8e03d7 230 end
R 231
232 -- This function does all the hard work. Recursively we dig the node at hand
233 -- if it is in the table and then search the surroundings for more stuff to dig.
9019eb 234 local function recursive_dig(pos, remaining_charge)
S 235     if remaining_charge < chainsaw_charge_per_node then
c63658 236         return remaining_charge
P 237     end
9019eb 238     local node = minetest.get_node(pos)
S 239
240     if not timber_nodenames[node.name] then
241         return remaining_charge
242     end
243
ec069a 244     -- Wood found - cut it
9019eb 245     handle_drops(minetest.get_node_drops(node.name, ""))
S 246     minetest.remove_node(pos)
247     remaining_charge = remaining_charge - chainsaw_charge_per_node
248
249     -- Check surroundings and run recursively if any charge left
16302c 250     for npos in iterSawTries(pos) do
9019eb 251         if remaining_charge < chainsaw_charge_per_node then
S 252             break
253         end
16302c 254         if timber_nodenames[minetest.get_node(npos).name] then
S 255             remaining_charge = recursive_dig(npos, remaining_charge)
9019eb 256         end
S 257     end
c63658 258     return remaining_charge
P 259 end
260
261 -- Function to randomize positions for new node drops
262 local function get_drop_pos(pos)
263     local drop_pos = {}
264
265     for i = 0, 8 do
266         -- Randomize position for a new drop
267         drop_pos.x = pos.x + math.random(-3, 3)
268         drop_pos.y = pos.y - 1
269         drop_pos.z = pos.z + math.random(-3, 3)
270
271         -- Move the randomized position upwards until
272         -- the node is air or unloaded.
273         for y = drop_pos.y, drop_pos.y + 5 do
274             drop_pos.y = y
275             local node = minetest.get_node_or_nil(drop_pos)
276
277             if not node then
278                 -- If the node is not loaded yet simply drop
279                 -- the item at the original digging position.
280                 return pos
281             elseif node.name == "air" then
9019eb 282                 -- Add variation to the entity drop position,
S 283                 -- but don't let drops get too close to the edge
284                 drop_pos.x = drop_pos.x + (math.random() * 0.8) - 0.5
285                 drop_pos.z = drop_pos.z + (math.random() * 0.8) - 0.5
c63658 286                 return drop_pos
P 287             end
288         end
289     end
290
291     -- Return the original position if this takes too long
292     return pos
e23f87 293 end
19c9a0 294
9019eb 295 -- Chainsaw entry point
S 296 local function chainsaw_dig(pos, current_charge)
297     -- Start sawing things down
298     local remaining_charge = recursive_dig(pos, current_charge)
299     minetest.sound_play("chainsaw", {pos = pos, gain = 1.0,
300             max_hear_distance = 10})
5cf765 301
9019eb 302     -- Now drop items for the player
S 303     for name, stack in pairs(produced) do
304         -- Drop stacks of stack max or less
305         local count, max = stack:get_count(), stack:get_stack_max()
306         stack:set_count(max)
307         while count > max do
308             minetest.add_item(get_drop_pos(pos), stack)
309             count = count - max
c63658 310         end
9019eb 311         stack:set_count(count)
S 312         minetest.add_item(get_drop_pos(pos), stack)
313     end
314
315     -- Clean up
316     produced = {}
317
318     return remaining_charge
5cf765 319 end
S 320
321
322 minetest.register_tool("technic:chainsaw", {
323     description = S("Chainsaw"),
324     inventory_image = "technic_chainsaw.png",
325     stack_max = 1,
99fd5d 326     wear_represents = "technic_RE_charge",
00d7c9 327     on_refill = technic.refill_RE_charge,
5cf765 328     on_use = function(itemstack, user, pointed_thing)
S 329         if pointed_thing.type ~= "node" then
330             return itemstack
331         end
9019eb 332
5cf765 333         local meta = minetest.deserialize(itemstack:get_metadata())
9019eb 334         if not meta or not meta.charge or
S 335                 meta.charge < chainsaw_charge_per_node then
5cf765 336             return
S 337         end
338
9019eb 339         local name = user:get_player_name()
51c02e 340         if minetest.is_protected(pointed_thing.under, name) then
S 341             minetest.record_protection_violation(pointed_thing.under, name)
342             return
9019eb 343         end
S 344
345         -- Send current charge to digging function so that the
346         -- chainsaw will stop after digging a number of nodes
347         meta.charge = chainsaw_dig(pointed_thing.under, meta.charge)
b8c902 348         if not technic.creative_mode then
M 349             technic.set_RE_wear(itemstack, meta.charge, chainsaw_max_charge)
350             itemstack:set_metadata(minetest.serialize(meta))
351         end
5cf765 352         return itemstack
S 353     end,
354 })
355
e4c34c 356 local mesecons_button = minetest.get_modpath("mesecons_button")
T 357 local trigger = mesecons_button and "mesecons_button:button_off" or "default:mese_crystal_fragment"
358
5cf765 359 minetest.register_craft({
9019eb 360     output = "technic:chainsaw",
c63658 361     recipe = {
e4c34c 362         {"technic:stainless_steel_ingot", trigger,                      "technic:battery"},
44cb8d 363         {"basic_materials:copper_wire",      "basic_materials:motor",              "technic:battery"},
5e4a87 364         {"",                              "",                           "technic:stainless_steel_ingot"},
44cb8d 365     },
VD 366     replacements = { {"basic_materials:copper_wire", "basic_materials:empty_spool"}, },
367
5cf765 368 })
9019eb 369