444 lines
17 KiB
Lua
444 lines
17 KiB
Lua
-- API for the technic CNC machine
|
|
-- Again code is adapted from the NonCubic Blocks MOD v1.4 by yves_de_beck
|
|
|
|
local S = technic_cnc.getter
|
|
|
|
-- Generic function for registering all the different node types
|
|
function technic_cnc.register_program(recipeitem, suffix, model, groups, images, description, cbox, sbox)
|
|
|
|
local dtype
|
|
local nodeboxdef
|
|
local meshdef
|
|
|
|
if type(model) ~= "string" then -- assume a nodebox if it's a table or function call
|
|
dtype = "nodebox"
|
|
nodeboxdef = {
|
|
type = "fixed",
|
|
fixed = model
|
|
}
|
|
else
|
|
dtype = "mesh"
|
|
meshdef = model
|
|
end
|
|
|
|
if cbox and not sbox then sbox = cbox end
|
|
|
|
minetest.register_node(":"..recipeitem.."_"..suffix, {
|
|
description = description,
|
|
drawtype = dtype,
|
|
node_box = nodeboxdef,
|
|
mesh = meshdef,
|
|
tiles = images,
|
|
paramtype = "light",
|
|
paramtype2 = "facedir",
|
|
walkable = true,
|
|
groups = groups,
|
|
selection_box = sbox,
|
|
collision_box = cbox
|
|
})
|
|
end
|
|
|
|
-- function to iterate over all the programs the CNC machine knows
|
|
function technic_cnc.register_all(recipeitem, groups, images, description)
|
|
for _, data in ipairs(technic_cnc.programs) do
|
|
-- Disable node creation for disabled node types for some material
|
|
local do_register = true
|
|
if technic_cnc.programs_disable[recipeitem] ~= nil then
|
|
for __, disable in ipairs(technic_cnc.programs_disable[recipeitem]) do
|
|
if disable == data.suffix then
|
|
do_register = false
|
|
end
|
|
end
|
|
end
|
|
-- Create the node if it passes the test
|
|
if do_register then
|
|
technic_cnc.register_program(recipeitem, data.suffix, data.model,
|
|
groups, images, description.." "..data.desc, data.cbox, data.sbox)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- REGISTER NEW TECHNIC_CNC_API's PART 2:
|
|
-- technic_cnc..register_element_end(subname, recipeitem, groups, images, desc_element_xyz)
|
|
------------------------------------------------------------------------------------------------------------
|
|
function technic_cnc.register_slope_edge_etc(recipeitem, groups, images, desc_slope, desc_slope_lying,
|
|
desc_slope_upsdown, desc_slope_edge, desc_slope_inner_edge, desc_slope_upsdwn_edge,
|
|
desc_slope_upsdwn_inner_edge, desc_pyramid, desc_spike, desc_onecurvededge, desc_twocurvededge,
|
|
desc_cylinder, desc_cylinder_horizontal, desc_spheroid, desc_element_straight, desc_element_edge,
|
|
desc_element_t, desc_element_cross, desc_element_end)
|
|
technic_cnc.register_slope(recipeitem, groups, images, desc_slope)
|
|
technic_cnc.register_slope_lying(recipeitem, groups, images, desc_slope_lying)
|
|
technic_cnc.register_slope_upsdown(recipeitem, groups, images, desc_slope_upsdown)
|
|
technic_cnc.register_slope_edge(recipeitem, groups, images, desc_slope_edge)
|
|
technic_cnc.register_slope_inner_edge(recipeitem, groups, images, desc_slope_inner_edge)
|
|
technic_cnc.register_slope_edge_upsdown(recipeitem, groups, images, desc_slope_upsdwn_edge)
|
|
technic_cnc.register_slope_inner_edge_upsdown(recipeitem, groups, images, desc_slope_upsdwn_inner_edge)
|
|
technic_cnc.register_pyramid(recipeitem, groups, images, desc_pyramid)
|
|
technic_cnc.register_spike(recipeitem, groups, images, desc_spike)
|
|
technic_cnc.register_onecurvededge(recipeitem, groups, images, desc_onecurvededge)
|
|
technic_cnc.register_twocurvededge(recipeitem, groups, images, desc_twocurvededge)
|
|
technic_cnc.register_cylinder(recipeitem, groups, images, desc_cylinder)
|
|
technic_cnc.register_cylinder_horizontal(recipeitem, groups, images, desc_cylinder_horizontal)
|
|
technic_cnc.register_spheroid(recipeitem, groups, images, desc_spheroid)
|
|
technic_cnc.register_element_straight(recipeitem, groups, images, desc_element_straight)
|
|
technic_cnc.register_element_edge(recipeitem, groups, images, desc_element_edge)
|
|
technic_cnc.register_element_t(recipeitem, groups, images, desc_element_t)
|
|
technic_cnc.register_element_cross(recipeitem, groups, images, desc_element_cross)
|
|
technic_cnc.register_element_end(recipeitem, groups, images, desc_element_end)
|
|
end
|
|
|
|
-- REGISTER STICKS: noncubic.register_xyz(recipeitem, groups, images, desc_element_xyz)
|
|
------------------------------------------------------------------------------------------------------------
|
|
function technic_cnc.register_stick_etc(recipeitem, groups, images, desc_stick)
|
|
technic_cnc.register_stick(recipeitem, groups, images, desc_stick)
|
|
end
|
|
|
|
function technic_cnc.register_elements(recipeitem, groups, images, desc_element_straight_double,
|
|
desc_element_edge_double, desc_element_t_double, desc_element_cross_double, desc_element_end_double)
|
|
technic_cnc.register_element_straight_double(recipeitem, groups, images, desc_element_straight_double)
|
|
technic_cnc.register_element_edge_double(recipeitem, groups, images, desc_element_edge_double)
|
|
technic_cnc.register_element_t_double(recipeitem, groups, images, desc_element_t_double)
|
|
technic_cnc.register_element_cross_double(recipeitem, groups, images, desc_element_cross_double)
|
|
technic_cnc.register_element_end_double(recipeitem, groups, images, desc_element_end_double)
|
|
end
|
|
|
|
-- CNC MACHINE API
|
|
------------------------------------------------------------------------------------------------------------
|
|
|
|
function technic_cnc.get_product(program, material, size)
|
|
-- Get and return product item string with stack size or nil if product not available
|
|
local multiplier = technic_cnc.products[program]
|
|
if multiplier then
|
|
size = math.max(1, math.min(2, size))
|
|
local twosize = technic_cnc.twosize_products[program]
|
|
local double = size == 1 and twosize and "_double" or ""
|
|
local product = ("%s_technic_cnc_%s%s"):format(material, program, double)
|
|
if minetest.registered_nodes[product] then
|
|
return ("%s %d"):format(product, multiplier * (twosize and size or 1))
|
|
end
|
|
end
|
|
end
|
|
|
|
function technic_cnc.set_program(meta, program, size)
|
|
if technic_cnc.products[program] then
|
|
if size then
|
|
meta:set_int("size", math.max(1, math.min(2, size)))
|
|
end
|
|
meta:set_string("program", program)
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
function technic_cnc.is_enabled(meta)
|
|
return meta:get("disable") == nil
|
|
end
|
|
|
|
function technic_cnc.enable(meta)
|
|
meta:set_string("disable", "")
|
|
end
|
|
|
|
function technic_cnc.disable(meta)
|
|
meta:set_string("disable", "1")
|
|
meta:set_string("LV_EU_demand", "")
|
|
end
|
|
|
|
function technic_cnc.get_material(inventory)
|
|
local srclist = inventory:get_list("src")
|
|
for index, stack in ipairs(srclist) do
|
|
if not stack:is_empty() then
|
|
return index, stack
|
|
end
|
|
end
|
|
end
|
|
|
|
function technic_cnc.produce(meta, inventory)
|
|
-- Get and check program
|
|
local program = meta:get("program")
|
|
if program then
|
|
-- Get material stack
|
|
local index, materialstack = technic_cnc.get_material(inventory)
|
|
if index and materialstack then
|
|
-- Get product and produce items if output has enough space
|
|
local size = meta:get_int("size")
|
|
local product = technic_cnc.get_product(program, materialstack:get_name(), size)
|
|
if product and inventory:room_for_item("dst", product) then
|
|
-- Remove materials from input inventory
|
|
materialstack:take_item()
|
|
inventory:set_stack("src", index, materialstack)
|
|
|
|
-- Add results to output inventory of machine
|
|
inventory:add_item("dst", product)
|
|
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
-- REGISTER MACHINES
|
|
------------------------------------------------------------------------------------------------------------
|
|
|
|
function technic_cnc.register_cnc_machine(nodename, def)
|
|
-- Basic sanity check for registration, prefer failing early
|
|
assert(type(nodename) == "string" and #nodename > 0, "nodename should be non empty string")
|
|
assert(type(def.description) == "string", "description field should be string")
|
|
assert(({["nil"]=1,number=1})[type(def.input_size)], "input_size field should be number if set")
|
|
assert(({["nil"]=1,number=1})[type(def.output_size)], "output_size field should be number if set")
|
|
assert(({["nil"]=1,["function"]=1})[type(def.get_formspec)], "get_formspec should be function if set")
|
|
assert(({["nil"]=1,["function"]=1})[type(def.on_receive_fields)], "on_receive_fields should be function if set")
|
|
assert(({["nil"]=1,["function"]=1})[type(def.technic_run)], "technic_run should be function if set")
|
|
assert(({["nil"]=1,table=1})[type(def.tube)], "tube field should be table if set")
|
|
|
|
-- Register recipe if recipe given
|
|
if def.recipe then
|
|
minetest.register_craft({
|
|
output = nodename,
|
|
recipe = def.recipe,
|
|
})
|
|
end
|
|
|
|
-- Collect / generate basic variables for CNC machine
|
|
local nodename_active = nodename .. "_active"
|
|
local idle_infotext = S("%s Idle"):format(def.description)
|
|
local active_infotext = S("%s Active"):format(def.description)
|
|
local unpowered_infotext = S("%s Unpowered"):format(def.description)
|
|
local groups = { cracky = 2, technic_machine = 1, technic_lv = 1 }
|
|
-- It is possible to override these using def fields
|
|
local on_receive_fields = def.on_receive_fields or technic_cnc.formspec.on_receive_fields
|
|
local get_formspec = def.get_formspec or technic_cnc.formspec.get_formspec
|
|
local input_size = def.input_size or 1
|
|
local output_size = def.output_size or 4
|
|
local technic_run
|
|
local after_dig_node
|
|
local allow_metadata_inventory_put
|
|
local allow_metadata_inventory_take
|
|
local allow_metadata_inventory_move
|
|
local can_dig
|
|
|
|
-- Update few variables in definition table to make some things easier
|
|
def.get_formspec = get_formspec
|
|
def.input_size = input_size
|
|
def.output_size = output_size
|
|
|
|
-- UPGRADE OLD CNC MACHINES
|
|
local function upgrade_machine(meta)
|
|
local oldmeta = meta:get("technic_power_machine")
|
|
if oldmeta then
|
|
local product = meta:get("cnc_product")
|
|
-- Remove old metadata fields
|
|
meta:set_string("cnc_product", "")
|
|
meta:set_string("cnc_multiplier", "")
|
|
meta:set_string("technic_power_machine", "")
|
|
if product then
|
|
-- Only executed for active machines, old inactive machines do not have cnc_product set
|
|
local program_raw = product:match("[%w_]+:[%w_]+_technic_cnc_([%w_]+)")
|
|
if program_raw then
|
|
local double = "_double"
|
|
local size = program_raw:sub(-#double) == double and 1 or 2
|
|
local program = size == 1 and program_raw:sub(1, #program_raw - #double) or program_raw
|
|
meta:set_string("program", program)
|
|
meta:set_int("size", size)
|
|
end
|
|
meta:set_string("formspec", get_formspec(nodename, def, meta))
|
|
end
|
|
end
|
|
end
|
|
|
|
if technic_cnc.use_technic and not def.technic_run then
|
|
-- Check and get EU demand for Technic CNC machine
|
|
assert(type(def.demand) == "number", "demand field must be set for Technic CNC")
|
|
|
|
-- Update machine state if needed
|
|
local function update_machine(pos, meta, oldname, newname, infotext, demand)
|
|
if demand then
|
|
meta:set_int("LV_EU_demand", demand)
|
|
end
|
|
meta:set_string("infotext", infotext)
|
|
technic.swap_node(pos, newname)
|
|
end
|
|
|
|
-- Technic action code performing the transformation, use form handler for when not using technic
|
|
technic_run = function(pos, node)
|
|
local meta = minetest.get_meta(pos)
|
|
upgrade_machine(meta)
|
|
|
|
local demand = def.demand
|
|
if def.upgrade then
|
|
local EU_upgrade, tube_upgrade = technic.handle_machine_upgrades(meta)
|
|
if EU_upgrade and EU_upgrade > 0 then
|
|
demand = math.max(0, demand - EU_upgrade * demand * 0.2)
|
|
end
|
|
technic.handle_machine_pipeworks(pos, tube_upgrade)
|
|
end
|
|
|
|
if not technic_cnc.is_enabled(meta) or not meta:get("program") then
|
|
update_machine(pos, meta, node.name, nodename, idle_infotext, 0)
|
|
return
|
|
end
|
|
|
|
-- Get and check material stack
|
|
local inv = meta:get_inventory()
|
|
if inv:is_empty("src") then
|
|
update_machine(pos, meta, node.name, nodename, idle_infotext, 0)
|
|
return
|
|
end
|
|
|
|
local eu_input = meta:get_int("LV_EU_input")
|
|
if eu_input < demand then
|
|
update_machine(pos, meta, node.name, nodename, unpowered_infotext, demand)
|
|
return
|
|
end
|
|
|
|
local src_time = meta:get_int("src_time")
|
|
if src_time >= 3 then
|
|
-- Cycle counter expired, reset counter and attempt to produce items
|
|
if technic_cnc.produce(meta, inv) then
|
|
-- Production succeed, reset cycle counter
|
|
meta:set_int("src_time", 0)
|
|
else
|
|
-- Production failed, set machine status to unpowered and try again after one cycle
|
|
meta:set_int("src_time", 2)
|
|
update_machine(pos, meta, node.name, nodename, unpowered_infotext, 0)
|
|
return
|
|
end
|
|
else
|
|
-- Increment cycle counter
|
|
meta:set_int("src_time", src_time + 1)
|
|
end
|
|
update_machine(pos, meta, node.name, nodename_active, active_infotext, demand)
|
|
end
|
|
end
|
|
|
|
if technic_cnc.use_technic then
|
|
allow_metadata_inventory_put = technic.machine_inventory_put
|
|
allow_metadata_inventory_take = technic.machine_inventory_take
|
|
allow_metadata_inventory_move = technic.machine_inventory_move
|
|
can_dig = technic.machine_can_dig
|
|
after_dig_node = def.upgrade and technic.machine_after_dig_node or nil
|
|
else
|
|
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
|
|
if minetest.is_protected(pos, player:get_player_name()) then
|
|
return 0
|
|
end
|
|
return stack:get_count()
|
|
end
|
|
|
|
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
|
|
if minetest.is_protected(pos, player:get_player_name()) then
|
|
return 0
|
|
end
|
|
return stack:get_count()
|
|
end
|
|
|
|
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
|
|
if minetest.is_protected(pos, player:get_player_name()) then
|
|
return 0
|
|
end
|
|
return count
|
|
end
|
|
|
|
can_dig = function(pos, player)
|
|
if player and minetest.is_protected(pos, player:get_player_name()) then
|
|
return false
|
|
end
|
|
local meta = minetest.get_meta(pos)
|
|
local inv = meta:get_inventory()
|
|
return inv:is_empty("dst") and inv:is_empty("src") and default.can_interact_with_node(player, pos)
|
|
end
|
|
end
|
|
|
|
-- Formspec handlers with / without pipeworks
|
|
do
|
|
local wrapped_on_receive_fields = on_receive_fields
|
|
local function update_formspec(meta)
|
|
meta:set_string("formspec", get_formspec(nodename, def, meta))
|
|
end
|
|
if technic_cnc.pipeworks and def.tube then
|
|
local pipeworks_on_receive_fields = technic_cnc.pipeworks.on_receive_fields
|
|
on_receive_fields = function(pos, formname, fields, sender)
|
|
local meta = minetest.get_meta(pos)
|
|
if not wrapped_on_receive_fields(pos, meta, fields, sender, update_formspec) and not fields.quit then
|
|
-- Custom pipeworks form handler to skip unnecessary protection messages
|
|
pipeworks_on_receive_fields(pos, meta, fields, sender, update_formspec)
|
|
end
|
|
upgrade_machine(meta)
|
|
end
|
|
else
|
|
on_receive_fields = function(pos, formname, fields, sender)
|
|
local meta = minetest.get_meta(pos)
|
|
wrapped_on_receive_fields(pos, meta, fields, sender, update_formspec)
|
|
upgrade_machine(meta)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Groups for pipeworks
|
|
if technic_cnc.pipeworks and def.tube then
|
|
groups.tubedevice = 1
|
|
groups.tubedevice_receiver = 1
|
|
end
|
|
|
|
-- Inactive state CNC machine
|
|
minetest.register_node(":" .. nodename, {
|
|
description = def.description,
|
|
tiles = def.tiles,
|
|
groups = groups,
|
|
connect_sides = {"bottom", "back", "left", "right"},
|
|
paramtype2 = "facedir",
|
|
legacy_facedir_simple = true,
|
|
on_construct = function(pos)
|
|
local meta = minetest.get_meta(pos)
|
|
meta:set_string("infotext", def.description)
|
|
meta:set_string("formspec", get_formspec(nodename, def, meta))
|
|
local inv = meta:get_inventory()
|
|
inv:set_size("src", def.input_size)
|
|
inv:set_size("dst", def.output_size)
|
|
if def.upgrade then
|
|
inv:set_size("upgrade1", 1)
|
|
inv:set_size("upgrade2", 1)
|
|
end
|
|
end,
|
|
after_place = def.tube and pipeworks.after_place,
|
|
after_dig_node = def.after_dig_node or after_dig_node,
|
|
tube = def.tube,
|
|
digilines = def.digilines,
|
|
can_dig = def.can_dig or can_dig,
|
|
allow_metadata_inventory_put = def.allow_metadata_inventory_put or allow_metadata_inventory_put,
|
|
allow_metadata_inventory_take = def.allow_metadata_inventory_take or allow_metadata_inventory_take,
|
|
allow_metadata_inventory_move = def.allow_metadata_inventory_move or allow_metadata_inventory_move,
|
|
on_receive_fields = on_receive_fields,
|
|
technic_run = def.technic_run or technic_run,
|
|
})
|
|
|
|
-- Active state CNC machine
|
|
if technic_cnc.use_technic then
|
|
local groups_active = table.copy(groups)
|
|
groups_active.not_in_creative_inventory = 1
|
|
minetest.register_node(":" .. nodename_active, {
|
|
description = def.description,
|
|
tiles = def.tiles_active,
|
|
groups = groups_active,
|
|
connect_sides = {"bottom", "back", "left", "right"},
|
|
paramtype2 = "facedir",
|
|
drop = nodename,
|
|
legacy_facedir_simple = true,
|
|
after_dig_node = def.after_dig_node or after_dig_node,
|
|
tube = def.tube,
|
|
digilines = def.digilines,
|
|
can_dig = def.can_dig or can_dig,
|
|
allow_metadata_inventory_put = def.allow_metadata_inventory_put or allow_metadata_inventory_put,
|
|
allow_metadata_inventory_take = def.allow_metadata_inventory_take or allow_metadata_inventory_take,
|
|
allow_metadata_inventory_move = def.allow_metadata_inventory_move or allow_metadata_inventory_move,
|
|
on_receive_fields = on_receive_fields,
|
|
technic_run = def.technic_run or technic_run,
|
|
technic_disabled_machine_name = nodename,
|
|
})
|
|
technic.register_machine("LV", nodename, technic.receiver)
|
|
technic.register_machine("LV", nodename_active, technic.receiver)
|
|
else
|
|
minetest.register_alias(nodename_active, nodename)
|
|
end
|
|
end
|