2013-06-30 07:12:02 +02:00
|
|
|
-- Configuration
|
2014-06-26 17:13:30 +02:00
|
|
|
|
|
|
|
local chainsaw_max_charge = 30000 -- Maximum charge of the saw
|
|
|
|
-- Gives 2500 nodes on a single charge (about 50 complete normal trees)
|
|
|
|
local chainsaw_charge_per_node = 12
|
|
|
|
-- Cut down tree leaves. Leaf decay may cause slowness on large trees
|
|
|
|
-- if this is disabled.
|
|
|
|
local chainsaw_leaves = true
|
|
|
|
|
|
|
|
-- The default trees
|
|
|
|
local timber_nodenames = {
|
|
|
|
["default:jungletree"] = true,
|
|
|
|
["default:papyrus"] = true,
|
|
|
|
["default:cactus"] = true,
|
|
|
|
["default:tree"] = true,
|
|
|
|
["default:apple"] = true,
|
2013-06-30 07:12:02 +02:00
|
|
|
}
|
|
|
|
|
2014-06-26 17:13:30 +02:00
|
|
|
if chainsaw_leaves then
|
2014-06-08 09:46:19 +02:00
|
|
|
timber_nodenames["default:leaves"] = true
|
|
|
|
timber_nodenames["default:jungleleaves"] = true
|
2013-06-30 07:12:02 +02:00
|
|
|
end
|
|
|
|
|
2013-07-17 21:34:35 +02:00
|
|
|
-- technic_worldgen defines rubber trees if moretrees isn't installed
|
|
|
|
if minetest.get_modpath("technic_worldgen") or
|
2014-06-26 17:13:30 +02:00
|
|
|
minetest.get_modpath("moretrees") then
|
2013-07-17 21:34:35 +02:00
|
|
|
timber_nodenames["moretrees:rubber_tree_trunk_empty"] = true
|
|
|
|
timber_nodenames["moretrees:rubber_tree_trunk"] = true
|
|
|
|
if chainsaw_leaves then
|
2014-05-04 18:59:37 +02:00
|
|
|
timber_nodenames["moretrees:rubber_tree_leaves"] = true
|
2013-07-17 21:34:35 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-06-30 07:12:02 +02:00
|
|
|
-- Support moretrees if it is there
|
2014-06-26 17:13:30 +02:00
|
|
|
if minetest.get_modpath("moretrees") then
|
2014-05-04 18:59:37 +02:00
|
|
|
timber_nodenames["moretrees:apple_tree_trunk"] = true
|
|
|
|
timber_nodenames["moretrees:apple_tree_trunk_sideways"] = true
|
|
|
|
timber_nodenames["moretrees:beech_trunk"] = true
|
|
|
|
timber_nodenames["moretrees:beech_trunk_sideways"] = true
|
|
|
|
timber_nodenames["moretrees:birch_trunk"] = true
|
|
|
|
timber_nodenames["moretrees:birch_trunk_sideways"] = true
|
|
|
|
timber_nodenames["moretrees:fir_trunk"] = true
|
|
|
|
timber_nodenames["moretrees:fir_trunk_sideways"] = true
|
|
|
|
timber_nodenames["moretrees:oak_trunk"] = true
|
|
|
|
timber_nodenames["moretrees:oak_trunk_sideways"] = true
|
|
|
|
timber_nodenames["moretrees:palm_trunk"] = true
|
|
|
|
timber_nodenames["moretrees:palm_trunk_sideways"] = true
|
|
|
|
timber_nodenames["moretrees:pine_trunk"] = true
|
|
|
|
timber_nodenames["moretrees:pine_trunk_sideways"] = true
|
|
|
|
timber_nodenames["moretrees:rubber_tree_trunk_sideways"] = true
|
|
|
|
timber_nodenames["moretrees:rubber_tree_trunk_sideways_empty"] = true
|
|
|
|
timber_nodenames["moretrees:sequoia_trunk"] = true
|
|
|
|
timber_nodenames["moretrees:sequoia_trunk_sideways"] = true
|
|
|
|
timber_nodenames["moretrees:spruce_trunk"] = true
|
|
|
|
timber_nodenames["moretrees:spruce_trunk_sideways"] = true
|
|
|
|
timber_nodenames["moretrees:willow_trunk"] = true
|
|
|
|
timber_nodenames["moretrees:willow_trunk_sideways"] = true
|
|
|
|
timber_nodenames["moretrees:jungletree_trunk"] = true
|
|
|
|
timber_nodenames["moretrees:jungletree_trunk_sideways"] = true
|
|
|
|
|
|
|
|
if chainsaw_leaves then
|
|
|
|
timber_nodenames["moretrees:apple_tree_leaves"] = true
|
|
|
|
timber_nodenames["moretrees:oak_leaves"] = true
|
|
|
|
timber_nodenames["moretrees:fir_leaves"] = true
|
|
|
|
timber_nodenames["moretrees:fir_leaves_bright"] = true
|
|
|
|
timber_nodenames["moretrees:sequoia_leaves"] = true
|
|
|
|
timber_nodenames["moretrees:birch_leaves"] = true
|
|
|
|
timber_nodenames["moretrees:birch_leaves"] = true
|
|
|
|
timber_nodenames["moretrees:palm_leaves"] = true
|
|
|
|
timber_nodenames["moretrees:spruce_leaves"] = true
|
|
|
|
timber_nodenames["moretrees:spruce_leaves"] = true
|
|
|
|
timber_nodenames["moretrees:pine_leaves"] = true
|
|
|
|
timber_nodenames["moretrees:willow_leaves"] = true
|
|
|
|
timber_nodenames["moretrees:jungletree_leaves_green"] = true
|
|
|
|
timber_nodenames["moretrees:jungletree_leaves_yellow"] = true
|
|
|
|
timber_nodenames["moretrees:jungletree_leaves_red"] = true
|
|
|
|
end
|
2013-06-30 07:12:02 +02:00
|
|
|
end
|
|
|
|
|
2014-06-26 17:13:30 +02:00
|
|
|
-- Support growing_trees
|
|
|
|
if minetest.get_modpath("growing_trees") then
|
2014-05-04 18:59:37 +02:00
|
|
|
timber_nodenames["growing_trees:trunk"] = true
|
|
|
|
timber_nodenames["growing_trees:medium_trunk"] = true
|
|
|
|
timber_nodenames["growing_trees:big_trunk"] = true
|
|
|
|
timber_nodenames["growing_trees:trunk_top"] = true
|
|
|
|
timber_nodenames["growing_trees:trunk_sprout"] = true
|
|
|
|
timber_nodenames["growing_trees:branch_sprout"] = true
|
|
|
|
timber_nodenames["growing_trees:branch"] = true
|
|
|
|
timber_nodenames["growing_trees:branch_xmzm"] = true
|
|
|
|
timber_nodenames["growing_trees:branch_xpzm"] = true
|
|
|
|
timber_nodenames["growing_trees:branch_xmzp"] = true
|
|
|
|
timber_nodenames["growing_trees:branch_xpzp"] = true
|
|
|
|
timber_nodenames["growing_trees:branch_zz"] = true
|
|
|
|
timber_nodenames["growing_trees:branch_xx"] = true
|
|
|
|
|
2014-06-26 17:13:30 +02:00
|
|
|
if chainsaw_leaves then
|
2014-05-04 18:59:37 +02:00
|
|
|
timber_nodenames["growing_trees:leaves"] = true
|
|
|
|
end
|
2013-06-30 07:12:02 +02:00
|
|
|
end
|
|
|
|
|
2014-06-26 17:13:30 +02:00
|
|
|
-- Support growing_cactus
|
|
|
|
if minetest.get_modpath("growing_cactus") then
|
2014-05-04 18:59:37 +02:00
|
|
|
timber_nodenames["growing_cactus:sprout"] = true
|
|
|
|
timber_nodenames["growing_cactus:branch_sprout_vertical"] = true
|
|
|
|
timber_nodenames["growing_cactus:branch_sprout_vertical_fixed"] = true
|
|
|
|
timber_nodenames["growing_cactus:branch_sprout_xp"] = true
|
|
|
|
timber_nodenames["growing_cactus:branch_sprout_xm"] = true
|
|
|
|
timber_nodenames["growing_cactus:branch_sprout_zp"] = true
|
|
|
|
timber_nodenames["growing_cactus:branch_sprout_zm"] = true
|
|
|
|
timber_nodenames["growing_cactus:trunk"] = true
|
|
|
|
timber_nodenames["growing_cactus:branch_trunk"] = true
|
|
|
|
timber_nodenames["growing_cactus:branch"] = true
|
|
|
|
timber_nodenames["growing_cactus:branch_xp"] = true
|
|
|
|
timber_nodenames["growing_cactus:branch_xm"] = true
|
|
|
|
timber_nodenames["growing_cactus:branch_zp"] = true
|
|
|
|
timber_nodenames["growing_cactus:branch_zm"] = true
|
|
|
|
timber_nodenames["growing_cactus:branch_zz"] = true
|
|
|
|
timber_nodenames["growing_cactus:branch_xx"] = true
|
2013-06-30 07:12:02 +02:00
|
|
|
end
|
|
|
|
|
2014-06-26 17:13:30 +02:00
|
|
|
-- Support farming_plus
|
|
|
|
if minetest.get_modpath("farming_plus") then
|
|
|
|
if chainsaw_leaves then
|
2014-05-04 18:59:37 +02:00
|
|
|
timber_nodenames["farming_plus:cocoa_leaves"] = true
|
|
|
|
end
|
2013-06-30 07:12:02 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
|
2013-12-17 19:56:37 +01:00
|
|
|
local S = technic.getter
|
2013-06-30 07:12:02 +02:00
|
|
|
|
2013-12-17 19:56:37 +01:00
|
|
|
technic.register_power_tool("technic:chainsaw", chainsaw_max_charge)
|
2013-06-30 07:12:02 +02:00
|
|
|
|
2013-12-17 19:56:37 +01:00
|
|
|
-- Table for saving what was sawed down
|
2014-06-26 17:13:30 +02:00
|
|
|
local produced = {}
|
|
|
|
|
|
|
|
-- Save the items sawed down so that we can drop them in a nice single stack
|
|
|
|
local function handle_drops(drops)
|
|
|
|
for _, item in ipairs(drops) do
|
|
|
|
local stack = ItemStack(item)
|
|
|
|
local name = stack:get_name()
|
|
|
|
local p = produced[name]
|
|
|
|
if not p then
|
|
|
|
produced[name] = stack
|
|
|
|
else
|
|
|
|
p:set_count(p:get_count() + stack:get_count())
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Iterator over positions to try to saw around a sawed node.
|
|
|
|
-- This returns nodes in a 3x2x3 area. It does not return lower (y) positions
|
|
|
|
-- to prevent the chainsaw from cutting down nodes below the cutting position.
|
|
|
|
-- @param pos Reference to sawing position. Note that this is overridden.
|
|
|
|
local function iterSawTries(pos)
|
|
|
|
-- Shift the position down on the x and z axes
|
|
|
|
pos.x, pos.z = pos.x - 1, pos.z - 1
|
|
|
|
-- Save our starting position for reseting it later
|
|
|
|
local startx, startz = pos.x, pos.z
|
|
|
|
-- We will move out by one in every direction except -y
|
|
|
|
local endx, endy, endz = pos.x + 2, pos.y + 1, pos.z + 2
|
|
|
|
-- Adjust for initial increment
|
|
|
|
pos.x = pos.x - 1
|
|
|
|
|
|
|
|
return function()
|
|
|
|
if pos.x < endx then
|
|
|
|
pos.x = pos.x + 1
|
2014-05-04 18:59:37 +02:00
|
|
|
else
|
2014-06-26 17:13:30 +02:00
|
|
|
pos.x = startx
|
|
|
|
if pos.z < endz then
|
|
|
|
pos.z = pos.z + 1
|
|
|
|
else
|
|
|
|
pos.z = startz
|
|
|
|
if pos.y < endy then
|
|
|
|
pos.y = pos.y + 1
|
|
|
|
else
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
end
|
2014-05-04 18:59:37 +02:00
|
|
|
end
|
2014-06-26 17:13:30 +02:00
|
|
|
return pos
|
2014-05-04 18:59:37 +02:00
|
|
|
end
|
2013-06-30 07:12:02 +02:00
|
|
|
end
|
2013-01-27 14:03:46 +01:00
|
|
|
|
2013-06-30 07:12:02 +02:00
|
|
|
-- 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.
|
2014-06-26 17:13:30 +02:00
|
|
|
local function recursive_dig(pos, remaining_charge)
|
|
|
|
if remaining_charge < chainsaw_charge_per_node then
|
|
|
|
return remaining_charge
|
|
|
|
end
|
|
|
|
local node = minetest.get_node(pos)
|
2014-05-04 18:59:37 +02:00
|
|
|
|
2014-06-26 17:13:30 +02:00
|
|
|
if not timber_nodenames[node.name] then
|
|
|
|
return remaining_charge
|
|
|
|
end
|
2014-05-04 18:59:37 +02:00
|
|
|
|
2014-06-26 17:13:30 +02:00
|
|
|
-- wood found - cut it
|
|
|
|
handle_drops(minetest.get_node_drops(node.name, ""))
|
|
|
|
minetest.remove_node(pos)
|
|
|
|
remaining_charge = remaining_charge - chainsaw_charge_per_node
|
2014-05-04 18:59:37 +02:00
|
|
|
|
2014-06-26 17:13:30 +02:00
|
|
|
-- Check surroundings and run recursively if any charge left
|
|
|
|
for pos in iterSawTries(pos) do
|
|
|
|
if remaining_charge < chainsaw_charge_per_node then
|
|
|
|
break
|
2014-05-04 18:59:37 +02:00
|
|
|
end
|
2014-06-26 17:13:30 +02:00
|
|
|
if timber_nodenames[minetest.get_node(pos).name] then
|
|
|
|
remaining_charge = recursive_dig(pos, remaining_charge)
|
2014-05-04 18:59:37 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
return remaining_charge
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Function to randomize positions for new node drops
|
|
|
|
local function get_drop_pos(pos)
|
|
|
|
local drop_pos = {}
|
|
|
|
|
|
|
|
for i = 0, 8 do
|
|
|
|
-- Randomize position for a new drop
|
|
|
|
drop_pos.x = pos.x + math.random(-3, 3)
|
|
|
|
drop_pos.y = pos.y - 1
|
|
|
|
drop_pos.z = pos.z + math.random(-3, 3)
|
|
|
|
|
|
|
|
-- Move the randomized position upwards until
|
|
|
|
-- the node is air or unloaded.
|
|
|
|
for y = drop_pos.y, drop_pos.y + 5 do
|
|
|
|
drop_pos.y = y
|
|
|
|
local node = minetest.get_node_or_nil(drop_pos)
|
|
|
|
|
|
|
|
if not node then
|
|
|
|
-- If the node is not loaded yet simply drop
|
|
|
|
-- the item at the original digging position.
|
|
|
|
return pos
|
|
|
|
elseif node.name == "air" then
|
2014-06-26 17:13:30 +02:00
|
|
|
-- Add variation to the entity drop position,
|
|
|
|
-- but don't let drops get too close to the edge
|
|
|
|
drop_pos.x = drop_pos.x + (math.random() * 0.8) - 0.5
|
|
|
|
drop_pos.z = drop_pos.z + (math.random() * 0.8) - 0.5
|
2014-05-04 18:59:37 +02:00
|
|
|
return drop_pos
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Return the original position if this takes too long
|
|
|
|
return pos
|
2013-02-21 22:01:49 +01:00
|
|
|
end
|
2013-07-08 22:53:44 +02:00
|
|
|
|
2014-06-26 17:13:30 +02:00
|
|
|
-- Chainsaw entry point
|
|
|
|
local function chainsaw_dig(pos, current_charge)
|
|
|
|
-- Start sawing things down
|
|
|
|
local remaining_charge = recursive_dig(pos, current_charge)
|
|
|
|
minetest.sound_play("chainsaw", {pos = pos, gain = 1.0,
|
|
|
|
max_hear_distance = 10})
|
|
|
|
|
|
|
|
-- Now drop items for the player
|
|
|
|
for name, stack in pairs(produced) do
|
|
|
|
-- Drop stacks of stack max or less
|
|
|
|
local count, max = stack:get_count(), stack:get_stack_max()
|
|
|
|
stack:set_count(max)
|
|
|
|
while count > max do
|
|
|
|
minetest.add_item(get_drop_pos(pos), stack)
|
|
|
|
count = count - max
|
2014-05-04 18:59:37 +02:00
|
|
|
end
|
2014-06-26 17:13:30 +02:00
|
|
|
stack:set_count(count)
|
|
|
|
minetest.add_item(get_drop_pos(pos), stack)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Clean up
|
|
|
|
produced = {}
|
|
|
|
|
|
|
|
return remaining_charge
|
2013-12-17 19:56:37 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
minetest.register_tool("technic:chainsaw", {
|
|
|
|
description = S("Chainsaw"),
|
|
|
|
inventory_image = "technic_chainsaw.png",
|
|
|
|
stack_max = 1,
|
Genericise handling of multiple meanings of wear
The tool workshop is meant to repair mechanical damage to tools, so
is at risk of `repairing' tools that use the wear bar to represent
something other than mechanical wear. It had special-case recognition
of the water and lava cans, which use the wear bar to represent how much
content they're carrying, and wouldn't repair them. But it didn't avoid
`repairing' RE chargeable items, which use the wear bar to represent
how much energy they have stored. It would modify the wear bar without
actually affecting the charge, so the wear bar would jump back to the
correct place when the next charging or discharging event occurred.
To genericise, introduce a new item property, "wear_represents", which
indicates how the wear bar is used for this item. Currently defined
values are "mechanical_wear" (straightforward damage to tools that
start out perfect), "technic_RE_charge" (electrical energy, canonically
represented in the meta rather than the wear bar), and "content_level"
(how full a container is). For backcompat, nil is interpreted as
"mechanical_wear". The tool workshop will only repair "mechanical_wear"
tools. As a bonus, set_RE_wear() will only set the wear bar for
"technic_RE_charge" items: this means developers will notice if they
forget to declare wear_represents, but also means that with no further
changes it's possible to have an RE chargeable item that uses its wear
bar to represent something else.
2014-04-28 11:44:07 +02:00
|
|
|
wear_represents = "technic_RE_charge",
|
2014-04-30 11:49:54 +02:00
|
|
|
on_refill = technic.refill_RE_charge,
|
2013-12-17 19:56:37 +01:00
|
|
|
on_use = function(itemstack, user, pointed_thing)
|
|
|
|
if pointed_thing.type ~= "node" then
|
|
|
|
return itemstack
|
|
|
|
end
|
2014-06-26 17:13:30 +02:00
|
|
|
|
2013-12-17 19:56:37 +01:00
|
|
|
local meta = minetest.deserialize(itemstack:get_metadata())
|
2014-06-26 17:13:30 +02:00
|
|
|
if not meta or not meta.charge or
|
|
|
|
meta.charge < chainsaw_charge_per_node then
|
2013-12-17 19:56:37 +01:00
|
|
|
return
|
|
|
|
end
|
2014-06-26 17:13:30 +02:00
|
|
|
|
|
|
|
local name = user:get_player_name()
|
2014-06-26 22:53:38 +02:00
|
|
|
if minetest.is_protected(pointed_thing.under, name) then
|
|
|
|
minetest.record_protection_violation(pointed_thing.under, name)
|
|
|
|
return
|
2013-12-17 19:56:37 +01:00
|
|
|
end
|
|
|
|
|
2014-06-26 17:13:30 +02:00
|
|
|
-- Send current charge to digging function so that the
|
|
|
|
-- chainsaw will stop after digging a number of nodes
|
|
|
|
meta.charge = chainsaw_dig(pointed_thing.under, meta.charge)
|
|
|
|
|
2013-12-17 19:56:37 +01:00
|
|
|
technic.set_RE_wear(itemstack, meta.charge, chainsaw_max_charge)
|
|
|
|
itemstack:set_metadata(minetest.serialize(meta))
|
|
|
|
return itemstack
|
|
|
|
end,
|
|
|
|
})
|
|
|
|
|
|
|
|
minetest.register_craft({
|
2014-06-26 17:13:30 +02:00
|
|
|
output = "technic:chainsaw",
|
2014-05-04 18:59:37 +02:00
|
|
|
recipe = {
|
2014-07-07 22:48:38 +02:00
|
|
|
{"technic:stainless_steel_ingot", "mesecons_button:button_off", "technic:battery"},
|
|
|
|
{"technic:fine_copper_wire", "technic:motor", "technic:battery"},
|
|
|
|
{"", "", "technic:stainless_steel_ingot"},
|
2014-05-04 18:59:37 +02:00
|
|
|
}
|
2013-12-17 19:56:37 +01:00
|
|
|
})
|
2014-06-26 17:13:30 +02:00
|
|
|
|