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,21 @@
-- HV battery box
minetest.register_craft({
output = 'technic:hv_battery_box0',
recipe = {
{'technic:mv_battery_box0', 'technic:mv_battery_box0', 'technic:mv_battery_box0'},
{'technic:mv_battery_box0', 'technic:hv_transformer', 'technic:mv_battery_box0'},
{'', 'technic:hv_cable', ''},
}
})
technic.register_battery_box("technic:hv_battery_box", {
tier = "HV",
max_charge = 1000000,
charge_rate = 100000,
discharge_rate = 400000,
charge_step = 10000,
discharge_step = 40000,
upgrade = 1,
tube = 1,
})

View file

@ -0,0 +1,54 @@
local S = technic.getter
minetest.register_craft({
output = 'technic:hv_cable 3',
recipe = {
{'homedecor:plastic_sheeting', 'homedecor:plastic_sheeting', 'homedecor:plastic_sheeting'},
{'technic:mv_cable', 'technic:mv_cable', 'technic:mv_cable'},
{'homedecor:plastic_sheeting', 'homedecor:plastic_sheeting', 'homedecor:plastic_sheeting'},
}
})
minetest.register_craft({
output = "technic:hv_cable_plate_1 5",
recipe = {
{"" , "" , "technic:hv_cable"},
{"technic:hv_cable", "technic:hv_cable", "technic:hv_cable"},
{"" , "" , "technic:hv_cable"},
}
})
minetest.register_craft({
output = "technic:hv_cable",
recipe = {{"technic:hv_cable_plate_1"}}
})
-- Register cables
technic.register_cable("technic:hv_cable", {
tier = "HV",
size = 3/16,
description = S("@1 Cable", S("HV"))
})
technic.register_cable_plate("technic:hv_cable_plate", {
tier = "HV",
size = 3/16,
description = S("@1 Cable Plate", S("HV")),
tiles = {"technic_hv_cable.png"},
})
if minetest.get_modpath("digilines") then
technic.register_cable("technic:hv_digi_cable", {
tier = "HV",
size = 3/16,
description = S("@1 Digiline Cable", S("HV")),
digiline = { wire = { rules = technic.digilines.rules_allfaces } }
})
technic.register_cable_plate("technic:hv_digi_cable_plate", {
tier = "HV",
size = 3/16,
description = S("@1 Digiline Cable Plate", S("HV")),
digiline = { wire = { rules = technic.digilines.rules_allfaces } },
tiles = {"technic_hv_digi_cable.png"}
})
end

View file

@ -0,0 +1,21 @@
-- HV compressor
local S = technic.getter
minetest.register_craft({
output = 'technic:hv_compressor',
recipe = {
{'technic:carbon_plate', 'technic:mv_compressor', 'technic:composite_plate'},
{'pipeworks:tube_1', 'technic:hv_transformer', 'pipeworks:tube_1'},
{'technic:stainless_steel_ingot', 'technic:hv_cable', 'technic:stainless_steel_ingot'},
}
})
technic.register_base_machine("technic:hv_compressor", {
typename = "compressing",
description = S("@1 Compressor", S("HV")),
tier = "HV",
demand = {1500, 1000, 750},
speed = 5,
upgrade = 1,
tube = 1
})

View file

@ -0,0 +1,26 @@
-- MV Electric Furnace
-- This is a faster version of the stone furnace which runs on EUs
-- In addition to this it can be upgraded with microcontrollers and batteries
-- This new version uses the batteries to lower the power consumption of the machine
-- Also in addition this furnace can be attached to the pipe system from the pipeworks mod.
local S = technic.getter
-- FIXME: kpoppel I'd like to introduce an induction heating element here also
minetest.register_craft({
output = 'technic:hv_electric_furnace',
recipe = {
{'technic:stainless_steel_ingot', 'technic:mv_electric_furnace', 'technic:stainless_steel_ingot'},
{'pipeworks:tube_1', 'technic:hv_transformer', 'pipeworks:tube_1'},
{'technic:stainless_steel_ingot', 'technic:hv_cable', 'technic:stainless_steel_ingot'},
}
})
technic.register_base_machine("technic:hv_electric_furnace", {
typename = "cooking",
description = S("@1 Furnace", S("HV")),
tier="HV",
upgrade=1,
tube=1,
demand={4000, 2500, 1500},
speed=12
})

View file

