Add mods: technic, moreores, paintings, Nyancat (Pbj_pup). Small fix: sandwiches

This commit is contained in:
N-Nachtigal 2025-06-05 16:15:56 +02:00
parent 15e8e696a2
commit fb09deddc1
1404 changed files with 156555 additions and 211 deletions

View file

@ -0,0 +1,138 @@
local S = technic.getter
local mat = technic.materials
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_meta():get_string("") == "" then
return 0
else
return tonumber(itemstack:get_meta():get_string(""))
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 node_name = minetest.get_node(pos).name
local def = minetest.registered_nodes[node_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 or node_name == data.liquid_source_name then
pos = pointed_thing.above
node_name = minetest.get_node(pos).name
def = minetest.registered_nodes[node_name] or {}
-- Try to place node above the pointed source, or abort.
if not def.buildable_to or node_name == data.liquid_source_name 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 = mat.water_source,
liquid_flowing_name = mat.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 = mat.lava_source,
liquid_flowing_name = mat.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'},
}
})
technic.register_can({
can_name = 'technic:river_water_can',
can_description = S("River Water Can"),
can_inventory_image = "technic_river_water_can.png",
can_capacity = 16,
liquid_source_name = mat.river_water_source,
liquid_flowing_name = mat.river_water_flowing,
})
minetest.register_craft({
output = 'technic:river_water_can 1',
recipe = {
{'technic:zinc_ingot', 'technic:rubber', 'technic:zinc_ingot'},
{mat.steel_ingot, '', mat.steel_ingot},
{'technic:zinc_ingot', mat.steel_ingot, 'technic:zinc_ingot'},
}
})

View file

@ -0,0 +1,228 @@
-- Configuration
local chainsaw_max_charge = 30000 -- Maximum charge of the saw
local chainsaw_charge_per_node = 12 -- Gives 2500 nodes on a single charge (about 50 complete normal trees)
local chainsaw_leaves = true -- Cut down tree leaves.
-- Leaf decay may cause slowness on large trees if this is disabled.
local chainsaw_vines = true -- Cut down vines
local timber_nodenames = {} -- Cuttable nodes
local max_saw_radius = 12 -- max x/z distance away from starting position to allow cutting
-- Prevents forest destruction, increase for extra wide trees
-- Support for nodes not in any supported node groups (tree, leaves, leafdecay, leafdecay_drop)
timber_nodenames["default:papyrus"] = true
timber_nodenames["default:cactus"] = true
timber_nodenames["default:bush_stem"] = true
timber_nodenames["default:acacia_bush_stem"] = true
timber_nodenames["default:pine_bush_stem"] = true
if minetest.get_modpath("growing_trees") then
timber_nodenames["growing_trees:branch_sprout"] = true
if chainsaw_leaves then
timber_nodenames["growing_trees:leaves"] = true
end
end
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
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
if minetest.get_modpath("ethereal") then
timber_nodenames["ethereal:bamboo"] = true
end
local S = technic.getter
-- 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
-- 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, origin, 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 for snow on pine trees, sand/gravel on leaves, etc
minetest.check_for_falling(pos)
-- Check surroundings and run recursively if any charge left
for y=-1, 1 do
if (pos.y + y) >= origin.y then
for x=-1, 1 do
if (pos.x + x) <= (origin.x + max_saw_radius) and (pos.x + x) >= (origin.x - max_saw_radius) then
for z=-1, 1 do
if (pos.z + z) <= (origin.z + max_saw_radius) and (pos.z + z) >= (origin.z - max_saw_radius) then
local npos = {x=pos.x+x, y=pos.y+y, z=pos.z+z}
if remaining_charge < chainsaw_charge_per_node then
return remaining_charge
end
if timber_nodenames[minetest.get_node(npos).name] then
remaining_charge = recursive_dig(npos, origin, remaining_charge)
end
end
end
end
end
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, pos, current_charge)
minetest.sound_play("chainsaw", {pos = pos, gain = 1.0, max_hear_distance = 10}, true)
-- 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
technic.register_power_tool("technic:chainsaw", {
description = S("Chainsaw"),
inventory_image = "technic_chainsaw.png",
max_charge = chainsaw_max_charge,
on_use = function(itemstack, user, pointed_thing)
if pointed_thing.type ~= "node" then
return
end
local charge = technic.get_charge(itemstack)
if 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
charge = chainsaw_dig(pointed_thing.under, charge)
if not technic.creative_mode then
technic.set_charge(itemstack, charge)
end
return itemstack
end,
})
local mesecons_button = minetest.get_modpath("mesecons_button")
local has_mcl = minetest.get_modpath("mcl_core")
local trigger = has_mcl and mesecons_button and "mesecons_button:button_wood_off"
or 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"},
{"basic_materials:copper_wire", "basic_materials:motor", "technic:battery"},
{"", "", "technic:stainless_steel_ingot"},
},
replacements = { {"basic_materials:copper_wire", "basic_materials:empty_spool"}, },
})
-- Add cuttable nodes after all mods loaded
minetest.after(0, function ()
for k, v in pairs(minetest.registered_nodes) do
if v.groups.tree then
timber_nodenames[k] = true
elseif chainsaw_leaves and (v.groups.leaves or v.groups.leafdecay or v.groups.leafdecay_drop) then
timber_nodenames[k] = true
elseif chainsaw_vines and v.groups.vines then
timber_nodenames[k] = true
end
end
end)

