diff options
Diffstat (limited to 'technic/tools')
-rw-r--r-- | technic/tools/cans.lua | 114 | ||||
-rw-r--r-- | technic/tools/chainsaw.lua | 366 | ||||
-rw-r--r-- | technic/tools/flashlight.lua | 123 | ||||
-rw-r--r-- | technic/tools/init.lua | 23 | ||||
-rw-r--r-- | technic/tools/mining_drill.lua | 419 | ||||
-rw-r--r-- | technic/tools/mining_lasers.lua | 178 | ||||
-rw-r--r-- | technic/tools/prospector.lua | 128 | ||||
-rw-r--r-- | technic/tools/sonic_screwdriver.lua | 98 | ||||
-rw-r--r-- | technic/tools/tree_tap.lua | 75 | ||||
-rw-r--r-- | technic/tools/vacuum.lua | 61 |
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', '', ''}, + } +}) |