@ -0,0 +1,400 @@
--- Forcefield generator.
-- @author ShadowNinja
--
-- Forcefields are powerful barriers but they consume huge amounts of power.
-- The forcefield Generator is an HV machine.
-- How expensive is the generator?
-- Leaves room for upgrades lowering the power drain?
local digilines_path = minetest.get_modpath("digilines")
local forcefield_power_drain = 10
local S = technic.getter
local cable_entry = "^technic_cable_connection_overlay.png"
local mat = technic.materials
minetest.register_craft({
output = "technic:forcefield_emitter_off",
recipe = {
{mat.mese, "basic_materials:motor", mat.mese },
{"technic:deployer_off", "technic:machine_casing", "technic:deployer_off"},
{mat.mese, "technic:hv_cable", mat.mese },
}
})
local replaceable_cids = {}
minetest.after(0, function()
for name, ndef in pairs(minetest.registered_nodes) do
if ndef.buildable_to == true and name ~= "ignore" then
replaceable_cids[minetest.get_content_id(name)] = true
end
end
end)
-- Idea: Let forcefields have different colors by upgrade slot.
-- Idea: Let forcefields add up by detecting if one hits another.
-- ___ __
-- / \/ \
-- | |
-- \___/\___/
local function update_forcefield(pos, meta, active)
if active then
-- rate limit by chance
if math.floor(math.random()*4) ~= 0 then
return
end
end
local shape = meta:get_int("shape")
local range = meta:get_int("range")
local vm = VoxelManip()
local MinEdge, MaxEdge = vm:read_from_map(vector.subtract(pos, range),
vector.add(pos, range))
local area = VoxelArea:new({MinEdge = MinEdge, MaxEdge = MaxEdge})
local data = vm:get_data()
local c_air = minetest.get_content_id("air")
local c_field = minetest.get_content_id("technic:forcefield")
for z = -range, range do
for y = -range, range do
local vi = area:index(pos.x + (-range), pos.y + y, pos.z + z)
for x = -range, range do
local relevant
if shape == 0 then
local squared = x * x + y * y + z * z
relevant =
squared <= range * range + range and
squared >= (range - 1) * (range - 1) + (range - 1)
else
relevant =
x == -range or x == range or
y == -range or y == range or
z == -range or z == range
end
if relevant then
local cid = data[vi]
if active and replaceable_cids[cid] then
data[vi] = c_field
elseif not active and cid == c_field then
data[vi] = c_air
end
end
vi = vi + 1
end
end
end
vm:set_data(data)
vm:update_liquids()
vm:write_to_map()
end
local function set_forcefield_formspec(meta)
local formspec
if digilines_path then
formspec = "size[5,3.25]"..
"field[0.3,3;5,1;channel;"..S("Digiline Channel")..";${channel}]"
else
formspec = "size[5,2.25]"
end
formspec = formspec..
"field[0.3,0.5;2,1;range;"..S("Range")..";${range}]"
-- The names for these toggle buttons are explicit about which
-- state they'll switch to, so that multiple presses (arising
-- from the ambiguity between lag and a missed press) only make
-- the single change that the user expects.
if meta:get_int("shape") == 0 then
formspec = formspec.."button[3,0.2;2,1;shape1;"..S("Sphere").."]"
else
formspec = formspec.."button[3,0.2;2,1;shape0;"..S("Cube").."]"
end
if meta:get_int("mesecon_mode") == 0 then
formspec = formspec.."button[0,1;5,1;mesecon_mode_1;"..S("Ignoring Mesecon Signal").."]"
else
formspec = formspec.."button[0,1;5,1;mesecon_mode_0;"..S("Controlled by Mesecon Signal").."]"
end
if meta:get_int("enabled") == 0 then
formspec = formspec..
"button[0,1.75;5,1;enable;"..S("@1 Disabled", S("@1 Forcefield Emitter", S("HV"))).."]"
else
formspec = formspec..
"button[0,1.75;5,1;disable;"..S("@1 Enabled", S("@1 Forcefield Emitter", S("HV"))).."]"
end
meta:set_string("formspec", formspec)
end
local forcefield_receive_fields = function(pos, formname, fields, sender)
local player_name = sender:get_player_name()
if minetest.is_protected(pos, player_name) then
minetest.chat_send_player(player_name, S("You are not allowed to edit this!"))
minetest.record_protection_violation(pos, player_name)
return
end
local meta = minetest.get_meta(pos)
local range = nil
if fields.range then
range = tonumber(fields.range) or 0
-- Smallest field is 5. Anything less is asking for trouble.
-- Largest is 20. It is a matter of pratical node handling.
-- At the maximim range updating the forcefield takes about 0.2s
range = math.max(range, 5)
range = math.min(range, 20)
if range == meta:get_int("range") then range = nil end
end
if fields.shape0 or fields.shape1 or range then
update_forcefield(pos, meta, false)
end
if range then meta:set_int("range", range) end
if fields.channel then meta:set_string("channel", fields.channel) end
if fields.shape0 then meta:set_int("shape", 0) end
if fields.shape1 then meta:set_int("shape", 1) end
if fields.enable then meta:set_int("enabled", 1) end
if fields.disable then meta:set_int("enabled", 0) end
if fields.mesecon_mode_0 then meta:set_int("mesecon_mode", 0) end
if fields.mesecon_mode_1 then meta:set_int("mesecon_mode", 1) end
set_forcefield_formspec(meta)
end
local mesecons = {
effector = {
action_on = function(pos, node)
minetest.get_meta(pos):set_int("mesecon_effect", 1)
end,
action_off = function(pos, node)
minetest.get_meta(pos):set_int("mesecon_effect", 0)
end
}
}
local digiline_def = {
receptor = {
rules = technic.digilines.rules,
action = function() end
},
effector = {
rules = technic.digilines.rules,
action = function(pos, node, channel, msg)
local meta = minetest.get_meta(pos)
if channel ~= meta:get_string("channel") then
return
end
local msgt = type(msg)
if msgt == "string" then
local smsg = msg:lower()
msg = {}
if smsg == "get" then
msg.command = "get"
elseif smsg == "off" then
msg.command = "off"
elseif smsg == "on" then
msg.command = "on"
elseif smsg == "toggle" then
msg.command = "toggle"
elseif smsg:sub(1, 5) == "range" then
msg.command = "range"
msg.value = tonumber(smsg:sub(7))
elseif smsg:sub(1, 5) == "shape" then
msg.command = "shape"
msg.value = smsg:sub(7):lower()
msg.value = tonumber(msg.value) or msg.value
end
elseif msgt ~= "table" then
return
end
if msg.command == "get" then
digilines.receptor_send(pos, technic.digilines.rules, channel, {
enabled = meta:get_int("enabled"),
range = meta:get_int("range"),
shape = meta:get_int("shape")
})
return
elseif msg.command == "off" then
meta:set_int("enabled", 0)
elseif msg.command == "on" then
meta:set_int("enabled", 1)
elseif msg.command == "toggle" then
local onn = meta:get_int("enabled")
onn = 1-onn -- Mirror onn with pivot 0.5, so switch between 1 and 0.
meta:set_int("enabled", onn)
elseif msg.command == "range" then
if type(msg.value) ~= "number" then
return
end
msg.value = math.max(msg.value, 5)
msg.value = math.min(msg.value, 20)
update_forcefield(pos, meta, false)
meta:set_int("range", msg.value)
elseif msg.command == "shape" then
local valuet = type(msg.value)
if valuet == "string" then
if msg.value == "sphere" then
msg.value = 0
elseif msg.value == "cube" then
msg.value = 1
end
elseif valuet ~= "number" then
return
end
if not msg.value then
return
end
update_forcefield(pos, meta, false)
meta:set_int("shape", msg.value)
else
return
end
set_forcefield_formspec(meta)
end
},
}
local function run(pos, node)
local meta = minetest.get_meta(pos)
local eu_input = meta:get_int("HV_EU_input")
local enabled = meta:get_int("enabled") ~= 0 and
(meta:get_int("mesecon_mode") == 0 or meta:get_int("mesecon_effect") ~= 0)
local machine_name = S("@1 Forcefield Emitter", S("HV"))
local range = meta:get_int("range")
local power_requirement
if meta:get_int("shape") == 0 then
power_requirement = math.floor(4 * math.pi * range * range)
else
power_requirement = 24 * range * range
end
power_requirement = power_requirement * forcefield_power_drain
if not enabled then
if node.name == "technic:forcefield_emitter_on" then
update_forcefield(pos, meta, false)
technic.swap_node(pos, "technic:forcefield_emitter_off")
meta:set_string("infotext", S("@1 Disabled", machine_name))
end
meta:set_int("HV_EU_demand", 0)
return
end
meta:set_int("HV_EU_demand", power_requirement)
if eu_input < power_requirement then
meta:set_string("infotext", S("@1 Unpowered", machine_name))
if node.name == "technic:forcefield_emitter_on" then
update_forcefield(pos, meta, false)
technic.swap_node(pos, "technic:forcefield_emitter_off")
end
elseif eu_input >= power_requirement then
if node.name == "technic:forcefield_emitter_off" then
technic.swap_node(pos, "technic:forcefield_emitter_on")
meta:set_string("infotext", S("@1 Active", machine_name) .. "\n" ..
S("Demand: @1", technic.EU_string(power_requirement)))
end
update_forcefield(pos, meta, true)
end
end
minetest.register_node("technic:forcefield_emitter_off", {
description = S("@1 Forcefield Emitter", S("HV")),
tiles = {
"technic_forcefield_emitter_off.png",
"technic_machine_bottom.png"..cable_entry,
"technic_forcefield_emitter_off.png",
"technic_forcefield_emitter_off.png",
"technic_forcefield_emitter_off.png",
"technic_forcefield_emitter_off.png"
},
groups = {cracky = 1, technic_machine = 1, technic_hv = 1, pickaxey = 3},
is_ground_content = false,
_mcl_blast_resistance = 1,
_mcl_hardness = 0.8,
on_receive_fields = forcefield_receive_fields,
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_int("HV_EU_input", 0)
meta:set_int("HV_EU_demand", 0)
meta:set_int("range", 10)
meta:set_int("enabled", 0)
meta:set_int("mesecon_mode", 0)
meta:set_int("mesecon_effect", 0)
if digilines_path then
meta:set_string("channel", "forcefield"..minetest.pos_to_string(pos))
end
meta:set_string("infotext", S("@1 Forcefield Emitter", S("HV")))
set_forcefield_formspec(meta)
end,
mesecons = mesecons,
digiline = digiline_def,
technic_run = run,
})
minetest.register_node("technic:forcefield_emitter_on", {
description = S("@1 Forcefield Emitter", S("HV")),
tiles = {
"technic_forcefield_emitter_on.png",
"technic_machine_bottom.png"..cable_entry,
"technic_forcefield_emitter_on.png",
"technic_forcefield_emitter_on.png",
"technic_forcefield_emitter_on.png",
"technic_forcefield_emitter_on.png"
},
groups = {cracky = 1, technic_machine = 1, technic_hv = 1,
not_in_creative_inventory=1, pickaxey = 3},
is_ground_content = false,
_mcl_blast_resistance = 1,
_mcl_hardness = 0.8,
drop = "technic:forcefield_emitter_off",
on_receive_fields = forcefield_receive_fields,
on_destruct = function(pos)
local meta = minetest.get_meta(pos)
update_forcefield(pos, meta, false)
end,
mesecons = mesecons,
digiline = digiline_def,
technic_run = run,
technic_on_disable = function (pos, node)
local meta = minetest.get_meta(pos)
update_forcefield(pos, meta, false)
technic.swap_node(pos, "technic:forcefield_emitter_off")
end,
on_blast = function(pos, intensity)
minetest.dig_node(pos)
return {"technic:forcefield_emitter_off"}
end,
})
minetest.register_node("technic:forcefield", {
description = S("@1 Forcefield", S("HV")),
sunlight_propagates = true,
drawtype = "glasslike",
groups = {not_in_creative_inventory=1},
is_ground_content = false,
paramtype = "light",
light_source = minetest.LIGHT_MAX,
diggable = false,
drop = '',
tiles = {{
name = "technic_forcefield_animated.png",
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 1.0,
},
}},
on_blast = function(pos, intensity)
end,
})
if minetest.get_modpath("mesecons_mvps") then
mesecon.register_mvps_stopper("technic:forcefield")
end
technic.register_machine("HV", "technic:forcefield_emitter_on", technic.receiver)
technic.register_machine("HV", "technic:forcefield_emitter_off", technic.receiver)