View file

@ -0,0 +1,115 @@
-- 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
local mat = technic.materials
minetest.register_alias("technic:light_off", "air")
technic.register_power_tool("technic:flashlight", {
description = S("Flashlight"),
inventory_image = "technic_flashlight.png",
max_charge = flashlight_max_charge,
})
minetest.register_craft({
output = "technic:flashlight",
recipe = {
{"technic:rubber", mat.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" and technic.use_charge(hotbar[i], 2) then
-- See https://github.com/minetest/minetest/issues/9377 for wield item animation
inv:set_stack("main", i, hotbar[i])
return true
end
end
return false
end
minetest.register_on_joinplayer(function(player)
local player_name = player:get_player_name()
local pos = player:get_pos()
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:get_pos()
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
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)
if minetest.get_modpath("mcl_core") then
minetest.register_alias("technic:light", "mcl_core:light_14")
else
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 = minetest.LIGHT_MAX,
pointable = false,
})
end

View file

@ -0,0 +1,21 @@
local path = technic.modpath.."/tools"
local function enabled(name)
return technic.config:get_bool("enable_" .. name)
end
if enabled("mining_drill") then dofile(path.."/mining_drill.lua") end
if enabled("mining_laser") then dofile(path.."/mining_lasers.lua") end
if enabled("flashlight") then dofile(path.."/flashlight.lua") end
if enabled("cans") then dofile(path.."/cans.lua") end
if enabled("chainsaw") then dofile(path.."/chainsaw.lua") end
if enabled("tree_tap") then dofile(path.."/tree_tap.lua") end
if enabled("sonic_screwdriver") then dofile(path.."/sonic_screwdriver.lua") end
if enabled("prospector") then dofile(path.."/prospector.lua") end
if enabled("vacuum") then dofile(path.."/vacuum.lua") end
if enabled("multimeter") then dofile(path.."/multimeter.lua") end
if minetest.get_modpath("screwdriver") then
-- compatibility alias
minetest.register_alias("technic:screwdriver", "screwdriver:screwdriver")
end

View file

@ -0,0 +1,358 @@
local max_charge = {50000, 200000, 300000}
local power_usage_per_node = {200, 500, 600}
local S = technic.getter
local mat = technic.materials
minetest.register_craft({
output = 'technic:mining_drill',
recipe = {
{mat.tin_ingot, 'technic:diamond_drill_head', mat.tin_ingot},
{'technic:stainless_steel_ingot', 'basic_materials:motor', 'technic:stainless_steel_ingot'},
{'', 'technic:red_energy_crystal', mat.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 get_description(mk, mode)
local description = "Mining Drill Mk@1"..(mode > 0 and " Mode @2" or "")
return mode > 0 and S(description, mk, mode) or S(description, mk)
end
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 == mat.lava_source then return end
if node.name == mat.lava_flowing then return end
if node.name == mat.water_source then minetest.remove_node(pos) return end
if node.name == mat.water_flowing then minetest.remove_node(pos) return end
local def = minetest.registered_nodes[node.name]
if not def then return end
def.on_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)
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-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-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)
end
local function drill_dig_it3 (pos,player)
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-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-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)
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
local 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
local 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}, true)
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 meta = itemstack:get_meta()
local mode = meta:get_int("mode")
if mode == 0 then
minetest.chat_send_player(player_name, S("Use while sneaking to change Mining Drill Mk@1 modes.", 2))
end
mode = mode < 4 and mode + 1 or 1
minetest.chat_send_player(player_name, get_description(2, mode)..": "..mining_drill_mode_text[mode][1])
itemstack:set_name("technic:mining_drill_mk2_"..mode)
meta:set_int("mode", mode)
return itemstack
end
local function mining_drill_mk3_setmode(user,itemstack)
local player_name = user:get_player_name()
local meta = itemstack:get_meta()
local mode = meta:get_int("mode")
if mode == 0 then
minetest.chat_send_player(player_name, S("Use while sneaking to change Mining Drill Mk@1 modes.", 3))
end
mode = mode < 5 and mode + 1 or 1
minetest.chat_send_player(player_name, get_description(3, mode)..": "..mining_drill_mode_text[mode][1])
itemstack:set_name("technic:mining_drill_mk3_"..mode)
meta:set_int("mode", mode)
return itemstack
end
local function mining_drill_mk2_handler(itemstack, user, pointed_thing)
local keys = user:get_player_control()
local meta = itemstack:get_meta()
local mode = meta:get_int("mode")
if mode == 0 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) then
return
end
local charge_to_take = cost_to_use(2, mode)
if technic.use_charge(itemstack, charge_to_take) then
local pos = minetest.get_pointed_thing_position(pointed_thing, false)
drill_dig_it(pos, user, mode)
end
return itemstack
end
local function mining_drill_mk3_handler(itemstack, user, pointed_thing)
local keys = user:get_player_control()
local meta = itemstack:get_meta()
local mode = meta:get_int("mode")
if mode == 0 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) then
return
end
local charge_to_take = cost_to_use(3, mode)
if technic.use_charge(itemstack, charge_to_take) then
local pos = minetest.get_pointed_thing_position(pointed_thing, false)
drill_dig_it(pos, user, mode)
end
return itemstack
end
-- register Mining Drill Mk1
technic.register_power_tool("technic:mining_drill", {
description = get_description(1, 0),
inventory_image = "technic_mining_drill.png",
max_charge = max_charge[1],
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 charge_to_take = cost_to_use(1, 1)
if technic.use_charge(itemstack, charge_to_take) then
local pos = minetest.get_pointed_thing_position(pointed_thing, false)
drill_dig_it(pos, user, 1)
end
return itemstack
end,
})
do -- register Mining Drill Mk2
local inventory_image = "technic_mining_drill_mk2.png"
for i = 0, 4 do
local overlay = i > 0 and "^technic_tool_mode"..i..".png" or ""
technic.register_power_tool("technic:mining_drill_mk2"..(i > 0 and ("_"..i) or ""), {
description = get_description(2, i),
inventory_image = inventory_image .. overlay,
wield_image = inventory_image,
max_charge = max_charge[2],
groups = i > 0 and {not_in_creative_inventory=1} or nil,
on_use = mining_drill_mk2_handler,
})
end
end
do -- register Mining Drill Mk3
local inventory_image = "technic_mining_drill_mk3.png"
for i = 0, 5 do
local overlay = i > 0 and "^technic_tool_mode"..i..".png" or ""
technic.register_power_tool("technic:mining_drill_mk3"..(i > 0 and ("_"..i) or ""), {
description = get_description(3, i),
inventory_image = inventory_image .. overlay,
wield_image = inventory_image,
max_charge = max_charge[3],
groups = i > 0 and {not_in_creative_inventory=1} or nil,
on_use = mining_drill_mk3_handler,
})
end
end

