minetest-mm/mods/facade/shaper.lua
2020-11-15 20:25:38 +01:00

370 lines
10 KiB
Lua

-- Facade Shaper
-- This machine serves the same purpose as the circular saw from moreblocks or the milling
-- maching from mymillwork. Namely, it provides a tool for creating shaped blocks that does
-- not rely on using recipes.
-- Balancing output per 1 input block with respect to apparent volume of output shape.
-- All current shapes are added, but shapes not present in this table will still be produced
-- one at a time — if that is the desired quantity, adding them is not required.
local output_ratios = {
bannerstone = 1,
bannerstone_corner = 1,
centerstone = 1,
column = 1,
column_corner = 1,
corbel = 1,
corbel_corner = 1,
corbel_corner_inner = 1,
carved_stone_a = 1,
carved_stone_a_corner = 1,
rgspro = 2,
rgspro_inner_corner = 1,
rgspro_outer_corner = 1,
corner_bricks = 2,
columnia_mid = 4,
columnia_bottom = 1,
columnia_top = 1,
columnia_crosslink = 1,
columnia_link = 4,
columnia_linkdown = 4,
}
-- The material to be used for buttons when no material is actually loaded.
-- It should be a generic material for which all the facade shapes are defined.
local demo_material = "default:stone"
-- Whether the facade should obey area protection for the inventories (as machines in technic mod)
-- or allow anybody to use them, but disallow the removal of machine itself (like circular saw in moreblocks)
local protect_inventories = false
local function prepare_formspec (material_name)
local output = string.gsub(material_name, "^.*:", "facade:")
local shaper_formspec =
"size[8,11;]"..
"label[0,0;" .. "Choose shape to produce:" .. "]"..
-- row 1, blocky shapes
"item_image_button[0,0.5;1,1;" .. output .. "_bannerstone" .. ";bannerstone; ]"..
"item_image_button[1,0.5;1,1;" .. output .. "_bannerstone_corner" .. ";bannerstone_corner; ]"..
"item_image_button[2,0.5;1,1;" .. output .. "_centerstone" .. ";centerstone; ]"..
"item_image_button[3,0.5;1,1;" .. output .. "_carved_stone_a" .. ";carved_stone_a; ]"..
"item_image_button[4,0.5;1,1;" .. output .. "_carved_stone_a_corner" .. ";carved_stone_a_corner; ]"..
"item_image_button[5,0.5;1,1;" .. output .. "_column" .. ";column; ]"..
"item_image_button[6,0.5;1,1;" .. output .. "_column_corner" .. ";column_corner; ]"..
-- row 2, corbel
"item_image_button[0,1.5;1,1;" .. output .. "_corbel" .. ";corbel; ]"..
"item_image_button[1,1.5;1,1;" .. output .. "_corbel_corner_inner" .. ";corbel_corner_inner; ]"..
"item_image_button[2,1.5;1,1;" .. output .. "_corbel_corner" .. ";corbel_corner; ]"..
-- row 3, cornice
"item_image_button[0,2.5;1,1;" .. output .. "_rgspro" .. ";rgspro; ]"..
"item_image_button[1,2.5;1,1;" .. output .. "_rgspro_inner_corner" .. ";rgspro_inner_corner; ]"..
"item_image_button[2,2.5;1,1;" .. output .. "_rgspro_outer_corner" .. ";rgspro_outer_corner; ]"
-- row 4, columnia
if not minetest.get_modpath("columnia") then
shaper_formspec = shaper_formspec ..
"item_image_button[0,3.5;1,1;" .. output .. "_columnia_mid" .. ";columnia_mid; ]"..
"item_image_button[1,3.5;1,1;" .. output .. "_columnia_bottom" .. ";columnia_bottom; ]"..
"item_image_button[2,3.5;1,1;" .. output .. "_columnia_crosslink" .. ";columnia_crosslink; ]"..
"item_image_button[3,3.5;1,1;" .. output .. "_columnia_link" .. ";columnia_link; ]"..
"item_image_button[4,3.5;1,1;" .. output .. "_columnia_linkdown" .. ";columnia_linkdown; ]"
-- this code is a provision in case top column pieces enter service
if minetest.registered_nodes[output .. "_columnia_top"] then
shaper_formspec = shaper_formspec ..
"item_image_button[5,3.5;1,1;" .. output .. "_columnia_top" .. ";columnia_top; ]"
end
end
-- row 5 for shapes which are not available for all materials
-- only one such shape exists so far, but more should be easy to add here
if minetest.registered_nodes[output .. "_corner_bricks"] then
shaper_formspec = shaper_formspec ..
"item_image_button[0,4.5;1,1;" .. output .. "_corner_bricks" .. ";corner_bricks; ]"
end
-- inventory part
shaper_formspec = shaper_formspec ..
"label[0, 5.5;".."In:".."]"..
"list[current_name;src;1,5.5;1,1;]"..
"label[3, 5.5;".."Out:".."]"..
"list[current_name;dst;4,5.5;4,1;]"..
"list[current_player;main;0,7;8,4;]"..
"listring[current_name;dst]"..
"listring[current_player;main]"..
"listring[current_name;src]"..
"listring[current_player;main]"
return(shaper_formspec)
end
-- a simple check for compatibile materials
local function check_material_applicability (material)
-- using centerstone node here, since it appears to be both one of the oldest
-- and defined for all materials as well, making it suitable for a quick check
if minetest.registered_nodes[string.gsub(material, "^.*:", "facade:") .. "_centerstone"] then
return true
else
return false
end
end
-- update the buttons to show shapes made from the actual material
local function update_formspec_put (pos, listname, index, stack, player)
if protect_inventories and minetest.is_protected(pos, player:get_player_name()) then
return
end
if listname ~= "src" then
return
end
local meta = minetest.get_meta(pos)
local material_name = stack:get_name()
if check_material_applicability(material_name) then
meta:set_string("formspec", prepare_formspec(material_name))
else
return
end
end
-- update the buttons to show shapes made from demo material if all material is removed
local function update_formspec_take (pos, listname, index, stack, player)
if protect_inventories and minetest.is_protected(pos, player:get_player_name()) then
return
end
if listname ~= "src" then
return
end
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
if inv:is_empty("src") then
meta:set_string("formspec", prepare_formspec(demo_material))
end
return
end
-- disallow putting in materials which are not supported
local function check_inventory_put (pos, listname, index, stack, player)
if protect_inventories and minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if listname ~= "src" then
return 0
end
local material_name = stack:get_name()
if check_material_applicability(material_name) then
return(stack:get_count())
else
return 0
end
end
local function check_inventory_take (pos, listname, index, stack, player)
if protect_inventories and minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if listname ~= "src" and listname ~= "dst" then
return 0
end
return(stack:get_count())
end
local function check_inventory_move (pos, from_list, from_index, to_list, to_index, count, player)
if protect_inventories and minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return(stack:get_count())
end
-- process the form fields and convert source material to desired shapes
local function form_handler(pos, formname, fields, sender)
if protect_inventories and minetest.is_protected(pos, sender:get_player_name()) then
return
end
if fields.quit then
return
end
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
if inv:is_empty("src") then
return
end
local inputstack = inv:get_stack("src", 1)
local inputname = inputstack:get_name()
for shape,_ in pairs(fields) do
local result = string.gsub(inputname, "^.*:", "facade:") .. "_" .. shape
-- one can never be overly paranoid, unlike the quick check before, this one is precise
if not minetest.registered_nodes[result] then
return
end
-- output quantities are adjusted to preserve roughly same mass of resulting products
if output_ratios[shape] then
result = result .. " " .. output_ratios[shape]
end
if not inv:room_for_item("dst", result) then
return
end
inputstack:take_item(1)
inv:set_stack("src", 1, inputstack)
inv:add_item("dst", result)
end
return
end
local function check_removability (pos, player)
local meta = minetest.get_meta(pos)
local owner = meta:set_string("owner")
local pname = player:get_player_name()
local inv = meta:get_inventory()
-- owner may always remove the device
if owner and owner ~= "" and pname and pname ~= "" and owner == pname then
if inv:is_empty("src") and inv:is_empty("dst") then
return true
else
return false
end
end
if minetest.is_protected(pos, player:get_player_name()) then
return false
end
if inv:is_empty("src") and inv:is_empty("dst") then
return true
end
return false
end
minetest.register_node("facade:shaper", {
description = "Shaper Machine",
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
-- base
{-1/2, -1/2, -1/2, 1/2, -14/32, 1/2},
-- back
{-8/32, -1/2, 12/32, 8/32, 1/2, 16/32},
-- table
{-8/32, -4/32, -16/32, 8/32, 4/32, 16/32},
-- rear table sliding support
{-16/32, -4/32, 12/32, 16/32, 4/32, 16/32},
-- front table sliding support
{-8/32, -14/32, -12/32, 8/32, -4/32, -16/32},
-- top tool beam
{-4/32, 16/32, -8/32, 4/32, 12/32, 12/32},
-- cutter holder
{-2/32, 7/32, -2/32, 2/32, 14/32, 2/32},
-- cutter
{-1/128, 6/32, -1/32, 1/128, 7/32, 1/32},
},
},
selection_box = {
type = "fixed",
fixed = {
{-1/2, -1/2, -1/2, 1/2, 1/2, 1/2},
},
},
tiles = { "facade_shaper_top.png",
"facade_shaper_bottom.png",
"facade_shaper_right.png",
"facade_shaper_left.png",
"facade_shaper_back.png",
"facade_shaper_front.png"},
groups = { oddly_breakable_by_hand=2, cracky=3, dig_immediate=1 },
paramtype = "light",
paramtype2 = "facedir",
legacy_facedir_simple = true,
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("formspec", prepare_formspec(demo_material))
local inv = meta:get_inventory()
inv:set_size("src", 1)
inv:set_size("dst", 4)
end,
after_place_node = function(pos, placer)
local meta = minetest.get_meta(pos)
local owner = placer and placer:get_player_name() or ""
meta:set_string("owner", owner)
if owner then
meta:set_string("infotext", ("Facade Shaper (owned by %s)"):format(owner))
else
meta:set_string("infotext", "Facade Shaper")
end
end,
can_dig = check_removability,
allow_metadata_inventory_put = check_inventory_put,
allow_metadata_inventory_take = check_inventory_take,
allow_metadata_inventory_move = check_inventory_move,
on_metadata_inventory_put = update_formspec_put,
on_metadata_inventory_take = update_formspec_take,
on_receive_fields = form_handler,
})
minetest.register_craft({
output = 'facade:shaper',
recipe = {
{'', 'default:diamond', '' },
{'default:steel_ingot', 'default:steelblock', 'default:steel_ingot' },
{'', 'default:steelblock' , '' },
},
})