View file

@ -0,0 +1,13 @@
minetest.register_alias("hv_generator", "technic:hv_generator")
minetest.register_craft({
output = 'technic:hv_generator',
recipe = {
{'technic:carbon_plate', 'technic:mv_generator', 'technic:composite_plate'},
{'pipeworks:tube_1', 'technic:hv_transformer', 'pipeworks:tube_1'},
{'technic:stainless_steel_ingot', 'technic:hv_cable', 'technic:stainless_steel_ingot'},
}
})
technic.register_generator({tier="HV", tube=1, supply=1200})

View file

@ -0,0 +1,21 @@
-- HV grinder
local S = technic.getter
minetest.register_craft({
output = 'technic:hv_grinder',
recipe = {
{'technic:carbon_plate', 'technic:mv_grinder', 'technic:composite_plate'},
{'pipeworks:tube_1', 'technic:hv_transformer', 'pipeworks:tube_1'},
{'technic:stainless_steel_ingot', 'technic:hv_cable', 'technic:stainless_steel_ingot'},
}
})
technic.register_base_machine("technic:hv_grinder", {
typename = "grinding",
description = S("@1 Grinder", S("HV")),
tier="HV",
demand={1200, 900, 600},
speed=5,
upgrade=1,
tube=1
})

View file

@ -0,0 +1,20 @@
technic.register_tier("HV", "High Voltage")
local path = technic.modpath.."/machines/HV"
-- Wiring stuff
dofile(path.."/cables.lua")
dofile(path.."/battery_box.lua")
-- Generators
dofile(path.."/solar_array.lua")
dofile(path.."/nuclear_reactor.lua")
dofile(path.."/generator.lua")
-- Machines
dofile(path.."/quarry.lua")
dofile(path.."/forcefield.lua")
dofile(path.."/electric_furnace.lua")
dofile(path.."/grinder.lua")
dofile(path.."/compressor.lua")

View file