View file

@ -0,0 +1,120 @@
local mat = technic.materials
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 allow_entire_discharging = true
local S = technic.getter
minetest.register_craft({
output = "technic:laser_mk1",
recipe = {
{mat.diamond, "basic_materials:brass_ingot", mat.obsidian_glass},
{"", "basic_materials:brass_ingot", "technic:red_energy_crystal"},
{"", "", mat.copper_ingot},
}
})
minetest.register_craft({
output = "technic:laser_mk2",
recipe = {
{mat.diamond, "technic:carbon_steel_ingot", "technic:laser_mk1"},
{"", "technic:carbon_steel_ingot", "technic:green_energy_crystal"},
{"", "", mat.copper_ingot},
}
})
minetest.register_craft({
output = "technic:laser_mk3",
recipe = {
{mat.diamond, "technic:carbon_steel_ingot", "technic:laser_mk2"},
{"", "technic:carbon_steel_ingot", "technic:blue_energy_crystal"},
{"", "", mat.copper_ingot},
}
})
local function laser_node(pos, node, player)
local def = minetest.registered_nodes[node.name]
if def.liquidtype ~= "none" and def.buildable_to then
minetest.remove_node(pos)
minetest.add_particle({
pos = pos,
velocity = {x = 0, y = 1.5 + math.random(), z = 0},
acceleration = {x = 0, y = -1, z = 0},
size = 6 + math.random() * 2,
texture = "smoke_puff.png^[transform" .. math.random(0, 7),
})
return
end
def.on_dig(pos, node, player)
end
local keep_node = {air = true}
local function can_keep_node(name)
if keep_node[name] ~= nil then
return keep_node[name]
end
keep_node[name] = minetest.get_item_group(name, "hot") ~= 0
return keep_node[name]
end
local function laser_shoot(player, range, particle_texture, sound)
local player_pos = player:get_pos()
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 + (player:get_properties().eye_height or 1.625)
minetest.add_particle({
pos = start_pos,
velocity = dir,
acceleration = vector.multiply(dir, 50),
expirationtime = (math.sqrt(1 + 100 * (range + 0.4)) - 1) / 50,
size = 1,
texture = particle_texture .. "^[transform" .. math.random(0, 7),
})
minetest.sound_play(sound, {pos = player_pos, max_hear_distance = range}, true)
for pos in technic.trace_node_ray_fat(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(pos)
if node.name == "ignore"
or not minetest.registered_nodes[node.name] then
break
end
if not can_keep_node(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], {
description = S("Mining Laser Mk@1", m[1]),
inventory_image = "technic_mining_laser_mk"..m[1]..".png",
range = 0,
max_charge = m[3],
on_use = function(itemstack, user)
local charge = technic.get_charge(itemstack)
if charge > 0 then
local range = m[2]
if charge < m[4] then
if not allow_entire_discharging then
return
end
-- If charge is too low, give the laser a shorter range
range = range * charge / m[4]
end
technic.use_charge(itemstack, math.min(m[4], charge))
laser_shoot(user, range, "technic_laser_beam_mk" .. m[1] .. ".png", "technic_laser_mk" .. m[1])
return itemstack
end
end,
})
end

