summaryrefslogtreecommitdiff
path: root/technic/tools
diff options
context:
space:
mode:
Diffstat (limited to 'technic/tools')
-rw-r--r--technic/tools/cans.lua114
-rw-r--r--technic/tools/chainsaw.lua366
-rw-r--r--technic/tools/flashlight.lua123
-rw-r--r--technic/tools/init.lua23
-rw-r--r--technic/tools/mining_drill.lua419
-rw-r--r--technic/tools/mining_lasers.lua178
-rw-r--r--technic/tools/prospector.lua128
-rw-r--r--technic/tools/sonic_screwdriver.lua98
-rw-r--r--technic/tools/tree_tap.lua75
-rw-r--r--technic/tools/vacuum.lua61
10 files changed, 1585 insertions, 0 deletions
diff --git a/technic/tools/cans.lua b/technic/tools/cans.lua
new file mode 100644
index 0000000..f12ec93
--- /dev/null
+++ b/technic/tools/cans.lua
@@ -0,0 +1,114 @@
+local S = technic.getter
+
+local function set_can_wear(itemstack, level, max_level)
+ local temp
+ if level == 0 then
+ temp = 0
+ else
+ temp = 65536 - math.floor(level / max_level * 65535)
+ if temp > 65535 then temp = 65535 end
+ if temp < 1 then temp = 1 end
+ end
+ itemstack:set_wear(temp)
+end
+
+local function get_can_level(itemstack)
+ if itemstack:get_metadata() == "" then
+ return 0
+ else
+ return tonumber(itemstack:get_metadata())
+ end
+end
+
+function technic.register_can(d)
+ local data = {}
+ for k, v in pairs(d) do data[k] = v end
+ minetest.register_tool(data.can_name, {
+ description = data.can_description,
+ inventory_image = data.can_inventory_image,
+ stack_max = 1,
+ wear_represents = "content_level",
+ liquids_pointable = true,
+ on_use = function(itemstack, user, pointed_thing)
+ if pointed_thing.type ~= "node" then return end
+ local node = minetest.get_node(pointed_thing.under)
+ if node.name ~= data.liquid_source_name then return end
+ local charge = get_can_level(itemstack)
+ if charge == data.can_capacity then return end
+ if minetest.is_protected(pointed_thing.under, user:get_player_name()) then
+ minetest.log("action", user:get_player_name().." tried to take "..node.name.." at protected position "..minetest.pos_to_string(pointed_thing.under).." with a "..data.can_name)
+ return
+ end
+ minetest.remove_node(pointed_thing.under)
+ charge = charge + 1
+ itemstack:set_metadata(tostring(charge))
+ set_can_wear(itemstack, charge, data.can_capacity)
+ return itemstack
+ end,
+ on_place = function(itemstack, user, pointed_thing)
+ if pointed_thing.type ~= "node" then return end
+ local pos = pointed_thing.under
+ local def = minetest.registered_nodes[minetest.get_node(pos).name] or {}
+ if def.on_rightclick and user and not user:get_player_control().sneak then
+ return def.on_rightclick(pos, minetest.get_node(pos), user, itemstack, pointed_thing)
+ end
+ if not def.buildable_to then
+ pos = pointed_thing.above
+ def = minetest.registered_nodes[minetest.get_node(pos).name] or {}
+ if not def.buildable_to then return end
+ end
+ local charge = get_can_level(itemstack)
+ if charge == 0 then return end
+ if minetest.is_protected(pos, user:get_player_name()) then
+ minetest.log("action", user:get_player_name().." tried to place "..data.liquid_source_name.." at protected position "..minetest.pos_to_string(pos).." with a "..data.can_name)
+ return
+ end
+ minetest.set_node(pos, {name=data.liquid_source_name})
+ charge = charge - 1
+ itemstack:set_metadata(tostring(charge))
+ set_can_wear(itemstack, charge, data.can_capacity)
+ return itemstack
+ end,
+ on_refill = function(stack)
+ stack:set_metadata(tostring(data.can_capacity))
+ set_can_wear(stack, data.can_capacity, data.can_capacity)
+ return stack
+ end,
+ })
+end
+
+technic.register_can({
+ can_name = "technic:water_can",
+ can_description = S("Water Can"),
+ can_inventory_image = "technic_water_can.png",
+ can_capacity = 16,
+ liquid_source_name = "default:water_source",
+ liquid_flowing_name = "default:water_flowing",
+})
+
+minetest.register_craft({
+ output = 'technic:water_can 1',
+ recipe = {
+ {'technic:zinc_ingot', 'technic:rubber','technic:zinc_ingot'},
+ {'technic:carbon_steel_ingot', '', 'technic:carbon_steel_ingot'},
+ {'technic:zinc_ingot', 'technic:carbon_steel_ingot', 'technic:zinc_ingot'},
+ }
+})
+
+technic.register_can({
+ can_name = "technic:lava_can",
+ can_description = S("Lava Can"),
+ can_inventory_image = "technic_lava_can.png",
+ can_capacity = 8,
+ liquid_source_name = "default:lava_source",
+ liquid_flowing_name = "default:lava_flowing",
+})
+
+minetest.register_craft({
+ output = 'technic:lava_can 1',
+ recipe = {
+ {'technic:zinc_ingot', 'technic:stainless_steel_ingot','technic:zinc_ingot'},
+ {'technic:stainless_steel_ingot', '', 'technic:stainless_steel_ingot'},
+ {'technic:zinc_ingot', 'technic:stainless_steel_ingot', 'technic:zinc_ingot'},
+ }
+})
diff --git a/technic/tools/chainsaw.lua b/technic/tools/chainsaw.lua
new file mode 100644
index 0000000..bf4efff
--- /dev/null
+++ b/technic/tools/chainsaw.lua
@@ -0,0 +1,366 @@
+-- Configuration
+
+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,
+ ["default:pinetree"] = true,
+}
+
+if chainsaw_leaves then
+ timber_nodenames["default:leaves"] = true
+ timber_nodenames["default:jungleleaves"] = true
+ timber_nodenames["default:pine_needles"] = true
+end
+
+-- technic_worldgen defines rubber trees if moretrees isn't installed
+if minetest.get_modpath("technic_worldgen") or
+ minetest.get_modpath("moretrees") then
+ timber_nodenames["moretrees:rubber_tree_trunk_empty"] = true
+ timber_nodenames["moretrees:rubber_tree_trunk"] = true
+ if chainsaw_leaves then
+ timber_nodenames["moretrees:rubber_tree_leaves"] = true
+ end
+end
+
+-- Support moretrees if it is there
+if minetest.get_modpath("moretrees") then
+ timber_nodenames["moretrees:acacia_trunk"] = true
+ timber_nodenames["moretrees:apple_tree_trunk"] = true
+ timber_nodenames["moretrees:beech_trunk"] = true
+ timber_nodenames["moretrees:birch_trunk"] = true
+ timber_nodenames["moretrees:fir_trunk"] = true
+ timber_nodenames["moretrees:oak_trunk"] = true
+ timber_nodenames["moretrees:palm_trunk"] = true
+ timber_nodenames["moretrees:pine_trunk"] = true
+ timber_nodenames["moretrees:sequoia_trunk"] = true
+ timber_nodenames["moretrees:spruce_trunk"] = true
+ timber_nodenames["moretrees:willow_trunk"] = true
+ timber_nodenames["moretrees:jungletree_trunk"] = true
+
+ if chainsaw_leaves then
+ timber_nodenames["moretrees:acacia_leaves"] = true
+ 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
+ timber_nodenames["moretrees:acorn"] = true
+ timber_nodenames["moretrees:coconut"] = true
+ timber_nodenames["moretrees:spruce_cone"] = true
+ timber_nodenames["moretrees:pine_cone"] = true
+ timber_nodenames["moretrees:fir_cone"] = true
+ timber_nodenames["moretrees:apple_blossoms"] = true
+ end
+end
+
+-- Support growing_trees
+if minetest.get_modpath("growing_trees") then
+ 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
+
+ if chainsaw_leaves then
+ timber_nodenames["growing_trees:leaves"] = true
+ end
+end
+
+-- Support growing_cactus
+if minetest.get_modpath("growing_cactus") then
+ 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
+end
+
+-- Support farming_plus
+if minetest.get_modpath("farming_plus") then
+ if chainsaw_leaves then
+ timber_nodenames["farming_plus:banana_leaves"] = true
+ timber_nodenames["farming_plus:banana"] = true
+ timber_nodenames["farming_plus:cocoa_leaves"] = true
+ timber_nodenames["farming_plus:cocoa"] = true
+ end
+end
+
+-- Support nature
+if minetest.get_modpath("nature") then
+ if chainsaw_leaves then
+ timber_nodenames["nature:blossom"] = true
+ end
+end
+
+-- Support snow
+if minetest.get_modpath("snow") then
+ if chainsaw_leaves then
+ timber_nodenames["snow:needles"] = true
+ timber_nodenames["snow:needles_decorated"] = true
+ timber_nodenames["snow:star"] = true
+ end
+end
+
+-- Support vines (also generated by moretrees if available)
+if minetest.get_modpath("vines") then
+ if chainsaw_leaves then
+ timber_nodenames["vines:vines"] = true
+ end
+end
+
+if minetest.get_modpath("trunks") then
+ if chainsaw_leaves then
+ timber_nodenames["trunks:moss"] = true
+ timber_nodenames["trunks:moss_fungus"] = true
+ timber_nodenames["trunks:treeroot"] = true
+ end
+end
+
+local S = technic.getter
+
+technic.register_power_tool("technic:chainsaw", chainsaw_max_charge)
+
+-- Table for saving what was sawed down
+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 positions in a 3x1x3 area around the position, plus the
+-- position above it. This does not return the bottom position to prevent
+-- the chainsaw from cutting down nodes below the cutting position.
+-- @param pos Sawing position.
+local function iterSawTries(pos)
+ -- Copy position to prevent mangling it
+ local pos = vector.new(pos)
+ local i = 0
+
+ return function()
+ i = i + 1
+ -- Given a (top view) area like so (where 5 is the starting position):
+ -- X -->
+ -- Z 123
+ -- | 456
+ -- V 789
+ -- This will return positions 1, 4, 7, 2, 8 (skip 5), 3, 6, 9,
+ -- and the position above 5.
+ if i == 1 then
+ -- Move to starting position
+ pos.x = pos.x - 1
+ pos.z = pos.z - 1
+ elseif i == 4 or i == 7 then
+ -- Move to next X and back to start of Z when we reach
+ -- the end of a Z line.
+ pos.x = pos.x + 1
+ pos.z = pos.z - 2
+ elseif i == 5 then
+ -- Skip the middle position (we've already run on it)
+ -- and double-increment the counter.
+ pos.z = pos.z + 2
+ i = i + 1
+ elseif i <= 9 then
+ -- Go to next Z.
+ pos.z = pos.z + 1
+ elseif i == 10 then
+ -- Move back to center and up.
+ -- The Y+ position must be last so that we don't dig
+ -- straight upward and not come down (since the Y-
+ -- position isn't checked).
+ pos.x = pos.x - 1
+ pos.z = pos.z - 1
+ pos.y = pos.y + 1
+ else
+ return nil
+ end
+ return pos
+ end
+end
+
+-- 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.
+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)
+
+ if not timber_nodenames[node.name] then
+ return remaining_charge
+ end
+
+ -- Wood found - cut it
+ handle_drops(minetest.get_node_drops(node.name, ""))
+ minetest.remove_node(pos)
+ remaining_charge = remaining_charge - chainsaw_charge_per_node
+
+ -- Check surroundings and run recursively if any charge left
+ for npos in iterSawTries(pos) do
+ if remaining_charge < chainsaw_charge_per_node then
+ break
+ end
+ if timber_nodenames[minetest.get_node(npos).name] then
+ remaining_charge = recursive_dig(npos, remaining_charge)
+ 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
+ -- 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
+ return drop_pos
+ end
+ end
+ end
+
+ -- Return the original position if this takes too long
+ return pos
+end
+
+-- 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
+ end
+ stack:set_count(count)
+ minetest.add_item(get_drop_pos(pos), stack)
+ end
+
+ -- Clean up
+ produced = {}
+
+ return remaining_charge
+end
+
+
+minetest.register_tool("technic:chainsaw", {
+ description = S("Chainsaw"),
+ inventory_image = "technic_chainsaw.png",
+ stack_max = 1,
+ wear_represents = "technic_RE_charge",
+ on_refill = technic.refill_RE_charge,
+ on_use = function(itemstack, user, pointed_thing)
+ if pointed_thing.type ~= "node" then
+ return itemstack
+ end
+
+ local meta = minetest.deserialize(itemstack:get_metadata())
+ if not meta or not meta.charge or
+ meta.charge < chainsaw_charge_per_node then
+ return
+ end
+
+ local name = user:get_player_name()
+ if minetest.is_protected(pointed_thing.under, name) then
+ minetest.record_protection_violation(pointed_thing.under, name)
+ return
+ end
+
+ -- 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)
+ if not technic.creative_mode then
+ technic.set_RE_wear(itemstack, meta.charge, chainsaw_max_charge)
+ itemstack:set_metadata(minetest.serialize(meta))
+ end
+ return itemstack
+ end,
+})
+
+local mesecons_button = minetest.get_modpath("mesecons_button")
+local trigger = mesecons_button and "mesecons_button:button_off" or "default:mese_crystal_fragment"
+
+minetest.register_craft({
+ output = "technic:chainsaw",
+ recipe = {
+ {"technic:stainless_steel_ingot", trigger, "technic:battery"},
+ {"technic:fine_copper_wire", "technic:motor", "technic:battery"},
+ {"", "", "technic:stainless_steel_ingot"},
+ }
+})
+
diff --git a/technic/tools/flashlight.lua b/technic/tools/flashlight.lua
new file mode 100644
index 0000000..252dc8c
--- /dev/null
+++ b/technic/tools/flashlight.lua
@@ -0,0 +1,123 @@
+-- Original code comes from walkin_light mod by Echo
+-- http://minetest.net/forum/viewtopic.php?id=2621
+
+local flashlight_max_charge = 30000
+
+local S = technic.getter
+
+technic.register_power_tool("technic:flashlight", flashlight_max_charge)
+
+minetest.register_alias("technic:light_off", "air")
+
+minetest.register_tool("technic:flashlight", {
+ description = S("Flashlight"),
+ inventory_image = "technic_flashlight.png",
+ stack_max = 1,
+ wear_represents = "technic_RE_charge",
+ on_refill = technic.refill_RE_charge,
+})
+
+minetest.register_craft({
+ output = "technic:flashlight",
+ recipe = {
+ {"technic:rubber", "default:glass", "technic:rubber"},
+ {"technic:stainless_steel_ingot", "technic:battery", "technic:stainless_steel_ingot"},
+ {"", "technic:battery", ""}
+ }
+})
+
+
+local player_positions = {}
+local was_wielding = {}
+
+local function check_for_flashlight(player)
+ if player == nil then
+ return false
+ end
+ local inv = player:get_inventory()
+ local hotbar = inv:get_list("main")
+ for i = 1, 8 do
+ if hotbar[i]:get_name() == "technic:flashlight" then
+ local meta = minetest.deserialize(hotbar[i]:get_metadata())
+ if meta and meta.charge and meta.charge >= 2 then
+ if not technic.creative_mode then
+ meta.charge = meta.charge - 2;
+ technic.set_RE_wear(hotbar[i], meta.charge, flashlight_max_charge)
+ hotbar[i]:set_metadata(minetest.serialize(meta))
+ inv:set_stack("main", i, hotbar[i])
+ end
+ return true
+ end
+ end
+ end
+ return false
+end
+
+minetest.register_on_joinplayer(function(player)
+ local player_name = player:get_player_name()
+ local pos = player:getpos()
+ local rounded_pos = vector.round(pos)
+ rounded_pos.y = rounded_pos.y + 1
+ player_positions[player_name] = rounded_pos
+ was_wielding[player_name] = true
+end)
+
+
+minetest.register_on_leaveplayer(function(player)
+ local player_name = player:get_player_name()
+ local pos = player_positions[player_name]
+ local nodename = minetest.get_node(pos).name
+ if nodename == "technic:light" then
+ minetest.remove_node(pos)
+ end
+ player_positions[player_name] = nil
+end)
+
+minetest.register_globalstep(function(dtime)
+ for i, player in pairs(minetest.get_connected_players()) do
+ local player_name = player:get_player_name()
+ local flashlight_weared = check_for_flashlight(player)
+ local pos = player:getpos()
+ local rounded_pos = vector.round(pos)
+ rounded_pos.y = rounded_pos.y + 1
+ local old_pos = player_positions[player_name]
+ local player_moved = old_pos and not vector.equals(old_pos, rounded_pos)
+ if not old_pos then
+ old_pos = rounded_pos
+ player_moved = true
+ end
+
+ -- Remove light, flashlight weared out or was removed from hotbar
+ if was_wielding[player_name] and not flashlight_weared then
+ was_wielding[player_name] = false
+ local node = minetest.get_node_or_nil(old_pos)
+ if node and node.name == "technic:light" then
+ minetest.remove_node(old_pos)
+ end
+ elseif (player_moved or not was_wielding[player_name]) and flashlight_weared then
+ local node = minetest.get_node_or_nil(rounded_pos)
+ if node and node.name == "air" then
+ minetest.set_node(rounded_pos, {name="technic:light"})
+ end
+ local node = minetest.get_node_or_nil(old_pos)
+ if node and node.name == "technic:light" then
+ minetest.remove_node(old_pos)
+ end
+ player_positions[player_name] = rounded_pos
+ was_wielding[player_name] = true
+ end
+ end
+end)
+
+minetest.register_node("technic:light", {
+ drawtype = "glasslike",
+ tiles = {"technic_light.png"},
+ paramtype = "light",
+ groups = {not_in_creative_inventory=1},
+ drop = "",
+ walkable = false,
+ buildable_to = true,
+ sunlight_propagates = true,
+ light_source = LIGHT_MAX,
+ pointable = false,
+})
diff --git a/technic/tools/init.lua b/technic/tools/init.lua
new file mode 100644
index 0000000..5e0aa02
--- /dev/null
+++ b/technic/tools/init.lua
@@ -0,0 +1,23 @@
+local path = technic.modpath.."/tools"
+
+if technic.config:get_bool("enable_mining_drill") then
+ dofile(path.."/mining_drill.lua")
+end
+if technic.config:get_bool("enable_mining_laser") then
+ dofile(path.."/mining_lasers.lua")
+end
+if technic.config:get_bool("enable_flashlight") then
+ dofile(path.."/flashlight.lua")
+end
+dofile(path.."/cans.lua")
+dofile(path.."/chainsaw.lua")
+dofile(path.."/tree_tap.lua")
+dofile(path.."/sonic_screwdriver.lua")
+dofile(path.."/prospector.lua")
+dofile(path.."/vacuum.lua")
+
+if minetest.get_modpath("screwdriver") then
+ -- compatibility alias
+ minetest.register_alias("technic:screwdriver", "screwdriver:screwdriver")
+end
+
diff --git a/technic/tools/mining_drill.lua b/technic/tools/mining_drill.lua
new file mode 100644
index 0000000..8a25abe
--- /dev/null
+++ b/technic/tools/mining_drill.lua
@@ -0,0 +1,419 @@
+local max_charge = {50000, 200000, 650000}
+local power_usage_per_node = {200, 500, 800}
+
+local S = technic.getter
+
+minetest.register_craft({
+ output = 'technic:mining_drill',
+ recipe = {
+ {'moreores:tin_ingot', 'technic:diamond_drill_head', 'moreores:tin_ingot'},
+ {'technic:stainless_steel_ingot', 'technic:motor', 'technic:stainless_steel_ingot'},
+ {'', 'technic:red_energy_crystal', 'default:copper_ingot'},
+ }
+})
+minetest.register_craft({
+ output = 'technic:mining_drill_mk2',
+ recipe = {
+ {'technic:diamond_drill_head', 'technic:diamond_drill_head', 'technic:diamond_drill_head'},
+ {'technic:stainless_steel_ingot', 'technic:mining_drill', 'technic:stainless_steel_ingot'},
+ {'', 'technic:green_energy_crystal', ''},
+ }
+})
+minetest.register_craft({
+ output = 'technic:mining_drill_mk3',
+ recipe = {
+ {'technic:diamond_drill_head', 'technic:diamond_drill_head', 'technic:diamond_drill_head'},
+ {'technic:stainless_steel_ingot', 'technic:mining_drill_mk2', 'technic:stainless_steel_ingot'},
+ {'', 'technic:blue_energy_crystal', ''},
+ }
+})
+for i = 1, 4 do
+ minetest.register_craft({
+ output = 'technic:mining_drill_mk3',
+ recipe = {
+ {'technic:diamond_drill_head', 'technic:diamond_drill_head', 'technic:diamond_drill_head'},
+ {'technic:stainless_steel_ingot', 'technic:mining_drill_mk2_'..i, 'technic:stainless_steel_ingot'},
+ {'', 'technic:blue_energy_crystal', ''},
+ }
+ })
+end
+
+local mining_drill_mode_text = {
+ {S("Single node.")},
+ {S("3 nodes deep.")},
+ {S("3 nodes wide.")},
+ {S("3 nodes tall.")},
+ {S("3x3 nodes.")},
+}
+
+local function drill_dig_it0 (pos,player)
+ if minetest.is_protected(pos, player:get_player_name()) then
+ minetest.record_protection_violation(pos, player:get_player_name())
+ return
+ end
+ local node=minetest.get_node(pos)
+ if node.name == "air" or node.name == "ignore" then return end
+ if node.name == "default:lava_source" then return end
+ if node.name == "default:lava_flowing" then return end
+ if node.name == "default:water_source" then minetest.remove_node(pos) return end
+ if node.name == "default:water_flowing" then minetest.remove_node(pos) return end
+ minetest.node_dig(pos,node,player)
+end
+
+local function drill_dig_it1 (player)
+ local dir=player:get_look_dir()
+ if math.abs(dir.x)>math.abs(dir.z) then
+ if dir.x>0 then return 0 end
+ return 1
+ end
+ if dir.z>0 then return 2 end
+ return 3
+end
+
+local function drill_dig_it2 (pos,player)
+ drill_dig_it0 (pos,player)
+ pos.z=pos.z+1
+ drill_dig_it0 (pos,player)
+ pos.z=pos.z-2
+ drill_dig_it0 (pos,player)
+ pos.z=pos.z+1
+ pos.y=pos.y+1
+ drill_dig_it0 (pos,player)
+ pos.z=pos.z+1
+ drill_dig_it0 (pos,player)
+ pos.z=pos.z-2
+ drill_dig_it0 (pos,player)
+ pos.z=pos.z+1
+ pos.y=pos.y-2
+ drill_dig_it0 (pos,player)
+ pos.z=pos.z+1
+ drill_dig_it0 (pos,player)
+ pos.z=pos.z-2
+ drill_dig_it0 (pos,player)
+end
+
+local function drill_dig_it3 (pos,player)
+ drill_dig_it0 (pos,player)
+ pos.x=pos.x+1
+ drill_dig_it0 (pos,player)
+ pos.x=pos.x-2
+ drill_dig_it0 (pos,player)
+ pos.x=pos.x+1
+ pos.y=pos.y+1
+ drill_dig_it0 (pos,player)
+ pos.x=pos.x+1
+ drill_dig_it0 (pos,player)
+ pos.x=pos.x-2
+ drill_dig_it0 (pos,player)
+ pos.x=pos.x+1
+ pos.y=pos.y-2
+ drill_dig_it0 (pos,player)
+ pos.x=pos.x+1
+ drill_dig_it0 (pos,player)
+ pos.x=pos.x-2
+ drill_dig_it0 (pos,player)
+end
+
+local function drill_dig_it4 (pos,player)
+ drill_dig_it0 (pos,player)
+ pos.x=pos.x+1
+ drill_dig_it0 (pos,player)
+ pos.x=pos.x-2
+ drill_dig_it0 (pos,player)
+ pos.x=pos.x+1
+ pos.z=pos.z+1
+ drill_dig_it0 (pos,player)
+ pos.x=pos.x+1
+ drill_dig_it0 (pos,player)
+ pos.x=pos.x-2
+ drill_dig_it0 (pos,player)
+ pos.x=pos.x+1
+ pos.z=pos.z-2
+ drill_dig_it0 (pos,player)
+ pos.x=pos.x+1
+ drill_dig_it0 (pos,player)
+ pos.x=pos.x-2
+ drill_dig_it0 (pos,player)
+end
+
+local function cost_to_use(drill_type, mode)
+ local mult
+ if mode == 1 then
+ mult = 1
+ elseif mode <= 4 then
+ mult = 3
+ else
+ mult = 9
+ end
+ return power_usage_per_node[drill_type] * mult
+end
+
+local function drill_dig_it(pos, player, mode)
+ if mode == 1 then
+ drill_dig_it0(pos, player)
+ end
+
+ if mode == 2 then -- 3 deep
+ dir = drill_dig_it1(player)
+ if dir == 0 then -- x+
+ drill_dig_it0(pos, player)
+ pos.x = pos.x + 1
+ drill_dig_it0(pos, player)
+ pos.x = pos.x + 1
+ drill_dig_it0(pos, player)
+ end
+ if dir == 1 then -- x-
+ drill_dig_it0(pos, player)
+ pos.x=pos.x-1
+ drill_dig_it0 (pos,player)
+ pos.x=pos.x-1
+ drill_dig_it0 (pos,player)
+ end
+ if dir==2 then -- z+
+ drill_dig_it0 (pos,player)
+ pos.z=pos.z+1
+ drill_dig_it0 (pos,player)
+ pos.z=pos.z+1
+ drill_dig_it0 (pos,player)
+ end
+ if dir==3 then -- z-
+ drill_dig_it0 (pos,player)
+ pos.z=pos.z-1
+ drill_dig_it0 (pos,player)
+ pos.z=pos.z-1
+ drill_dig_it0 (pos,player)
+ end
+ end
+
+ if mode==3 then -- 3 wide
+ dir=drill_dig_it1(player)
+ if dir==0 or dir==1 then -- x
+ drill_dig_it0 (pos,player)
+ pos.z=pos.z+1
+ drill_dig_it0 (pos,player)
+ pos.z=pos.z-2
+ drill_dig_it0 (pos,player)
+ end
+ if dir==2 or dir==3 then -- z
+ drill_dig_it0 (pos,player)
+ pos.x=pos.x+1
+ drill_dig_it0 (pos,player)
+ pos.x=pos.x-2
+ drill_dig_it0 (pos,player)
+ end
+ end
+
+ if mode==4 then -- 3 tall, selected in the middle
+ drill_dig_it0 (pos,player)
+ pos.y=pos.y-1
+ drill_dig_it0 (pos,player)
+ pos.y=pos.y-1
+ drill_dig_it0 (pos,player)
+ end
+
+ if mode==5 then -- 3 x 3
+ local dir=player:get_look_dir()
+ if math.abs(dir.y)<0.5 then
+ dir=drill_dig_it1(player)
+ if dir==0 or dir==1 then -- x
+ drill_dig_it2(pos,player)
+ end
+ if dir==2 or dir==3 then -- z
+ drill_dig_it3(pos,player)
+ end
+ else
+ drill_dig_it4(pos,player)
+ end
+ end
+
+ minetest.sound_play("mining_drill", {pos = pos, gain = 1.0, max_hear_distance = 10,})
+end
+
+local function pos_is_pointable(pos)
+ local node = minetest.get_node(pos)
+ local nodedef = minetest.registered_nodes[node.name]
+ return nodedef and nodedef.pointable
+end
+
+local function mining_drill_mk2_setmode(user,itemstack)
+ local player_name=user:get_player_name()
+ local item=itemstack:to_table()
+ local meta=minetest.deserialize(item["metadata"])
+ if meta==nil then
+ meta={}
+ mode=0
+ end
+ if meta["mode"]==nil then
+ minetest.chat_send_player(player_name, S("Use while sneaking to change Mining Drill Mk%d modes."):format(2))
+ meta["mode"]=0
+ mode=0
+ end
+ mode=(meta["mode"])
+ mode=mode+1
+ if mode>=5 then mode=1 end
+ minetest.chat_send_player(player_name, S("Mining Drill Mk%d Mode %d"):format(2, mode)..": "..mining_drill_mode_text[mode][1])
+ item["name"]="technic:mining_drill_mk2_"..mode
+ meta["mode"]=mode
+ item["metadata"]=minetest.serialize(meta)
+ itemstack:replace(item)
+ return itemstack
+end
+
+local function mining_drill_mk3_setmode(user,itemstack)
+ local player_name=user:get_player_name()
+ local item=itemstack:to_table()
+ local meta=minetest.deserialize(item["metadata"])
+ if meta==nil then
+ meta={}
+ mode=0
+ end
+ if meta["mode"]==nil then
+ minetest.chat_send_player(player_name, S("Use while sneaking to change Mining Drill Mk%d modes."):format(3))
+ meta["mode"]=0
+ mode=0
+ end
+ mode=(meta["mode"])
+ mode=mode+1
+ if mode>=6 then mode=1 end
+ minetest.chat_send_player(player_name, S("Mining Drill Mk%d Mode %d"):format(3, mode)..": "..mining_drill_mode_text[mode][1])
+ item["name"]="technic:mining_drill_mk3_"..mode
+ meta["mode"]=mode
+ item["metadata"]=minetest.serialize(meta)
+ itemstack:replace(item)
+ return itemstack
+end
+
+
+local function mining_drill_mk2_handler(itemstack, user, pointed_thing)
+ local keys = user:get_player_control()
+ local player_name = user:get_player_name()
+ local meta = minetest.deserialize(itemstack:get_metadata())
+ if not meta or not meta.mode or keys.sneak then
+ return mining_drill_mk2_setmode(user, itemstack)
+ end
+ if pointed_thing.type ~= "node" or not pos_is_pointable(pointed_thing.under) or not meta.charge then
+ return
+ end
+ local charge_to_take = cost_to_use(2, meta.mode)
+ if meta.charge >= charge_to_take then
+ local pos = minetest.get_pointed_thing_position(pointed_thing, above)
+ drill_dig_it(pos, user, meta.mode)
+ if not technic.creative_mode then
+ meta.charge = meta.charge - charge_to_take
+ itemstack:set_metadata(minetest.serialize(meta))
+ technic.set_RE_wear(itemstack, meta.charge, max_charge[2])
+ end
+ end
+ return itemstack
+end
+
+local function mining_drill_mk3_handler(itemstack, user, pointed_thing)
+ local keys = user:get_player_control()
+ local player_name = user:get_player_name()
+ local meta = minetest.deserialize(itemstack:get_metadata())
+ if not meta or not meta.mode or keys.sneak then
+ return mining_drill_mk3_setmode(user, itemstack)
+ end
+ if pointed_thing.type ~= "node" or not pos_is_pointable(pointed_thing.under) or not meta.charge then
+ return
+ end
+ local charge_to_take = cost_to_use(3, meta.mode)
+ if meta.charge >= charge_to_take then
+ local pos = minetest.get_pointed_thing_position(pointed_thing, above)
+ drill_dig_it(pos, user, meta.mode)
+ if not technic.creative_mode then
+ meta.charge = meta.charge - charge_to_take
+ itemstack:set_metadata(minetest.serialize(meta))
+ technic.set_RE_wear(itemstack, meta.charge, max_charge[3])
+ end
+ end
+ return itemstack
+end
+
+technic.register_power_tool("technic:mining_drill", max_charge[1])
+
+minetest.register_tool("technic:mining_drill", {
+ description = S("Mining Drill Mk%d"):format(1),
+ inventory_image = "technic_mining_drill.png",
+ stack_max = 1,
+ wear_represents = "technic_RE_charge",
+ on_refill = technic.refill_RE_charge,
+ on_use = function(itemstack, user, pointed_thing)
+ if pointed_thing.type ~= "node" or not pos_is_pointable(pointed_thing.under) then
+ return itemstack
+ end
+ local meta = minetest.deserialize(itemstack:get_metadata())
+ if not meta or not meta.charge then
+ return
+ end
+ local charge_to_take = cost_to_use(1, 1)
+ if meta.charge >= charge_to_take then
+ local pos = minetest.get_pointed_thing_position(pointed_thing, above)
+ drill_dig_it(pos, user, 1)
+ if not technic.creative_mode then
+ meta.charge = meta.charge - charge_to_take
+ itemstack:set_metadata(minetest.serialize(meta))
+ technic.set_RE_wear(itemstack, meta.charge, max_charge[1])
+ end
+ end
+ return itemstack
+ end,
+})
+
+minetest.register_tool("technic:mining_drill_mk2", {
+ description = S("Mining Drill Mk%d"):format(2),
+ inventory_image = "technic_mining_drill_mk2.png",
+ wear_represents = "technic_RE_charge",
+ on_refill = technic.refill_RE_charge,
+ on_use = function(itemstack, user, pointed_thing)
+ mining_drill_mk2_handler(itemstack, user, pointed_thing)
+ return itemstack
+ end,
+})
+
+technic.register_power_tool("technic:mining_drill_mk2", max_charge[2])
+
+for i = 1, 4 do
+ technic.register_power_tool("technic:mining_drill_mk2_"..i, max_charge[2])
+ minetest.register_tool("technic:mining_drill_mk2_"..i, {
+ description = S("Mining Drill Mk%d Mode %d"):format(2, i),
+ inventory_image = "technic_mining_drill_mk2.png^technic_tool_mode"..i..".png",
+ wield_image = "technic_mining_drill_mk2.png",
+ wear_represents = "technic_RE_charge",
+ on_refill = technic.refill_RE_charge,
+ groups = {not_in_creative_inventory=1},
+ on_use = function(itemstack, user, pointed_thing)
+ mining_drill_mk2_handler(itemstack, user, pointed_thing)
+ return itemstack
+ end,
+ })
+end
+
+minetest.register_tool("technic:mining_drill_mk3", {
+ description = S("Mining Drill Mk%d"):format(3),
+ inventory_image = "technic_mining_drill_mk3.png",
+ wear_represents = "technic_RE_charge",
+ on_refill = technic.refill_RE_charge,
+ on_use = function(itemstack, user, pointed_thing)
+ mining_drill_mk3_handler(itemstack,user,pointed_thing)
+ return itemstack
+ end,
+})
+
+technic.register_power_tool("technic:mining_drill_mk3", max_charge[3])
+
+for i=1,5,1 do
+ technic.register_power_tool("technic:mining_drill_mk3_"..i, max_charge[3])
+ minetest.register_tool("technic:mining_drill_mk3_"..i, {
+ description = S("Mining Drill Mk%d Mode %d"):format(3, i),
+ inventory_image = "technic_mining_drill_mk3.png^technic_tool_mode"..i..".png",
+ wield_image = "technic_mining_drill_mk3.png",
+ wear_represents = "technic_RE_charge",
+ on_refill = technic.refill_RE_charge,
+ groups = {not_in_creative_inventory=1},
+ on_use = function(itemstack, user, pointed_thing)
+ mining_drill_mk3_handler(itemstack,user,pointed_thing)
+ return itemstack
+ end,
+ })
+end
diff --git a/technic/tools/mining_lasers.lua b/technic/tools/mining_lasers.lua
new file mode 100644
index 0000000..4c83ae9
--- /dev/null
+++ b/technic/tools/mining_lasers.lua
@@ -0,0 +1,178 @@
+local mining_lasers_list = {
+-- {<num>, <range of the laser shots>, <max_charge>, <charge_per_shot>},
+ {"1", 7, 50000, 1000},
+ {"2", 14, 200000, 2000},
+ {"3", 21, 650000, 3000},
+}
+
+local S = technic.getter
+
+minetest.register_craft({
+ output = 'technic:laser_mk1',
+ recipe = {
+ {'default:diamond', 'technic:brass_ingot', 'default:obsidian_glass'},
+ {'', 'technic:brass_ingot', 'technic:red_energy_crystal'},
+ {'', '', 'default:copper_ingot'},
+ }
+})
+minetest.register_craft({
+ output = 'technic:laser_mk2',
+ recipe = {
+ {'default:diamond', 'technic:carbon_steel_ingot', 'technic:laser_mk1'},
+ {'', 'technic:carbon_steel_ingot', 'technic:green_energy_crystal'},
+ {'', '', 'default:copper_ingot'},
+ }
+})
+minetest.register_craft({
+ output = 'technic:laser_mk3',
+ recipe = {
+ {'default:diamond', 'technic:carbon_steel_ingot', 'technic:laser_mk2'},
+ {'', 'technic:carbon_steel_ingot', 'technic:blue_energy_crystal'},
+ {'', '', 'default:copper_ingot'},
+ }
+})
+
+-- Based on code by Uberi: https://gist.github.com/Uberi/3125280
+local function rayIter(pos, dir, range)
+ local p = vector.round(pos)
+ local x_step, y_step, z_step = 0, 0, 0
+ local x_component, y_component, z_component = 0, 0, 0
+ local x_intersect, y_intersect, z_intersect = 0, 0, 0
+
+ if dir.x == 0 then
+ x_intersect = math.huge
+ elseif dir.x > 0 then
+ x_step = 1
+ x_component = 1 / dir.x
+ x_intersect = x_component
+ else
+ x_step = -1
+ x_component = 1 / -dir.x
+ end
+ if dir.y == 0 then
+ y_intersect = math.huge
+ elseif dir.y > 0 then
+ y_step = 1
+ y_component = 1 / dir.y
+ y_intersect = y_component
+ else
+ y_step = -1
+ y_component = 1 / -dir.y
+ end
+ if dir.z == 0 then
+ z_intersect = math.huge
+ elseif dir.z > 0 then
+ z_step = 1
+ z_component = 1 / dir.z
+ z_intersect = z_component
+ else
+ z_step = -1
+ z_component = 1 / -dir.z
+ end
+
+ return function()
+ if x_intersect < y_intersect then
+ if x_intersect < z_intersect then
+ p.x = p.x + x_step
+ x_intersect = x_intersect + x_component
+ else
+ p.z = p.z + z_step
+ z_intersect = z_intersect + z_component
+ end
+ elseif y_intersect < z_intersect then
+ p.y = p.y + y_step
+ y_intersect = y_intersect + y_component
+ else
+ p.z = p.z + z_step
+ z_intersect = z_intersect + z_component
+ end
+ if vector.distance(pos, p) > range then
+ return nil
+ end
+ return p
+ end
+end
+
+local function laser_node(pos, node, player)
+ local def = minetest.registered_nodes[node.name]
+ if def and def.liquidtype ~= "none" then
+ minetest.remove_node(pos)
+ minetest.add_particle({
+ pos = pos,
+ vel = {x=0, y=2, z=0},
+ acc = {x=0, y=-1, z=0},
+ expirationtime = 1.5,
+ size = 6 + math.random() * 2,
+ texture = "smoke_puff.png^[transform" .. math.random(0, 7),
+ })
+ return
+ end
+ minetest.node_dig(pos, node, player)
+end
+
+local no_destroy = {
+ ["air"] = true,
+ ["default:lava_source"] = true,
+ ["default:lava_flowing"] = true,
+}
+local function laser_shoot(player, range, particle_texture, sound)
+ local player_pos = player:getpos()
+ local player_name = player:get_player_name()
+ local dir = player:get_look_dir()
+
+ local start_pos = vector.new(player_pos)
+ -- Adjust to head height
+ start_pos.y = start_pos.y + 1.9
+ minetest.add_particle({
+ pos = startpos,
+ vel = dir,
+ acc = vector.multiply(dir, 50),
+ expirationtime = range / 11,
+ size = 1,
+ texture = particle_texture .. "^[transform" .. math.random(0, 7),
+ })
+ minetest.sound_play(sound, {pos = player_pos, max_hear_distance = range})
+ for pos in rayIter(start_pos, dir, range) do
+ if minetest.is_protected(pos, player_name) then
+ minetest.record_protection_violation(pos, player_name)
+ break
+ end
+ local node = minetest.get_node_or_nil(pos)
+ if not node then
+ break
+ end
+ if not no_destroy[node.name] then
+ laser_node(pos, node, player)
+ end
+ end
+end
+
+
+for _, m in pairs(mining_lasers_list) do
+ technic.register_power_tool("technic:laser_mk"..m[1], m[3])
+ minetest.register_tool("technic:laser_mk"..m[1], {
+ description = S("Mining Laser Mk%d"):format(m[1]),
+ inventory_image = "technic_mining_laser_mk"..m[1]..".png",
+ stack_max = 1,
+ wear_represents = "technic_RE_charge",
+ on_refill = technic.refill_RE_charge,
+ on_use = function(itemstack, user)
+ local meta = minetest.deserialize(itemstack:get_metadata())
+ if not meta or not meta.charge then
+ return
+ end
+
+ -- If there's enough charge left, fire the laser
+ if meta.charge >= m[4] then
+ laser_shoot(user, m[2], "technic_laser_beam_mk"..m[1]..".png", "technic_laser_mk"..m[1])
+ if not technic.creative_mode then
+ meta.charge = meta.charge - m[4]
+ technic.set_RE_wear(itemstack, meta.charge, m[3])
+ itemstack:set_metadata(minetest.serialize(meta))
+ end
+ end
+ return itemstack
+ end,
+ })
+end
+
diff --git a/technic/tools/prospector.lua b/technic/tools/prospector.lua
new file mode 100644
index 0000000..b28f1d8
--- /dev/null
+++ b/technic/tools/prospector.lua
@@ -0,0 +1,128 @@
+local S = technic.getter
+
+technic.register_power_tool("technic:prospector", 300000)
+
+local function get_metadata(toolstack)
+ local m = minetest.deserialize(toolstack:get_metadata())
+ if not m then m = {} end
+ if not m.charge then m.charge = 0 end
+ if not m.target then m.target = "" end
+ if not m.look_depth then m.look_depth = 7 end
+ if not m.look_radius then m.look_radius = 1 end
+ return m
+end
+
+minetest.register_tool("technic:prospector", {
+ description = S("Prospector"),
+ inventory_image = "technic_prospector.png",
+ wear_represents = "technic_RE_charge",
+ on_refill = technic.refill_RE_charge,
+ on_use = function(toolstack, user, pointed_thing)
+ if not user or not user:is_player() or user.is_fake_player then return end
+ if pointed_thing.type ~= "node" then return end
+ local toolmeta = get_metadata(toolstack)
+ local look_diameter = toolmeta.look_radius * 2 + 1
+ local charge_to_take = toolmeta.look_depth * (toolmeta.look_depth + 1) * look_diameter * look_diameter
+ if toolmeta.charge < charge_to_take then return end
+ if toolmeta.target == "" then
+ minetest.chat_send_player(user:get_player_name(), "Right-click to set target block type")
+ return
+ end
+ if not technic.creative_mode then
+ toolmeta.charge = toolmeta.charge - charge_to_take
+ toolstack:set_metadata(minetest.serialize(toolmeta))
+ technic.set_RE_wear(toolstack, toolmeta.charge, technic.power_tools[toolstack:get_name()])
+ end
+ local start_pos = pointed_thing.under
+ local forward = minetest.facedir_to_dir(minetest.dir_to_facedir(user:get_look_dir(), true))
+ local right = forward.x ~= 0 and { x=0, y=1, z=0 } or (forward.y ~= 0 and { x=0, y=0, z=1 } or { x=1, y=0, z=0 })
+ local up = forward.x ~= 0 and { x=0, y=0, z=1 } or (forward.y ~= 0 and { x=1, y=0, z=0 } or { x=0, y=1, z=0 })
+ local base_pos = vector.add(start_pos, vector.multiply(vector.add(right, up), - toolmeta.look_radius))
+ local found = false
+ for f = 0, toolmeta.look_depth-1 do
+ for r = 0, look_diameter-1 do
+ for u = 0, look_diameter-1 do
+ if minetest.get_node(vector.add(vector.add(vector.add(base_pos, vector.multiply(forward, f)), vector.multiply(right, r)), vector.multiply(up, u))).name == toolmeta.target then found = true end
+ end
+ end
+ end
+ if math.random() < 0.02 then found = not found end
+ minetest.chat_send_player(user:get_player_name(), minetest.registered_nodes[toolmeta.target].description.." is "..(found and "present" or "absent").." in "..look_diameter.."x"..look_diameter.."x"..toolmeta.look_depth.." region")
+ minetest.sound_play("technic_prospector_"..(found and "hit" or "miss"), { pos = vector.add(user:getpos(), { x = 0, y = 1, z = 0 }), gain = 1.0, max_hear_distance = 10 })
+ return toolstack
+ end,
+ on_place = function(toolstack, user, pointed_thing)
+ if not user or not user:is_player() or user.is_fake_player then return end
+ local toolmeta = get_metadata(toolstack)
+ local pointed
+ if pointed_thing.type == "node" then
+ local pname = minetest.get_node(pointed_thing.under).name
+ local pdef = minetest.registered_nodes[pname]
+ if pdef and (pdef.groups.not_in_creative_inventory or 0) == 0 and pname ~= toolmeta.target then
+ pointed = pname
+ end
+ end
+ local look_diameter = toolmeta.look_radius * 2 + 1
+ minetest.show_formspec(user:get_player_name(), "technic:prospector_control",
+ "size[7,8.5]"..
+ "item_image[0,0;1,1;"..toolstack:get_name().."]"..
+ "label[1,0;"..minetest.formspec_escape(toolstack:get_definition().description).."]"..
+ (toolmeta.target ~= "" and
+ "label[0,1.5;Current target:]"..
+ "label[0,2;"..minetest.formspec_escape(minetest.registered_nodes[toolmeta.target].description).."]"..
+ "item_image[0,2.5;1,1;"..toolmeta.target.."]" or
+ "label[0,1.5;No target set]")..
+ (pointed and
+ "label[3.5,1.5;May set new target:]"..
+ "label[3.5,2;"..minetest.formspec_escape(minetest.registered_nodes[pointed].description).."]"..
+ "item_image[3.5,2.5;1,1;"..pointed.."]"..
+ "button_exit[3.5,3.65;2,0.5;target_"..pointed..";Set target]" or
+ "label[3.5,1.5;No new target available]")..
+ "label[0,4.5;Region cross section:]"..
+ "label[0,5;"..look_diameter.."x"..look_diameter.."]"..
+ "label[3.5,4.5;Set region cross section:]"..
+ "button_exit[3.5,5.15;1,0.5;look_radius_0;1x1]"..
+ "button_exit[4.5,5.15;1,0.5;look_radius_1;3x3]"..
+ "button_exit[5.5,5.15;1,0.5;look_radius_3;7x7]"..
+ "label[0,6;Region depth:]"..
+ "label[0,6.5;"..toolmeta.look_depth.."]"..
+ "label[3.5,6;Set region depth:]"..
+ "button_exit[3.5,6.65;1,0.5;look_depth_7;7]"..
+ "button_exit[4.5,6.65;1,0.5;look_depth_14;14]"..
+ "button_exit[5.5,6.65;1,0.5;look_depth_21;21]"..
+ "label[0,7.5;Accuracy:]"..
+ "label[0,8;98%]")
+ return
+ end,
+})
+
+minetest.register_on_player_receive_fields(function(user, formname, fields)
+ if formname ~= "technic:prospector_control" then return false end
+ if not user or not user:is_player() or user.is_fake_player then return end
+ local toolstack = user:get_wielded_item()
+ if toolstack:get_name() ~= "technic:prospector" then return true end
+ local toolmeta = get_metadata(toolstack)
+ for field, value in pairs(fields) do
+ if field:sub(1, 7) == "target_" then
+ toolmeta.target = field:sub(8)
+ end
+ if field:sub(1, 12) == "look_radius_" then
+ toolmeta.look_radius = field:sub(13)
+ end
+ if field:sub(1, 11) == "look_depth_" then
+ toolmeta.look_depth = field:sub(12)
+ end
+ end
+ toolstack:set_metadata(minetest.serialize(toolmeta))
+ user:set_wielded_item(toolstack)
+ return true
+end)
+
+minetest.register_craft({
+ output = "technic:prospector",
+ recipe = {
+ {"moreores:pick_silver", "moreores:mithril_block", "pipeworks:teleport_tube_1"},
+ {"technic:brass_ingot", "technic:control_logic_unit", "technic:brass_ingot"},
+ {"", "technic:blue_energy_crystal", ""},
+ }
+})
diff --git a/technic/tools/sonic_screwdriver.lua b/technic/tools/sonic_screwdriver.lua
new file mode 100644
index 0000000..300d363
--- /dev/null
+++ b/technic/tools/sonic_screwdriver.lua
@@ -0,0 +1,98 @@
+local sonic_screwdriver_max_charge = 15000
+
+local S = technic.getter
+
+technic.register_power_tool("technic:sonic_screwdriver", sonic_screwdriver_max_charge)
+
+-- screwdriver handler code reused from minetest/minetest_game screwdriver @a9ac480
+local ROTATE_FACE = 1
+local ROTATE_AXIS = 2
+
+local function nextrange(x, max)
+ x = x + 1
+ if x > max then
+ x = 0
+ end
+ return x
+end
+
+-- Handles rotation
+local function screwdriver_handler(itemstack, user, pointed_thing, mode)
+ if pointed_thing.type ~= "node" then
+ return
+ end
+
+ local pos = pointed_thing.under
+
+ if minetest.is_protected(pos, user:get_player_name()) then
+ minetest.record_protection_violation(pos, user:get_player_name())
+ return
+ end
+
+ local node = minetest.get_node(pos)
+ local ndef = minetest.registered_nodes[node.name]
+ if not ndef or not ndef.paramtype2 == "facedir" or
+ (ndef.drawtype == "nodebox" and
+ not ndef.node_box.type == "fixed") or
+ node.param2 == nil then
+ return
+ end
+
+ -- contrary to the default screwdriver, do not check for can_dig, to allow rotating machines with CLU's in them
+ -- this is consistent with the previous sonic screwdriver
+
+ local meta1 = minetest.deserialize(itemstack:get_metadata())
+ if not meta1 or not meta1.charge or meta1.charge < 100 then
+ return
+ end
+
+ minetest.sound_play("technic_sonic_screwdriver", {pos = pos, gain = 0.3, max_hear_distance = 10})
+
+ -- Set param2
+ local rotationPart = node.param2 % 32 -- get first 4 bits
+ local preservePart = node.param2 - rotationPart
+
+ local axisdir = math.floor(rotationPart / 4)
+ local rotation = rotationPart - axisdir * 4
+ if mode == ROTATE_FACE then
+ rotationPart = axisdir * 4 + nextrange(rotation, 3)
+ elseif mode == ROTATE_AXIS then
+ rotationPart = nextrange(axisdir, 5) * 4
+ end
+
+ node.param2 = preservePart + rotationPart
+ minetest.swap_node(pos, node)
+
+ if not technic.creative_mode then
+ meta1.charge = meta1.charge - 100
+ itemstack:set_metadata(minetest.serialize(meta1))
+ technic.set_RE_wear(itemstack, meta1.charge, sonic_screwdriver_max_charge)
+ end
+
+ return itemstack
+end
+
+minetest.register_tool("technic:sonic_screwdriver", {
+ description = S("Sonic Screwdriver (left-click rotates face, right-click rotates axis)"),
+ inventory_image = "technic_sonic_screwdriver.png",
+ wear_represents = "technic_RE_charge",
+ on_refill = technic.refill_RE_charge,
+ on_use = function(itemstack, user, pointed_thing)
+ screwdriver_handler(itemstack, user, pointed_thing, ROTATE_FACE)
+ return itemstack
+ end,
+ on_place = function(itemstack, user, pointed_thing)
+ screwdriver_handler(itemstack, user, pointed_thing, ROTATE_AXIS)
+ return itemstack
+ end,
+})
+
+minetest.register_craft({
+ output = "technic:sonic_screwdriver",
+ recipe = {
+ {"", "default:diamond", ""},
+ {"mesecons_materials:fiber", "technic:battery", "mesecons_materials:fiber"},
+ {"mesecons_materials:fiber", "moreores:mithril_ingot", "mesecons_materials:fiber"}
+ }
+})
+
diff --git a/technic/tools/tree_tap.lua b/technic/tools/tree_tap.lua
new file mode 100644
index 0000000..e84fe33
--- /dev/null
+++ b/technic/tools/tree_tap.lua
@@ -0,0 +1,75 @@
+
+local S = technic.getter
+local mesecons_materials = minetest.get_modpath("mesecons_materials")
+
+minetest.register_tool("technic:treetap", {
+ description = S("Tree Tap"),
+ inventory_image = "technic_tree_tap.png",
+ on_use = function(itemstack, user, pointed_thing)
+ if pointed_thing.type ~= "node" then
+ return
+ end
+ local pos = pointed_thing.under
+ if minetest.is_protected(pos, user:get_player_name()) then
+ minetest.record_protection_violation(pos, user:get_player_name())
+ return
+ end
+ local node = minetest.get_node(pos)
+ local node_name = node.name
+ if node_name ~= "moretrees:rubber_tree_trunk" then
+ return
+ end
+ node.name = "moretrees:rubber_tree_trunk_empty"
+ minetest.swap_node(pos, node)
+ minetest.handle_node_drops(pointed_thing.above, {"technic:raw_latex"}, user)
+ if not technic.creative_mode then
+ local item_wear = tonumber(itemstack:get_wear())
+ item_wear = item_wear + 819
+ if item_wear > 65535 then
+ itemstack:clear()
+ return itemstack
+ end
+ itemstack:set_wear(item_wear)
+ end
+ return itemstack
+ end,
+})
+
+minetest.register_craft({
+ output = "technic:treetap",
+ recipe = {
+ {"pipeworks:tube_1", "group:wood", "default:stick"},
+ {"", "default:stick", "default:stick"}
+ },
+})
+
+minetest.register_craftitem("technic:raw_latex", {
+ description = S("Raw Latex"),
+ inventory_image = "technic_raw_latex.png",
+})
+
+if mesecons_materials then
+ minetest.register_craft({
+ type = "cooking",
+ recipe = "technic:raw_latex",
+ output = "mesecons_materials:glue",
+ })
+end
+
+minetest.register_craftitem("technic:rubber", {
+ description = S("Rubber Fiber"),
+ inventory_image = "technic_rubber.png",
+})
+
+minetest.register_abm({
+ nodenames = {"moretrees:rubber_tree_trunk_empty"},
+ interval = 60,
+ chance = 15,
+ action = function(pos, node)
+ if minetest.find_node_near(pos, (moretrees and moretrees.leafdecay_radius) or 5, {"moretrees:rubber_tree_leaves"}) then
+ node.name = "moretrees:rubber_tree_trunk"
+ minetest.swap_node(pos, node)
+ end
+ end
+})
+
diff --git a/technic/tools/vacuum.lua b/technic/tools/vacuum.lua
new file mode 100644
index 0000000..f5fac9a
--- /dev/null
+++ b/technic/tools/vacuum.lua
@@ -0,0 +1,61 @@
+-- Configuration
+local vacuum_max_charge = 10000 -- 10000 - Maximum charge of the vacuum cleaner
+local vacuum_charge_per_object = 100 -- 100 - Capable of picking up 50 objects
+local vacuum_range = 8 -- 8 - Area in which to pick up objects
+
+local S = technic.getter
+
+technic.register_power_tool("technic:vacuum", vacuum_max_charge)
+
+minetest.register_tool("technic:vacuum", {
+ description = S("Vacuum Cleaner"),
+ inventory_image = "technic_vacuum.png",
+ stack_max = 1,
+ wear_represents = "technic_RE_charge",
+ on_refill = technic.refill_RE_charge,
+ on_use = function(itemstack, user, pointed_thing)
+ local meta = minetest.deserialize(itemstack:get_metadata())
+ if not meta or not meta.charge then
+ return
+ end
+ if meta.charge > vacuum_charge_per_object then
+ minetest.sound_play("vacuumcleaner", {
+ to_player = user:get_player_name(),
+ gain = 0.4,
+ })
+ end
+ local pos = user:getpos()
+ local inv = user:get_inventory()
+ for _, object in ipairs(minetest.env:get_objects_inside_radius(pos, vacuum_range)) do
+ local luaentity = object:get_luaentity()
+ if not object:is_player() and luaentity and luaentity.name == "__builtin:item" and luaentity.itemstring ~= "" then
+ if inv and inv:room_for_item("main", ItemStack(luaentity.itemstring)) then
+ meta.charge = meta.charge - vacuum_charge_per_object
+ if meta.charge < vacuum_charge_per_object then
+ return
+ end
+ inv:add_item("main", ItemStack(luaentity.itemstring))
+ minetest.sound_play("item_drop_pickup", {
+ to_player = user:get_player_name(),
+ gain = 0.4,
+ })
+ luaentity.itemstring = ""
+ object:remove()
+ end
+ end
+ end
+
+ technic.set_RE_wear(itemstack, meta.charge, vacuum_max_charge)
+ itemstack:set_metadata(minetest.serialize(meta))
+ return itemstack
+ end,
+})
+
+minetest.register_craft({
+ output = 'technic:vacuum',
+ recipe = {
+ {'pipeworks:tube_1', 'pipeworks:filter', 'technic:battery'},
+ {'pipeworks:tube_1', 'technic:motor', 'technic:battery'},
+ {'technic:stainless_steel_ingot', '', ''},
+ }
+})