@ -0,0 +1,557 @@
--[[
The enriched uranium rod driven EU generator.
A very large and advanced machine providing vast amounts of power.
Very efficient but also expensive to run as it needs uranium.
Provides 100000 HV EUs for one week (only counted when loaded).
The nuclear reactor core requires a casing of water and a protective
shield to work. This is checked now and then and if the casing is not
intact the reactor will melt down!
--]]
local burn_ticks = 7 * 24 * 60 * 60 -- Seconds
local power_supply = 100000 -- EUs
local fuel_type = "technic:uranium_fuel" -- The reactor burns this
local digiline_meltdown = technic.config:get_bool("enable_nuclear_reactor_digiline_selfdestruct")
local has_digilines = minetest.get_modpath("digilines")
local has_mcl = minetest.get_modpath("mcl_core")
local mat = technic.materials
local S = technic.getter
local reactor_desc = S("@1 Nuclear Reactor Core", S("HV"))
local cable_entry = "^technic_cable_connection_overlay.png"
-- FIXME: Recipe should make more sense like a rod recepticle, steam chamber, HV generator?
minetest.register_craft({
output = 'technic:hv_nuclear_reactor_core',
recipe = {
{'technic:carbon_plate', mat.obsidian_glass, 'technic:carbon_plate'},
{'technic:composite_plate', 'technic:machine_casing', 'technic:composite_plate'},
{'technic:stainless_steel_ingot', 'technic:hv_cable', 'technic:stainless_steel_ingot'},
}
})
local size = minetest.get_modpath("mcl_formspec") and "size[9,9]" or "size[8,9]"
local function make_reactor_formspec(meta)
local f = size..
"label[0,0;"..S("Nuclear Reactor Rod Compartment").."]"..
"list[context;src;2,1;3,2;]"..
"listring[context;src]"..
"button[5.5,1.5;2,1;start;"..S("Start").."]"..
"checkbox[5.5,2.5;autostart;"..S("Automatic Start")..";"..meta:get_string("autostart").."]"
if has_mcl then
f = f..
mcl_formspec.get_itemslot_bg(2,1,3,2)..
-- player inventory
"list[current_player;main;0,4.5;9,3;9]"..
mcl_formspec.get_itemslot_bg(0,4.5,9,3)..
"list[current_player;main;0,7.74;9,1;]"..
mcl_formspec.get_itemslot_bg(0,7.74,9,1)..
"listring[current_player;main]"
else
f = f..
"list[current_player;main;0,5;8,4;]"..
"listring[current_player;main]"
end
if not has_digilines then
return f
end
local digiline_enabled = meta:get_string("enable_digiline")
f = f.."checkbox[0.5,2.8;enable_digiline;Enable Digiline;"..digiline_enabled.."]"
if digiline_enabled ~= "true" then
return f
end
return f..
"button_exit[4.6,3.69;2,1;save;"..S("Save").."]"..
"field[1,4;4,1;channel;"..S("Digiline Channel")..";${channel}]"
end
local SS_OFF = 0
local SS_DANGER = 1
local SS_CLEAR = 2
local reactor_siren = {}
local function siren_set_state(pos, state)
local hpos = minetest.hash_node_position(pos)
local siren = reactor_siren[hpos]
if not siren then
if state == SS_OFF then return end
siren = {state=SS_OFF}
reactor_siren[hpos] = siren
end
if state == SS_DANGER and siren.state ~= SS_DANGER then
if siren.handle then minetest.sound_stop(siren.handle) end
siren.handle = minetest.sound_play("technic_hv_nuclear_reactor_siren_danger_loop",
{pos=pos, gain=1.5, loop=true, max_hear_distance=48})
siren.state = SS_DANGER
elseif state == SS_CLEAR then
if siren.handle then minetest.sound_stop(siren.handle) end
local clear_handle = minetest.sound_play("technic_hv_nuclear_reactor_siren_clear",
{pos=pos, gain=1.5, loop=false, max_hear_distance=48})
siren.handle = clear_handle
siren.state = SS_CLEAR
minetest.after(10, function()
if siren.handle ~= clear_handle then return end
minetest.sound_stop(clear_handle)
if reactor_siren[hpos] == siren then
reactor_siren[hpos] = nil
end
end)
elseif state == SS_OFF and siren.state ~= SS_OFF then
if siren.handle then minetest.sound_stop(siren.handle) end
reactor_siren[hpos] = nil
end
end
local function siren_danger(pos, meta)
meta:set_int("siren", 1)
siren_set_state(pos, SS_DANGER)
end
local function siren_clear(pos, meta)
if meta:get_int("siren") ~= 0 then
siren_set_state(pos, SS_CLEAR)
meta:set_int("siren", 0)
end
end
--[[
The standard reactor structure consists of a 9x9x9 cube. A cross
section through the middle:
CCCC CCCC
CBBB BBBC
CBLL LLBC
CBLWWWLBC
CBLW#WLBC
CBLW|WLBC
CBLL|LLBC
CBBB|BBBC
CCCC|CCCC
C = Concrete, B = Blast-resistant concrete, L = Lead,
W = water node, # = reactor core, | = HV cable
The man-hole is optional (but necessary for refueling).
For the reactor to operate and not melt down, it insists on the inner
7x7x7 portion (from the core out to the blast-resistant concrete)
being intact. Intactness only depends on the number of nodes of the
right type in each layer. The water layer must have water in all but
at most one node; the steel and blast-resistant concrete layers must
have the right material in all but at most two nodes. The permitted
gaps are meant for the cable and man-hole, but can actually be anywhere
and contain anything. For the reactor to be useful, a cable must
connect to the core, but it can go in any direction.
The outer concrete layer of the standard structure is not required
for the reactor to operate. It is noted here because it used to
be mandatory, and for historical reasons (that it predates the
implementation of radiation) it needs to continue being adequate
shielding of legacy reactors. If it ever ceases to be adequate
shielding for new reactors, legacy ones should be grandfathered.
For legacy reasons, if the reactor has a stainless steel layer instead
of a lead layer it will be converted to a lead layer.
--]]
local function reactor_structure_badness(pos)
local vm = VoxelManip()
local pos1 = vector.subtract(pos, 3)
local pos2 = vector.add(pos, 3)
local MinEdge, MaxEdge = vm:read_from_map(pos1, pos2)
local data = vm:get_data()
local area = VoxelArea:new({MinEdge=MinEdge, MaxEdge=MaxEdge})
local c_blast_concrete = minetest.get_content_id("technic:blast_resistant_concrete")
local c_lead = minetest.get_content_id("technic:lead_block")
local c_steel = minetest.get_content_id("technic:stainless_steel_block")
local c_water_source = minetest.get_content_id(mat.water_source)
local c_water_flowing = minetest.get_content_id(mat.water_flowing)
local blast_layer, steel_layer, lead_layer, water_layer = 0, 0, 0, 0
for z = pos1.z, pos2.z do
for y = pos1.y, pos2.y do
for x = pos1.x, pos2.x do
local cid = data[area:index(x, y, z)]
if x == pos1.x or x == pos2.x or
y == pos1.y or y == pos2.y or
z == pos1.z or z == pos2.z then
if cid == c_blast_concrete then
blast_layer = blast_layer + 1
end
elseif x == pos1.x+1 or x == pos2.x-1 or
y == pos1.y+1 or y == pos2.y-1 or
z == pos1.z+1 or z == pos2.z-1 then
if cid == c_lead then
lead_layer = lead_layer + 1
elseif cid == c_steel then
steel_layer = steel_layer + 1
end
elseif x == pos1.x+2 or x == pos2.x-2 or
y == pos1.y+2 or y == pos2.y-2 or
z == pos1.z+2 or z == pos2.z-2 then
if cid == c_water_source or cid == c_water_flowing then
water_layer = water_layer + 1
end
end
end
end
end
if steel_layer >= 96 then
for z = pos1.z+1, pos2.z-1 do
for y = pos1.y+1, pos2.y-1 do
for x = pos1.x+1, pos2.x-1 do
local vi = area:index(x, y, z)
if x == pos1.x+1 or x == pos2.x-1 or
y == pos1.y+1 or y == pos2.y-1 or
z == pos1.z+1 or z == pos2.z-1 then
if data[vi] == c_steel then
data[vi] = c_lead
end
end
end
end
end
vm:set_data(data)
vm:write_to_map()
lead_layer = steel_layer
end
if water_layer > 25 then water_layer = 25 end
if lead_layer > 96 then lead_layer = 96 end
if blast_layer > 216 then blast_layer = 216 end
return (25 - water_layer) + (96 - lead_layer) + (216 - blast_layer)
end
local mcl_expl_info = {
drop_chance = 1.0,
max_blast_resistance = 10,
sound = true,
particles = true,
fire = true,
griefing = true,
grief_protected = true,
}
local function melt_down_reactor(pos)
minetest.log("action", "A reactor melted down at "..minetest.pos_to_string(pos))
if minetest.get_modpath("mcl_explosions") then
mcl_explosions.explode(pos, 30, mcl_expl_info)
end
minetest.set_node(pos, {name = "technic:corium_source"})
end
local function start_reactor(pos, meta)
if minetest.get_node(pos).name ~= "technic:hv_nuclear_reactor_core" then
return false
end
local inv = meta:get_inventory()
if inv:is_empty("src") then
return false
end
local src_list = inv:get_list("src")
local correct_fuel_count = 0
for _, src_stack in pairs(src_list) do
if src_stack and src_stack:get_name() == fuel_type then
correct_fuel_count = correct_fuel_count + 1
end
end
-- Check that the reactor is complete and has the correct fuel
if correct_fuel_count ~= 6 or reactor_structure_badness(pos) ~= 0 then
return false
end
meta:set_int("burn_time", 1)
technic.swap_node(pos, "technic:hv_nuclear_reactor_core_active")
meta:set_int("HV_EU_supply", power_supply)
for idx, src_stack in pairs(src_list) do
src_stack:take_item()
inv:set_stack("src", idx, src_stack)
end
return true
end
minetest.register_abm({
label = "Machines: reactor melt-down check",
nodenames = {"technic:hv_nuclear_reactor_core_active"},
interval = 4,
chance = 1,
action = function (pos, node)
local meta = minetest.get_meta(pos)
local badness = reactor_structure_badness(pos)
local accum_badness = meta:get_int("structure_accumulated_badness")
if badness == 0 then
if accum_badness ~= 0 then
meta:set_int("structure_accumulated_badness", math.max(accum_badness - 4, 0))
siren_clear(pos, meta)
end
else
siren_danger(pos, meta)
accum_badness = accum_badness + badness
if accum_badness >= 25 then
melt_down_reactor(pos)
else
meta:set_int("structure_accumulated_badness", accum_badness)
end
end
end,
})
local function run(pos, node)
local meta = minetest.get_meta(pos)
local burn_time = meta:get_int("burn_time") or 0
if burn_time >= burn_ticks or burn_time == 0 then
if has_digilines and meta:get_int("HV_EU_supply") == power_supply then
digilines.receptor_send(pos, technic.digilines.rules_allfaces,
-- TODO: Remove "remote_channel" and use de facto standard "channel"
meta:get("channel") or meta:get_string("remote_channel"),
{
command = "fuel_used",
pos = pos
}
)
end
if meta:get_string("autostart") == "true" then
if start_reactor(pos, meta) then
return
end
end
meta:set_int("HV_EU_supply", 0)
meta:set_int("burn_time", 0)
meta:set_string("infotext", S("@1 Idle", reactor_desc))
technic.swap_node(pos, "technic:hv_nuclear_reactor_core")
meta:set_int("structure_accumulated_badness", 0)
siren_clear(pos, meta)
elseif burn_time > 0 then
burn_time = burn_time + 1
meta:set_int("burn_time", burn_time)
local percent = math.floor(burn_time / burn_ticks * 100)
meta:set_string("infotext", S("@1 (@2% Fuel Used)", reactor_desc, percent))
meta:set_int("HV_EU_supply", power_supply)
end
end
local nuclear_reactor_receive_fields = function(pos, formname, fields, sender)
local player_name = sender:get_player_name()
if minetest.is_protected(pos, player_name) then
minetest.chat_send_player(player_name, S("You are not allowed to edit this!"))
minetest.record_protection_violation(pos, player_name)
return
end
local meta = minetest.get_meta(pos)
local update_formspec = false
if fields.channel or fields.remote_channel then
-- TODO: Remove "remote_channel" and use de facto standard "channel"
meta:set_string("remote_channel", fields.channel or fields.remote_channel)
meta:set_string("channel", fields.channel or fields.remote_channel)
end
if fields.start then
local b = start_reactor(pos, meta)
if b then
minetest.chat_send_player(player_name, S("Start successful"))
else
minetest.chat_send_player(player_name, S("Error"))
end
end
if fields.autostart then
meta:set_string("autostart", fields.autostart)
update_formspec = true
end
if fields.enable_digiline then
meta:set_string("enable_digiline", fields.enable_digiline)
update_formspec = true
end
if update_formspec then
meta:set_string("formspec", make_reactor_formspec(meta))
end
end
local digiline_def = function(pos, _, channel, msg)
local meta = minetest.get_meta(pos)
if meta:get_string("enable_digiline") ~= "true" or
-- TODO: Remove "remote_channel" and use de facto standard "channel"
channel ~= (meta:get("channel") or meta:get_string("remote_channel")) then
return
end
-- Convert string messages to tables:
local msgt = type(msg)
if msgt == "string" then
local smsg = msg:lower()
msg = {}
if smsg == "get" then
msg.command = "get"
elseif smsg:sub(1, 13) == "self_destruct" then
msg.command = "self_destruct"
msg.timer = tonumber(smsg:sub(15)) or 0
elseif smsg == "start" then
msg.command = "start"
end
elseif msgt ~= "table" then
return
end
if msg.command == "get" then
local inv = meta:get_inventory()
local invtable = {}
for i = 1, 6 do
local stack = inv:get_stack("src", i)
if stack:is_empty() then
invtable[i] = 0
elseif stack:get_name() == fuel_type then
invtable[i] = stack:get_count()
else
invtable[i] = -stack:get_count()
end
end
digilines.receptor_send(pos, technic.digilines.rules_allfaces, channel, {
burn_time = meta:get_int("burn_time"),
enabled = meta:get_int("HV_EU_supply") == power_supply,
siren = meta:get_int("siren") == 1,
structure_accumulated_badness = meta:get_int("structure_accumulated_badness"),
rods = invtable
})
elseif digiline_meltdown and msg.command == "self_destruct" and
minetest.get_node(pos).name == "technic:hv_nuclear_reactor_core_active" then
if msg.timer ~= 0 and type(msg.timer) == "number" then
siren_danger(pos, meta)
minetest.after(msg.timer, melt_down_reactor, pos)
else
melt_down_reactor(pos)
end
elseif msg.command == "start" then
local b = start_reactor(pos, meta)
if b then
digilines.receptor_send(pos, technic.digilines.rules_allfaces, channel, {
command = "start_success",
pos = pos
})
else
digilines.receptor_send(pos, technic.digilines.rules_allfaces, channel, {
command = "start_error",
pos = pos
})
end
end
end
minetest.register_node("technic:hv_nuclear_reactor_core", {
description = reactor_desc,
tiles = {
"technic_hv_nuclear_reactor_core.png",
"technic_hv_nuclear_reactor_core.png"..cable_entry
},
drawtype = "mesh",
mesh = "technic_reactor.obj",
groups = {cracky = 1, technic_machine = 1, technic_hv = 1, pickaxey = 3},
is_ground_content = false,
_mcl_blast_resistance = 1,
_mcl_hardness = 0.8,
legacy_facedir_simple = true,
sounds = technic.sounds.node_sound_wood_defaults(),
paramtype = "light",
paramtype2 = "facedir",
stack_max = 1,
on_receive_fields = nuclear_reactor_receive_fields,
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("infotext", reactor_desc)
meta:set_string("formspec", make_reactor_formspec(meta))
local inv = meta:get_inventory()
inv:set_size("src", 6)
end,
-- digiline interface
digiline = {
receptor = {
rules = technic.digilines.rules_allfaces,
action = function() end,
},
effector = {
rules = technic.digilines.rules_allfaces,
action = digiline_def,
},
},
can_dig = technic.machine_can_dig,
on_destruct = function(pos) siren_set_state(pos, SS_OFF) end,
allow_metadata_inventory_put = technic.machine_inventory_put,
allow_metadata_inventory_take = technic.machine_inventory_take,
allow_metadata_inventory_move = technic.machine_inventory_move,
on_metadata_inventory_move = technic.machine_on_inventory_move,
on_metadata_inventory_put = technic.machine_on_inventory_put,
on_metadata_inventory_take = technic.machine_on_inventory_take,
technic_run = run,
})
minetest.register_node("technic:hv_nuclear_reactor_core_active", {
tiles = {
"technic_hv_nuclear_reactor_core.png",
"technic_hv_nuclear_reactor_core.png"..cable_entry
},
drawtype = "mesh",
mesh = "technic_reactor.obj",
groups = {cracky = 1, technic_machine = 1, technic_hv = 1, radioactive = 4,
not_in_creative_inventory = 1, pickaxey = 3},
is_ground_content = false,
_mcl_blast_resistance = 1,
_mcl_hardness = 0.8,
legacy_facedir_simple = true,
sounds = technic.sounds.node_sound_wood_defaults(),
drop = "technic:hv_nuclear_reactor_core",
light_source = 14,
paramtype = "light",
paramtype2 = "facedir",
on_receive_fields = nuclear_reactor_receive_fields,
-- digiline interface
digiline = {
receptor = {
rules = technic.digilines.rules_allfaces,
action = function() end,
},
effector = {
rules = technic.digilines.rules_allfaces,
action = digiline_def,
},
},
can_dig = technic.machine_can_dig,
after_dig_node = melt_down_reactor,
on_destruct = function(pos) siren_set_state(pos, SS_OFF) end,
allow_metadata_inventory_put = technic.machine_inventory_put,
allow_metadata_inventory_take = technic.machine_inventory_take,
allow_metadata_inventory_move = technic.machine_inventory_move,
on_metadata_inventory_move = technic.machine_on_inventory_move,
on_metadata_inventory_put = technic.machine_on_inventory_put,
on_metadata_inventory_take = technic.machine_on_inventory_take,
technic_run = run,
technic_on_disable = function(pos, node)
local timer = minetest.get_node_timer(pos)
timer:start(1)
end,
on_timer = function(pos, node)
-- Connected back?
if technic.get_timeout("HV", pos) > 0 then return false end
local meta = minetest.get_meta(pos)
local burn_time = meta:get_int("burn_time") or 0
if burn_time >= burn_ticks or burn_time == 0 then
meta:set_int("HV_EU_supply", 0)
meta:set_int("burn_time", 0)
technic.swap_node(pos, "technic:hv_nuclear_reactor_core")
meta:set_int("structure_accumulated_badness", 0)
siren_clear(pos, meta)
return false
end
meta:set_int("burn_time", burn_time + 1)
return true
end,
})
technic.register_machine("HV", "technic:hv_nuclear_reactor_core", technic.producer)
technic.register_machine("HV", "technic:hv_nuclear_reactor_core_active", technic.producer)