View file

@ -0,0 +1,308 @@
local S = technic.getter
local remote_start_ttl = technic.config:get_int("multimeter_remote_start_ttl")
local max_charge = 50000
local power_usage = 100 -- Normal network reading uses this much energy
local rs_charge_multiplier = 100 -- Remote start energy requirement multiplier
local texture = "technic_multimeter.png"
local texture_logo = "technic_multimeter_logo.png"
local texture_bg9 = "technic_multimeter_bg.png"
local texture_button = "technic_multimeter_button.png"
local texture_button_pressed = "technic_multimeter_button_pressed.png"
local bgcolor = "#FFC00F"
local bgcolor_lcd = "#4B8E66"
local bghiglight_lcd = "#5CAA77"
local textcolor = "#101010"
--local bgcolor_button = "#626E41"
local form_width = 8
local form_height = 11.5
local btn_count = 3
local btn_spacing = 0.1
local btn_width = (form_width - ((btn_count + 1) * btn_spacing)) / btn_count
local open_formspecs = {}
local formspec_escape = minetest.formspec_escape
local function fmtf(n) return type(n) == "number" and ("%0.3f"):format(n) or n end
local function fs_x_pos(i) return (btn_spacing * i) + (btn_width * (i - 1)) end
local function create_button(index, y, h, name, label, exit, modifier)
local x = fs_x_pos(index)
local t1 = texture_button .. (modifier and formspec_escape(modifier) or "")
local t2 = texture_button_pressed .. (modifier and formspec_escape(modifier) or "")
local dimensions = ("%s,%s;%s,%s"):format(fmtf(x),fmtf(y),fmtf(btn_width),h)
local properties = ("%s;%s;%s;false;false;%s"):format(t1, name, label, t2)
return ("image_button%s[%s;%s]"):format(exit and "_exit" or "", dimensions, properties)
end
local formspec_format_string = "formspec_version[3]" ..
("size[%s,%s;]bgcolor[%s;both;]"):format(fmtf(form_width), fmtf(form_height), bgcolor) ..
("style_type[*;textcolor=%s;font_size=*1]"):format(textcolor) ..
("style_type[table;textcolor=%s;font_size=*1;font=mono]"):format(textcolor) ..
("style_type[label;textcolor=%s;font_size=*2]"):format(textcolor) ..
("background9[0,0;%s,%s;%s;false;3]"):format(fmtf(form_width), fmtf(form_height), texture_bg9) ..
("image[0.3,0.3;5.75,1;%s]"):format(texture_logo) ..
"label[0.6,1.5;Network %s]" ..
("field[%s,2.5;%s,0.8;net;Network ID:;%%s]"):format(fmtf(fs_x_pos(2)),fmtf(btn_width)) ..
create_button(3, "2.5", "0.8", "rs", "Remote start", false, "^[colorize:#10E010:125") ..
create_button(1, form_height - 0.9, "0.8", "wp", "Waypoint", true) ..
create_button(2, form_height - 0.9, "0.8", "up", "Update", false) ..
create_button(3, form_height - 0.9, "0.8", "exit", "Exit", true) ..
("tableoptions[border=false;background=%s;highlight=%s;color=%s]"):format(bgcolor_lcd,bghiglight_lcd,textcolor) ..
"tablecolumns[indent,width=0.2;text,width=13;text,width=13;text,align=center]" ..
("table[0.1,3.4;%s,%s;items;1,Property,Value,Unit%%s]"):format(fmtf(form_width - 0.2), fmtf(form_height - 4.4))
minetest.register_craft({
output = 'technic:multimeter',
recipe = {
{'basic_materials:copper_strip', 'technic:rubber', 'basic_materials:copper_strip'},
{'basic_materials:plastic_sheet', 'basic_materials:ic', 'basic_materials:plastic_sheet'},
{'technic:battery', 'basic_materials:ic', 'technic:copper_coil'},
}
})
local function use_charge(itemstack, multiplier)
return technic.use_charge(itemstack, power_usage * (multiplier or 1))
end
local function async_itemstack_get(player, refstack)
local inv = player:get_inventory()
local invindex, invstack
if inv and refstack then
local invsize = inv:get_size('main')
local name = refstack:get_name()
local count = refstack:get_count()
local meta = refstack:get_meta()
for i=1,invsize do
local stack = inv:get_stack('main', i)
if stack:get_count() == count and stack:get_name() == name and stack:get_meta():equals(meta) then
-- This item stack seems very similar to one that were used originally, use this
invindex = i
invstack = stack
break
end
end
end
return inv, invindex, invstack
end
--[[ Base58
local alpha = {
"1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H",
"J","K","L","M","N","P","Q","R","S","T","U","V","W","X","Y","Z",
"a","b","c","d","e","f","g","h","i","j","k","m","n","o",
"p","q","r","s","t","u","v","w","x","y","z"
} --]]
-- Base36
local alpha = {
"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H",
"I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"
}
local function base36(num)
if type(num) ~= "number" then return end
if num < 36 then return alpha[num + 1] end
local result = ""
while num ~= 0 do
result = alpha[(num % 36) + 1] .. result
num = math.floor(num / 36)
end
return result
end
-- Clean version of minetest.pos_to_string
local function v2s(v) return ("%s,%s,%s"):format(v.x,v.y,v.z) end
-- Size of hash table
local function count(t)
if type(t) ~= "table" then return 0 end
local c=0 for _ in pairs(t) do c=c+1 end return c
end
-- Percentage value as string
local function percent(val, max)
if type(val) ~= "number" or type(max) ~= "number" then return "" end
local p = (val / max) * 100
return p > 99.99 and "100" or ("%0.2f"):format(p)
end
-- Get network TTL
local function net_ttl(net) return type(net.timeout) == "number" and (net.timeout - minetest.get_us_time()) end
-- Microseconds to milliseconds
local function us2ms(val) return type(val) == "number" and (val / 1000) or 0 end
-- Microseconds to seconds
local function us2s(val) return type(val) == "number" and (val / 1000 / 1000) or 0 end
local function formspec(data)
local tablerows = ""
for _,row in ipairs(data.rows) do
tablerows = tablerows .. ",1" ..
"," .. formspec_escape(row[1] or "-") ..
"," .. formspec_escape(row[2] or "-") ..
"," .. formspec_escape(row[3] or "-")
end
local base36_net = base36(data.network_id) or "N/A"
return formspec_format_string:format(base36_net, base36_net, tablerows)
end
local function multimeter_inspect(itemstack, player, pos, fault)
local id = pos and technic.pos2network(pos)
local rows = {}
local data = { network_id = id, rows = rows }
local name = player:get_player_name()
if id and itemstack and not fault then
table.insert(rows, { "Ref. point", v2s(technic.network2pos(id)), "coord" })
table.insert(rows, { "Activated", technic.active_networks[id] and "yes" or "no", "active" })
local net = technic.networks[id]
if net then
table.insert(rows, { "Timeout", ("%0.1f"):format(us2s(net_ttl(net))), "s" })
table.insert(rows, { "Lag", ("%0.2f"):format(us2ms(net.lag)), "ms" })
table.insert(rows, { "Skip", net.skip, "cycles" })
table.insert(rows, {})
local PR = net.PR_nodes
local RE = net.RE_nodes
local BA = net.BA_nodes
local C = count(net.all_nodes)
table.insert(rows, { "Supply", net.supply, "EU" })
table.insert(rows, { "Demand", net.demand, "EU" })
table.insert(rows, { "Battery charge", net.battery_charge, "EU" })
table.insert(rows, { "Battery charge", percent(net.battery_charge, net.battery_charge_max), "%" })
table.insert(rows, { "Battery capacity", net.battery_charge_max, "EU" })
table.insert(rows, {})
table.insert(rows, { "Nodes", C, "count" })
table.insert(rows, { "Cables", C - #PR - #RE - #BA, "count" }) -- FIXME: Do not count PR+RE duplicates
table.insert(rows, { "Generators", #PR, "count" })
table.insert(rows, { "Consumers", #RE, "count" })
table.insert(rows, { "Batteries", #BA, "count" })
end
else
table.insert(rows, { "Operation failed", "", "" })
if not id then
table.insert(rows, {})
table.insert(rows, { "Bad contact", "No network", "Fault" })
end
if fault then table.insert(rows, {}) end
if fault == "battery" then
table.insert(rows, { "Recharge", "Insufficient charge", "Fault" })
elseif fault == "decode" then
table.insert(rows, { "Decoder error", "Net ID decode", "Fault" })
elseif fault == "switchload" then
table.insert(rows, { "Remote load error", "Load switching station", "Fault" })
elseif fault == "cableload" then
table.insert(rows, { "Remote load error", "Load ref. cable", "Fault" })
elseif fault == "protected" then
table.insert(rows, { "Protection error", "Area is protected", "Access" })
end
if not itemstack then
table.insert(rows, {})
table.insert(rows, { "Missing FLUTE", "FLUTE not found", "Fault" })
end
end
open_formspecs[name] = { pos = pos, itemstack = itemstack }
minetest.show_formspec(name, "technic:multimeter", formspec(data))
end
local function remote_start_net(player, pos)
local sw_pos = {x=pos.x,y=pos.y+1,z=pos.z}
-- Try to load switch network node
local sw_node = technic.get_or_load_node(sw_pos)
if sw_node.name ~= "technic:switching_station" then return "switchload" end
-- Try to load network node
local tier = technic.sw_pos2tier(sw_pos, true)
if not tier then return "cableload" end
-- Check protections
if minetest.is_protected(pos, player:get_player_name()) then return "protected" end
-- All checks passed, start network
local network_id = technic.sw_pos2network(sw_pos) or technic.create_network(sw_pos)
technic.activate_network(network_id, remote_start_ttl)
end
local function async_itemstack_use_charge(itemstack, player, multiplier)
local fault = nil
local inv, invindex, invstack = async_itemstack_get(player, itemstack)
if not inv or not invindex or not use_charge(invstack, multiplier) then
-- Multimeter battery empty
fault = "battery"
elseif invstack then
inv:set_stack('main', invindex, invstack)
end
return invstack, fault
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "technic:multimeter" then
-- Not our formspec, tell engine to continue with other registered handlers
return
end
local name = player:get_player_name()
local flute = open_formspecs[name]
if fields and name then
local pos = flute and flute.pos
if fields.up then
local itemstack = flute and flute.itemstack
local invstack, fault = async_itemstack_use_charge(itemstack, player)
multimeter_inspect(invstack, player, pos, fault)
return true
elseif fields.wp and pos then
local network_id = technic.pos2network(pos)
local encoded_net_id = base36(network_id)
if encoded_net_id then
local net_pos = technic.network2pos(network_id)
local id = player:hud_add({
hud_elem_type = "waypoint",
name = ("Network %s"):format(encoded_net_id),
text = "m",
number = 0xE0B020,
world_pos = net_pos
})
minetest.after(90, function() if player then player:hud_remove(id) end end)
end
elseif fields.rs and fields.net and fields.net ~= "" then
-- Use charge first before even attempting remote start
local itemstack = flute and flute.itemstack
local invstack, fault = async_itemstack_use_charge(itemstack, player, rs_charge_multiplier)
if not fault then
local net_id = tonumber(fields.net, 36)
local net_pos = net_id and technic.network2pos(net_id)
if net_pos then
fault = remote_start_net(player, net_pos)
else
fault = "decode"
end
end
multimeter_inspect(invstack, player, pos, fault)
return true
elseif fields.quit then
open_formspecs[name] = nil
end
end
-- Tell engine to skip rest of formspec handlers
return true
end)
local function check_node(pos)
local name = minetest.get_node(pos).name
if technic.machine_tiers[name] or technic.get_cable_tier(name) or name == "technic:switching_station" then
return name
end
end
technic.register_power_tool("technic:multimeter", {
description = S("Multimeter"),
inventory_image = texture,
wield_image = texture,
liquids_pointable = false,
max_charge = max_charge,
on_use = function(itemstack, player, pointed_thing)
local pos = minetest.get_pointed_thing_position(pointed_thing, false)
if pos and pointed_thing.type == "node" then
local name = check_node(pos)
if name then
if name == "technic:switching_station" then
-- Switching station compatibility shim
pos.y = pos.y - 1
end
open_formspecs[player:get_player_name()] = nil
multimeter_inspect(itemstack, player, pos, not use_charge(itemstack) and "battery")
end
end
return itemstack
end,
})

View file

@ -0,0 +1,147 @@
local S = technic.getter
local mat = technic.materials
local function migrate_meta(meta)
local data = meta:get("")
if data then
local fields = minetest.deserialize(data, true)
if type(fields) == "table" then
meta:set_string("target", fields.target)
meta:set_int("look_radius", fields.look_radius or 1)
meta:set_int("look_depth", fields.look_depth or 7)
meta:set_string("", "")
return meta:get("target")
end
end
end
local function get_field(meta)
return (meta:get("look_depth") or 7), (meta:get("look_radius") or 1)
end
technic.register_power_tool("technic:prospector", {
description = S("Prospector"),
inventory_image = "technic_prospector.png",
max_charge = 300000,
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 meta = toolstack:get_meta()
local target = meta:get("target") or migrate_meta(meta)
if not target then
minetest.chat_send_player(user:get_player_name(), S("Right-click to set target block type"))
return toolstack
end
local look_depth, look_radius = get_field(meta)
local look_diameter = look_radius * 2 + 1
local charge_to_take = look_depth * (look_depth + 1) * look_diameter * look_diameter
if not technic.use_charge(toolstack, charge_to_take) then
return toolstack
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), - look_radius))
local found = false
for f = 0, 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 == 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(),
S("@1 is "..(found and "present" or "absent").." in @2 region",
minetest.registered_nodes[target].description,
look_diameter.."x"..look_diameter.."x"..look_depth))
minetest.sound_play("technic_prospector_"..(found and "hit" or "miss"),
{ pos = vector.add(user:get_pos(), { x = 0, y = 1, z = 0 }), gain = 1.0, max_hear_distance = 10 }, true)
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 meta = toolstack:get_meta()
local target = meta:get("target") or migrate_meta(meta)
local look_depth, look_radius = get_field(meta)
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 ~= target then
pointed = pname
end
end
local look_diameter = 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_description()).."]"..
(target and
"label[0,1.5;"..S("Current target:").."]"..
"label[0,2;"..minetest.formspec_escape(minetest.registered_nodes[target].description).."]"..
"item_image[0,2.5;1,1;"..target.."]" or
"label[0,1.5;"..S("No target set").."]")..
(pointed and
"label[3.5,1.5;"..S("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..";"..S("Set target").."]" or
"label[3.5,1.5;"..S("No new target available").."]")..
"label[0,4.5;"..S("Region cross section:").."]"..
"label[0,5;"..look_diameter.."x"..look_diameter.."]"..
"label[3.5,4.5;"..S("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;"..S("Region depth:").."]"..
"label[0,6.5;"..look_depth.."]"..
"label[3.5,6;"..S("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;"..S("Accuracy:").."]"..
"label[0,8;98%]")
return toolstack
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 meta = toolstack:get_meta()
for field, value in pairs(fields) do
if field:sub(1, 7) == "target_" then
meta:set_string("target", field:sub(8))
elseif field:sub(1, 12) == "look_radius_" then
meta:set_int("look_radius", field:sub(13))
elseif field:sub(1, 11) == "look_depth_" then
meta:set_int("look_depth", field:sub(12))
end
end
user:set_wielded_item(toolstack)
return true
end)
minetest.register_craft({
output = "technic:prospector",
recipe = {
{mat.pick_silver, mat.mithril_block, "pipeworks:teleport_tube_1"},
{"basic_materials:brass_ingot", "technic:control_logic_unit", "basic_materials:brass_ingot"},
{"", "technic:blue_energy_crystal", ""},
}
})

View file

@ -0,0 +1,86 @@
local sonic_screwdriver_max_charge = 15000
local S = technic.getter
local mat = technic.materials
-- 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 ndef.paramtype2 ~= "facedir" or
(ndef.drawtype == "nodebox" and
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
if not technic.use_charge(itemstack, 100) then
return
end
minetest.sound_play("technic_sonic_screwdriver", {pos = pos, gain = 0.5, max_hear_distance = 10}, true)
-- 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)
return itemstack
end
technic.register_power_tool("technic:sonic_screwdriver", {
description = S("Sonic Screwdriver (left-click rotates face, right-click rotates axis)"),
inventory_image = "technic_sonic_screwdriver.png",
max_charge = sonic_screwdriver_max_charge,
on_use = function(itemstack, user, pointed_thing)
return screwdriver_handler(itemstack, user, pointed_thing, ROTATE_FACE)
end,
on_place = function(itemstack, user, pointed_thing)
return screwdriver_handler(itemstack, user, pointed_thing, ROTATE_AXIS)
end,
})
minetest.register_craft({
output = "technic:sonic_screwdriver",
recipe = {
{"", mat.diamond, ""},
{"mesecons_materials:fiber", "technic:battery", "mesecons_materials:fiber"},
{"mesecons_materials:fiber", mat.mithril_ingot, "mesecons_materials:fiber"}
}
})

View file

@ -0,0 +1,87 @@
local S = technic.getter
local mat = technic.materials
local mesecons_materials = minetest.get_modpath("mesecons_materials")
local function drop_raw_latex(pointed_thing, user)
if minetest.get_modpath("mcl_core") then
minetest.add_item(user:get_pos(), "technic:raw_latex")
else
minetest.handle_node_drops(pointed_thing.above, {"technic:raw_latex"}, user)
end
end
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)
drop_raw_latex(pointed_thing, 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", mat.stick},
{"", mat.stick, mat.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({
label = "Tools: tree tap",
nodenames = {"moretrees:rubber_tree_trunk_empty"},
interval = 60,
chance = 15,
action = function(pos, node)
local radius = (moretrees and moretrees.leafdecay_radius) or 5
local nodes = minetest.find_node_near(pos, radius, {"moretrees:rubber_tree_leaves"})
if nodes then
node.name = "moretrees:rubber_tree_trunk"
minetest.swap_node(pos, node)
end
end
})

View file

@ -0,0 +1,50 @@
-- 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", {
description = S("Vacuum Cleaner"),
inventory_image = "technic_vacuum.png",
max_charge = vacuum_max_charge,
on_use = function(itemstack, user, pointed_thing)
local original_charge = technic.get_charge(itemstack)
if original_charge < vacuum_charge_per_object then
return
end
minetest.sound_play("vacuumcleaner", {to_player = user:get_player_name(), gain = 0.4}, true)
local pos = user:get_pos()
local inv = user:get_inventory()
local charge = original_charge
for _, object in ipairs(minetest.get_objects_inside_radius(pos, vacuum_range)) do
local entity = object:get_luaentity()
if not object:is_player() and entity and entity.name == "__builtin:item" and entity.itemstring ~= "" then
if inv and inv:room_for_item("main", ItemStack(entity.itemstring)) then
charge = charge - vacuum_charge_per_object
inv:add_item("main", ItemStack(entity.itemstring))
minetest.sound_play("item_drop_pickup", {to_player = user:get_player_name(), gain = 0.4}, true)
entity.itemstring = ""
object:remove()
if charge < vacuum_charge_per_object then
break
end
end
end
end
if not technic.creative_mode and charge ~= original_charge then
technic.set_charge(itemstack, charge)
return itemstack
end
end,
})
minetest.register_craft({
output = 'technic:vacuum',
recipe = {
{'pipeworks:tube_1', 'pipeworks:filter', 'technic:battery'},
{'pipeworks:tube_1', 'basic_materials:motor', 'technic:battery'},
{'technic:stainless_steel_ingot', '', ''},
}
})