View file

@ -0,0 +1,640 @@
local S = technic.getter
local has_digilines = minetest.get_modpath("digilines")
local has_mesecons = minetest.get_modpath("mesecons")
local has_vizlib = minetest.get_modpath("vizlib")
local has_jumpdrive = minetest.get_modpath("jumpdrive")
local has_mcl = minetest.get_modpath("mcl_formspec")
local quarry_max_depth = technic.config:get_int("quarry_max_depth")
local quarry_dig_particles = technic.config:get_bool("quarry_dig_particles")
local quarry_time_limit = technic.config:get_int("quarry_time_limit")
local quarry_demand = 10000
local network_time_limit = 30000
local infotext
do
local name = S("@1 Quarry", S("HV"))
local demand = S("Demand: @1", technic.EU_string(quarry_demand))
infotext = {
active = S("@1 Active", name).."\n"..demand,
disabled = S("@1 Disabled", name),
finished = S("@1 Finished", name),
purge = S("@1 Purging Cache", name),
unpowered = S("@1 Unpowered", name),
}
end
-- Hard-coded outward-spiral dig pattern for up to 17x17 dig area
local dig_pattern = {
0,1,2,2,3,3,0,0,0,1,1,1,2,2,2,2,3,3,3,3,0,0,0,0,0,1,1,1,1,1,2,2,
2,2,2,2,3,3,3,3,3,3,0,0,0,0,0,0,0,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,
2,2,2,2,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,
1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,
0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
}
-- Convert the dig pattern values to x/z offset vectors
do
local head = vector.new()
dig_pattern[0] = head
for i = 1, #dig_pattern do
head = vector.add(head, minetest.facedir_to_dir(dig_pattern[i]))
dig_pattern[i] = {x = head.x, z = head.z}
end
end
-- Cache of pipeworks fake players
local fake_players = {}
minetest.register_on_leaveplayer(function(player)
fake_players[player:get_player_name()] = nil
end)
local function get_fake_player(name)
if not fake_players[name] then
fake_players[name] = pipeworks.create_fake_player({name = name})
end
return fake_players[name]
end
local function player_allowed(pos, name)
local owner = minetest.get_meta(pos):get_string("owner")
if owner == "" or owner == name then
return true
end
return not minetest.is_protected(pos, name)
end
local function can_dig_node(pos, dig_pos, node_name, owner, digger)
if node_name == "air" or node_name == "vacuum:vacuum" then
return false
end
if vector.equals(pos, dig_pos) then
return false -- Don't dig self
end
local def = minetest.registered_nodes[node_name]
if not def or not def.diggable or (def.can_dig and not def.can_dig(dig_pos, digger)) then
return false
end
if def._mcl_hardness == -1 then
return false
end
return not minetest.is_protected(dig_pos, owner)
end
local function do_purge(pos, meta)
local inv = meta:get_inventory()
for i, stack in ipairs(inv:get_list("cache")) do
if not stack:is_empty() then
technic.tube_inject_item(pos, pos, vector.new(0, 1, 0), stack:to_table())
inv:set_stack("cache", i, "")
break
end
end
if inv:is_empty("cache") then
meta:set_int("purge_on", 0)
end
end
local function spawn_dig_particles(pos, dig_pos, node)
local end_pos = vector.new(pos.x, pos.y - 0.5, pos.z)
local dist = vector.distance(dig_pos, end_pos)
local t = math.sqrt((2 * dist) / 20)
local acc = vector.multiply(vector.subtract(end_pos, dig_pos), (1 / dist) * 20)
minetest.add_particlespawner({
amount = 50,
time = 0.5,
minpos = vector.subtract(dig_pos, 0.4),
maxpos = vector.add(dig_pos, 0.4),
minacc = acc,
maxacc = acc,
minsize = 0.5,
maxsize = 1.5,
minexptime = t,
maxexptime = t,
node = node,
})
end
local function do_digging(pos, meta, net_time)
local us_start = minetest.get_us_time()
local step = tonumber(meta:get("step") or "")
if not step then
-- Missing metadata or not yet updated by conversion LBM, abort digging
return
end
local radius = meta:get_int("size")
local diameter = radius * 2 + 1
local num_steps = diameter * diameter
local dug = meta:get_int("dug")
local max_depth = meta:get_int("max_depth")
local offset = {
x = meta:get_int("offset_x"),
y = math.floor(step / num_steps) + 1 - meta:get_int("offset_y"),
z = meta:get_int("offset_z")
}
if dug == -1 then
-- Find ground before digging
if offset.y > max_depth then
meta:set_int("finished", 1)
return
end
local pos1 = {
x = pos.x + offset.x - radius,
y = pos.y - offset.y,
z = pos.z + offset.z - radius
}
local pos2 = {
x = pos.x + offset.x + radius,
y = pos.y - offset.y,
z = pos.z + offset.z + radius
}
minetest.load_area(pos1, pos2)
local nodes = minetest.find_nodes_in_area(pos1, pos2, {"air", "vacuum:vacuum"})
if #nodes < num_steps then
-- There are nodes to dig, start digging at this layer
meta:set_int("dug", 0)
else
-- Move down to next layer
meta:set_int("step", step + num_steps)
end
return
end
local owner = meta:get_string("owner")
local digger = get_fake_player(owner)
while true do
-- Search for something to dig
if offset.y > max_depth then
-- Finished digging
meta:set_int("finished", 1)
meta:set_int("purge_on", 1)
break
end
local dig_offset = dig_pattern[step % num_steps]
local dig_pos = {
x = pos.x + offset.x + dig_offset.x,
y = pos.y - offset.y,
z = pos.z + offset.z + dig_offset.z,
}
step = step + 1
if step % num_steps == 0 then
-- Finished this layer, move down
offset.y = offset.y + 1
end
local node = technic.get_or_load_node(dig_pos)
if can_dig_node(pos, dig_pos, node.name, owner, digger) then
-- Found something to dig, dig it and stop
minetest.remove_node(dig_pos)
if quarry_dig_particles then
spawn_dig_particles(pos, dig_pos, node)
end
local inv = meta:get_inventory()
local drops = minetest.get_node_drops(node.name, "")
local full = false
for _, item in ipairs(drops) do
local left = inv:add_item("cache", item)
while not left:is_empty() do
-- Cache is full, forcibly purge until the item fits
full = true
do_purge(pos, meta)
left = inv:add_item("cache", left)
end
end
dug = dug + 1
if full or dug % 99 == 0 then
-- Time to purge the cache
meta:set_int("purge_on", 1)
end
break
end
local us_used = minetest.get_us_time() - us_start
if us_used > quarry_time_limit or net_time + us_used > network_time_limit then
break
end
end
meta:set_int("dug", dug)
meta:set_int("step", step)
end
local function quarry_run(pos, _, _, network)
local meta = minetest.get_meta(pos)
if meta:get_int("purge_on") == 1 then
-- Purging
meta:set_string("infotext", infotext.purge)
meta:set_int("HV_EU_demand", 0)
do_purge(pos, meta)
elseif meta:get_int("finished") == 1 then
-- Finished
meta:set_string("infotext", infotext.finished)
meta:set_int("HV_EU_demand", 0)
elseif meta:get_int("enabled") == 1 then
-- Active
if meta:get_int("HV_EU_input") >= quarry_demand then
meta:set_string("infotext", infotext.active)
do_digging(pos, meta, network.lag)
else
meta:set_string("infotext", infotext.unpowered)
end
meta:set_int("HV_EU_demand", quarry_demand)
else
-- Disabled
meta:set_int("HV_EU_demand", 0)
meta:set_string("infotext", infotext.disabled)
if not meta:get_inventory():is_empty("cache") then
meta:set_int("purge_on", 1)
end
end
end
local function reset_quarry(meta)
meta:set_int("step", 0)
meta:set_int("dug", -1)
meta:set_int("purge_on", 1)
meta:set_int("finished", 0)
end
local size = minetest.get_modpath("mcl_formspec") and "size[9,10]" or "size[8,9]"
local base_formspec = size..
"label[0,0;"..S("@1 Quarry", S("HV")).."]"..
"list[context;cache;0,0.7;4,3;]"..
"listring[context;cache]"..
"button[6,0.6;2,1;restart;"..S("Restart").."]"..
"field[4.3,2.1;2,1;size;"..S("Radius")..";${size}]"..
"field[6.3,2.1;2,1;max_depth;"..S("Max Depth")..";${max_depth}]"..
"field[4.3,3.1;1.333,1;offset_x;"..S("Offset X")..";${offset_x}]"..
"field[5.633,3.1;1.333,1;offset_y;"..S("Offset Y")..";${offset_y}]"..
"field[6.966,3.1;1.333,1;offset_z;"..S("Offset Z")..";${offset_z}]"
if has_digilines then
base_formspec = base_formspec..
"field[4.3,4.2;4,1;channel;"..S("Digiline Channel")..";${channel}]"
end
if has_mcl then
base_formspec = base_formspec..
mcl_formspec.get_itemslot_bg(0,0.7,4,3)..
-- player inventory
"list[current_player;main;0,5.5;9,3;9]"..
mcl_formspec.get_itemslot_bg(0,5.5,9,3)..
"list[current_player;main;0,8.74;9,1;]"..
mcl_formspec.get_itemslot_bg(0,8.74,9,1)..
"listring[current_player;main]"
else
base_formspec = base_formspec..
"list[current_player;main;0,5;8,4;]"..
"listring[current_player;main]"
end
local function update_formspec(meta)
local fs = base_formspec
local status = S("Digging not started")
if meta:get_int("purge_on") == 1 then
status = S("Purging cache")
elseif meta:get_int("finished") == 1 then
status = S("Digging finished")
elseif meta:get_int("enabled") == 1 then
local diameter = meta:get_int("size") * 2 + 1
local num_steps = diameter * diameter
local y_level = math.floor(meta:get_int("step") / num_steps) + 1 - meta:get_int("offset_y")
if y_level < 0 then
status = S("Digging @1 m above machine", math.abs(y_level))
else
status = S("Digging @1 m below machine", y_level)
end
end
if meta:get_int("enabled") == 1 then
fs = fs.."button[4,0.6;2,1;disable;"..S("Enabled").."]"
else
fs = fs.."button[4,0.6;2,1;enable;"..S("Disabled").."]"
end
if has_mesecons then
local selected = meta:get("mesecons") or "true"
if has_jumpdrive then
fs = fs.."checkbox[0,3.6;mesecons;"..S("Enable Mesecons Control")..";"..selected.."]"
else
fs = fs.."checkbox[0,3.8;mesecons;"..S("Enable Mesecons Control")..";"..selected.."]"
end
end
if has_jumpdrive then
local selected = meta:get("reset_on_move") or "true"
if has_mesecons then
fs = fs.."checkbox[0,4.1;reset_on_move;"..S("Restart When Moved")..";"..selected.."]"
else
fs = fs.."checkbox[0,3.8;reset_on_move;"..S("Restart When Moved")..";"..selected.."]"
end
end
meta:set_string("formspec", fs.."label[4,0;"..status.."]")
end
local function clamp(value, min, max, default)
value = tonumber(value) or default or max
return math.min(math.max(value, min), max)
end
local function quarry_receive_fields(pos, _, fields, sender)
local player_name = sender:get_player_name()
if not player_allowed(pos, player_name) then
minetest.chat_send_player(player_name, S("You are not allowed to edit this!"))
return
end
local meta = minetest.get_meta(pos)
if fields.size then
meta:set_int("size", clamp(fields.size, 0, 8, 4))
end
if fields.max_depth then
local depth = clamp(fields.max_depth, 1, quarry_max_depth)
meta:set_int("max_depth", depth)
local ymin = -math.min(10, depth - 1)
meta:set_int("offset_y", clamp(meta:get_int("offset_y"), ymin, 10, 0))
end
if fields.offset_x then
meta:set_int("offset_x", clamp(fields.offset_x, -10, 10, 0))
end
if fields.offset_y then
local ymin = -math.min(10, meta:get_int("max_depth") - 1)
meta:set_int("offset_y", clamp(fields.offset_y, ymin, 10, 0))
end
if fields.offset_z then
meta:set_int("offset_z", clamp(fields.offset_z, -10, 10, 0))
end
if fields.mesecons then
meta:set_string("mesecons", fields.mesecons)
end
if fields.reset_on_move then
meta:set_string("reset_on_move", fields.reset_on_move)
end
if fields.channel then
meta:set_string("channel", fields.channel)
end
if fields.enable then meta:set_int("enabled", 1) end
if fields.disable then meta:set_int("enabled", 0) end
if fields.restart then reset_quarry(meta) end
update_formspec(meta)
end
local function show_working_area(pos, _, player)
if not player or player:get_wielded_item():get_name() ~= "" then
-- Only spawn particles when using an empty hand
return
end
local meta = minetest.get_meta(pos)
local radius = meta:get_int("size") + 0.5
local offset = vector.new(meta:get_int("offset_x"), meta:get_int("offset_y"), meta:get_int("offset_z"))
local depth = meta:get_int("max_depth") + 0.5
-- Draw area from top corner to bottom corner
local pos1 = vector.add(pos, vector.new(offset.x - radius, offset.y - 0.5, offset.z - radius))
local pos2 = vector.add(pos, vector.new(offset.x + radius, -depth, offset.z + radius))
vizlib.draw_area(pos1, pos2, {player = player})
end
local function digiline_action(pos, _, channel, msg)
local meta = minetest.get_meta(pos)
if channel ~= meta:get_string("channel") then
return
end
-- Convert string message to table
if type(msg) == "string" then
msg = msg:lower()
if msg == "get" or msg == "on" or msg == "off" or msg == "restart" then
msg = {command = msg}
elseif msg:sub(1, 7) == "radius " then
msg = {command = "radius", value = msg:sub(8,-1)}
elseif msg:sub(1,10) == "max_depth " then
msg = {command = "max_depth", value = msg:sub(11,-1)}
elseif msg:sub(1,9) == "offset_x " then
msg = {command = "offset_x", value = msg:sub(10,-1)}
elseif msg:sub(1,9) == "offset_y " then
msg = {command = "offset_y", value = msg:sub(10,-1)}
elseif msg:sub(1,9) == "offset_z " then
msg = {command = "offset_z", value = msg:sub(10,-1)}
elseif msg:sub(1,7) == "offset " then
local s = string.split(msg:sub(8,-1), ",")
msg = {command = "offset", value = {x = s[1], y = s[2], z = s[3]}}
end
end
if type(msg) ~= "table" then return end
-- Convert old message format to new format
if msg.command ~= "set" and msg.command ~= "get" then
local cmd = msg.command
if cmd == "restart" then
msg = {command = "set", restart = true}
elseif cmd == "on" or cmd == "off" then
msg = {command = "set", enabled = msg.command == "on"}
elseif cmd == "radius" or cmd == "max_depth" or cmd == "offset"
or cmd == "offset_x" or cmd == "offset_y" or cmd == "offset_z" then
msg = {command = "set", [cmd] = msg.value}
end
end
-- Process message
if msg.command == "get" then
local diameter = meta:get_int("size") * 2 + 1
local num_steps = diameter * diameter
local offset = {
x = meta:get_int("offset_x"),
y = meta:get_int("offset_y"),
z = meta:get_int("offset_z")
}
digilines.receptor_send(pos, technic.digilines.rules, channel, {
enabled = meta:get_int("enabled") == 1,
finished = meta:get_int("finished") == 1,
radius = meta:get_int("size"),
max_depth = meta:get_int("max_depth"),
offset_x = offset.x,
offset_y = offset.y,
offset_z = offset.z,
offset = offset,
dug_nodes = meta:get_int("dug"),
dig_level = -(math.floor(meta:get_int("step") / num_steps) + 1 - offset.y),
})
elseif msg.command == "set" then
if msg.enabled ~= nil then
meta:set_int("enabled", msg.enabled == true and 1 or 0)
end
if msg.restart == true then
reset_quarry(meta)
end
if msg.radius then
meta:set_int("size", clamp(msg.radius, 0, 8, 4))
end
if msg.max_depth then
local depth = clamp(msg.max_depth, 1, quarry_max_depth)
meta:set_int("max_depth", depth)
local ymin = -math.min(10, depth - 1)
meta:set_int("offset_y", clamp(meta:get_int("offset_y"), ymin, 10, 0))
end
if msg.offset_x then
meta:set_int("offset_x", clamp(msg.offset_x, -10, 10, 0))
end
if msg.offset_y then
local ymin = -math.min(10, meta:get_int("max_depth") - 1)
meta:set_int("offset_y", clamp(msg.offset_y, ymin, 10, 0))
end
if msg.offset_z then
meta:set_int("offset_z", clamp(msg.offset_z, -10, 10, 0))
end
if msg.offset and type(msg.offset) == "table" then
local ymin = -math.min(10, meta:get_int("max_depth") - 1)
meta:set_int("offset_x", clamp(msg.offset.x, -10, 10, 0))
meta:set_int("offset_y", clamp(msg.offset.y, ymin, 10, 0))
meta:set_int("offset_z", clamp(msg.offset.z, -10, 10, 0))
end
end
end
minetest.register_node("technic:quarry", {
description = S("@1 Quarry", S("HV")),
tiles = {
"technic_carbon_steel_block.png^pipeworks_tube_connection_metallic.png",
"technic_carbon_steel_block.png^technic_quarry_bottom.png",
"technic_carbon_steel_block.png^technic_cable_connection_overlay.png",
"technic_carbon_steel_block.png^technic_cable_connection_overlay.png",
"technic_carbon_steel_block.png^technic_cable_connection_overlay.png",
"technic_carbon_steel_block.png^technic_cable_connection_overlay.png"
},
groups = {cracky = 2, tubedevice = 1, technic_machine = 1, technic_hv = 1, pickaxey = 2},
is_ground_content = false,
_mcl_blast_resistance = 1,
_mcl_hardness = 0.8,
connect_sides = {"front", "back", "left", "right"},
tube = {
connect_sides = {top = 1},
-- Lower priority than tubes, so items will prefer any tube to another quarry
priority = 10,
can_go = function(pos, node, velocity, stack)
-- Always eject up, even if items came in another way
return { vector.new(0, 1, 0) }
end
},
on_punch = has_vizlib and show_working_area or nil,
on_rightclick = function(pos)
local meta = minetest.get_meta(pos)
update_formspec(meta)
end,
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_int("size", 4)
meta:set_int("offset_x", 0)
meta:set_int("offset_y", 0)
meta:set_int("offset_z", 0)
meta:set_int("max_depth", quarry_max_depth)
meta:set_string("mesecons", "false")
meta:set_string("reset_on_move", "false")
meta:get_inventory():set_size("cache", 12)
reset_quarry(meta)
update_formspec(meta)
end,
on_movenode = has_jumpdrive and function(_, pos)
local meta = minetest.get_meta(pos)
if meta:get("reset_on_move") ~= "false" then
reset_quarry(meta)
end
end or nil,
after_place_node = function(pos, placer, itemstack)
minetest.get_meta(pos):set_string("owner", placer:get_player_name())
pipeworks.scan_for_tube_objects(pos)
end,
can_dig = function(pos, player)
return minetest.get_meta(pos):get_inventory():is_empty("cache")
end,
after_dig_node = pipeworks.scan_for_tube_objects,
on_receive_fields = quarry_receive_fields,
technic_run = quarry_run,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
return player_allowed(pos, player:get_player_name()) and count or 0
end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
return player_allowed(pos, player:get_player_name()) and stack:get_count() or 0
end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
return player_allowed(pos, player:get_player_name()) and stack:get_count() or 0
end,
on_metadata_inventory_move = technic.machine_on_inventory_move,
on_metadata_inventory_put = technic.machine_on_inventory_put,
on_metadata_inventory_take = technic.machine_on_inventory_take,
mesecons = {
effector = {
action_on = function(pos)
local meta = minetest.get_meta(pos)
if meta:get("mesecons") ~= "false" then
meta:set_int("enabled", 1)
end
end,
action_off = function(pos)
local meta = minetest.get_meta(pos)
if meta:get("mesecons") ~= "false" then
meta:set_int("enabled", 0)
end
end
}
},
digiline = {
receptor = {
rules = technic.digilines.rules,
},
effector = {
rules = technic.digilines.rules,
action = digiline_action,
}
},
})
minetest.register_craft({
output = "technic:quarry",
recipe = {
{"technic:carbon_plate", "pipeworks:filter", "technic:composite_plate"},
{"basic_materials:motor", "technic:machine_casing", "technic:diamond_drill_head"},
{"technic:carbon_steel_block", "technic:hv_cable", "technic:carbon_steel_block"}
}
})
technic.register_machine("HV", "technic:quarry", technic.receiver)
minetest.register_lbm({
label = "Old quarry conversion",
name = "technic:old_quarry_conversion",
nodenames = {"technic:quarry"},
run_at_every_load = false,
action = function(pos, node)
local meta = minetest.get_meta(pos)
if meta:get("step") then
-- Quarry v3, don't do anything
-- This can happen when a quarry is moved with a jumpdrive
return
elseif meta:get("quarry_pos") then
-- Quarry v2, calculate step if quarry is digging below
local level = meta:get_int("dig_level") - pos.y
if level < 0 then
local diameter = meta:get_int("size") * 2 + 1
local num_steps = diameter * diameter
-- Convert the negative value to positive, and go back up one level
level = math.abs(level + 1)
meta:set_int("step", level * num_steps)
end
-- Delete unused meta values
meta:set_string("quarry_dir", "")
meta:set_string("quarry_pos", "")
meta:set_string("dig_pos", "")
meta:set_string("dig_level", "")
meta:set_string("dig_index", "")
meta:set_string("dig_steps", "")
else
-- Quarry v1, reset quarry
reset_quarry(meta)
end
local dir = minetest.facedir_to_dir(node.param2)
local offset = vector.multiply(dir, meta:get_int("size") + 1)
meta:set_int("offset_x", offset.x)
meta:set_int("offset_y", 4)
meta:set_int("offset_z", offset.z)
if not meta:get("max_depth") then
meta:set_int("max_depth", quarry_max_depth)
end
update_formspec(meta)
end
})

View file

@ -0,0 +1,18 @@
-- The high voltage solar array is an assembly of medium voltage arrays.
-- Solar arrays are not able to store large amounts of energy.
minetest.register_craft({
output = 'technic:hv_solar_array 1',
recipe = {
{'technic:mv_solar_array', 'technic:mv_solar_array', 'technic:mv_solar_array'},
{'technic:carbon_plate', 'technic:hv_transformer', 'technic:composite_plate'},
{'', 'technic:hv_cable', ''},
}
})
technic.register_solar_array("technic:hv_solar_array", {
tier="HV",
power=100
})
minetest.register_alias("technic:solar_array_hv", "technic:hv_solar_array")