code:
-- Sticky blocks can be used together with pistons or movestones to push / pull
-- structures that are "glued" together using sticky blocks

-- All sides sticky block
minetest.register_node("mesecons_stickyblocks:sticky_block_all", {
	-- TODO: Rename to “All-Faces Sticky Block” when other sticky blocks become available
	description = "Sticky Block",
	tiles = {"mesecons_stickyblocks_sticky.png"},
	is_ground_content = false,
	groups = {choppy=3, oddly_breakable_by_hand=2},
	mvps_sticky = function (pos)
		local connected = {}
		for _, r in ipairs(mesecon.rules.alldirs) do
			table.insert(connected, vector.add(pos, r))
		end
		return connected
	end,
	sounds = mesecon.node_sound.wood,
})


code:
name = mesecons_stickyblocks
depends = mesecons, mesecons_gamecompat, mesecons_mvps

repo_name: korkut/MeseCraft

license: mit


code: The switch is a receptor. It changes its state when punched.


code:
-- mesecons_switch

mesecon.register_node("mesecons_switch:mesecon_switch", {
	paramtype2="facedir",
	description="Switch",
	is_ground_content = false,
	sounds = mesecon.node_sound.stone,
	on_rightclick = function (pos, node)
		if(mesecon.flipstate(pos, node) == "on") then
			mesecon.receptor_on(pos)
		else
			mesecon.receptor_off(pos)
		end
		minetest.sound_play("mesecons_switch", { pos = pos }, true)
	end
},{
	groups = {dig_immediate=2},
	tiles = {	"mesecons_switch_side.png", "mesecons_switch_side.png",
				"mesecons_switch_side.png", "mesecons_switch_side.png",
				"mesecons_switch_side.png", "mesecons_switch_off.png"},
	mesecons = {receptor = { state = mesecon.state.off }}
},{
	groups = {dig_immediate=2, not_in_creative_inventory=1},
	tiles = {	"mesecons_switch_side.png", "mesecons_switch_side.png",
				"mesecons_switch_side.png", "mesecons_switch_side.png",
				"mesecons_switch_side.png", "mesecons_switch_on.png"},
	mesecons = {receptor = { state = mesecon.state.on }}
})

minetest.register_craft({
	output = "mesecons_switch:mesecon_switch_off 2",
	recipe = {
		{"mesecons_gamecompat:steel_ingot", "mesecons_gamecompat:cobble", "mesecons_gamecompat:steel_ingot"},
		{"group:mesecon_conductor_craftable","", "group:mesecon_conductor_craftable"},
	}
})


code:
name = mesecons_switch
depends = mesecons, mesecons_gamecompat


code:
The torch is an inverter, it may take up to 1 second until the signal has passed through. The input is 2 blocks away in the direction of the stick, outputs are around the mesecon glow.
It doesn't work in an inactive block; it just retains its state until the block becomes active.


code:
--MESECON TORCHES

local rotate_torch_rules = function (rules, param2)
	if param2 == 5 then
		return mesecon.rotate_rules_right(rules)
	elseif param2 == 2 then
		return mesecon.rotate_rules_right(mesecon.rotate_rules_right(rules)) --180 degrees
	elseif param2 == 4 then
		return mesecon.rotate_rules_left(rules)
	elseif param2 == 1 then
		return mesecon.rotate_rules_down(rules)
	elseif param2 == 0 then
		return mesecon.rotate_rules_up(rules)
	else
		return rules
	end
end

local torch_get_output_rules = function(node)
	local rules = {
		{x = 1,  y = 0, z = 0},
		{x = 0,  y = 0, z = 1},
		{x = 0,  y = 0, z =-1},
		{x = 0,  y = 1, z = 0},
		{x = 0,  y =-1, z = 0}}

	return rotate_torch_rules(rules, node.param2)
end

local torch_input_rules_unrotated_horizontal = {vector.new(-2, 0, 0), vector.new(-1, 1, 0)}
local torch_input_rules_unrotated_vertical   = {vector.new(-2, 0, 0)}

local torch_get_input_rules = function(node)
	local rules = (node.param2 == 0 or node.param2 == 1)
		and torch_input_rules_unrotated_vertical
		or  torch_input_rules_unrotated_horizontal

	return rotate_torch_rules(rules, node.param2)
end

minetest.register_craft({
	output = "mesecons_torch:mesecon_torch_on 4",
	recipe = {
	{"group:mesecon_conductor_craftable"},
	{"group:stick"},}
})

local torch_selectionbox =
{
	type = "wallmounted",
	wall_top = {-0.1, 0.5-0.6, -0.1, 0.1, 0.5, 0.1},
	wall_bottom = {-0.1, -0.5, -0.1, 0.1, -0.5+0.6, 0.1},
	wall_side = {-0.5, -0.1, -0.1, -0.5+0.6, 0.1, 0.1},
}

minetest.register_node("mesecons_torch:mesecon_torch_off", {
	drawtype = "torchlike",
	tiles = {"jeija_torches_off.png", "jeija_torches_off_ceiling.png", "jeija_torches_off_side.png"},
	inventory_image = "jeija_torches_off.png",
	paramtype = "light",
	is_ground_content = false,
	walkable = false,
	paramtype2 = "wallmounted",
	selection_box = torch_selectionbox,
	groups = {dig_immediate = 3, not_in_creative_inventory = 1},
	drop = "mesecons_torch:mesecon_torch_on",
	sounds = mesecon.node_sound.default,
	mesecons = {receptor = {
		state = mesecon.state.off,
		rules = torch_get_output_rules
	}},
	on_blast = mesecon.on_blastnode,
})

minetest.register_node("mesecons_torch:mesecon_torch_on", {
	drawtype = "torchlike",
	tiles = {"jeija_torches_on.png", "jeija_torches_on_ceiling.png", "jeija_torches_on_side.png"},
	inventory_image = "jeija_torches_on.png",
	wield_image = "jeija_torches_on.png",
	paramtype = "light",
	is_ground_content = false,
	sunlight_propagates = true,
	walkable = false,
	paramtype2 = "wallmounted",
	selection_box = torch_selectionbox,
	groups = {dig_immediate=3},
	light_source = minetest.LIGHT_MAX-5,
	description="Mesecon Torch",
	sounds = mesecon.node_sound.default,
	mesecons = {receptor = {
		state = mesecon.state.on,
		rules = torch_get_output_rules
	}},
	on_blast = mesecon.on_blastnode,
})

minetest.register_abm({
	nodenames = {"mesecons_torch:mesecon_torch_off","mesecons_torch:mesecon_torch_on"},
	interval = 1,
	chance = 1,
	action = function(pos, node)
		local is_powered = false
		for _, rule in ipairs(torch_get_input_rules(node)) do
			local src = vector.add(pos, rule)
			if mesecon.is_power_on(src) then
				is_powered = true
			end
		end

		if is_powered then
			if node.name == "mesecons_torch:mesecon_torch_on" then
				minetest.swap_node(pos, {name = "mesecons_torch:mesecon_torch_off", param2 = node.param2})
				mesecon.receptor_off(pos, torch_get_output_rules(node))
			end
		elseif node.name == "mesecons_torch:mesecon_torch_off" then
			minetest.swap_node(pos, {name = "mesecons_torch:mesecon_torch_on", param2 = node.param2})
			mesecon.receptor_on(pos, torch_get_output_rules(node))
		end
	end
})

-- Param2 Table (Block Attached To)
-- 5 = z-1
-- 3 = x-1
-- 4 = z+1
-- 2 = x+1
-- 0 = y+1
-- 1 = y-1


code:
name = mesecons_torch
depends = mesecons, mesecons_gamecompat


code: A receptor just like a switch, but it can be attached to walls.


code:
-- WALL LEVER
-- Basically a switch that can be attached to a wall
-- Powers the block 2 nodes behind (using a receiver)
mesecon.register_node("mesecons_walllever:wall_lever", {
	description="Lever",
	drawtype = "mesh",
	inventory_image = "jeija_wall_lever_inv.png",
	wield_image = "jeija_wall_lever_inv.png",
	paramtype = "light",
	paramtype2 = "facedir",
	is_ground_content = false,
	sunlight_propagates = true,
	walkable = false,
	selection_box = {
		type = "fixed",
		fixed = { -8/16, -8/16, 3/16, 8/16, 8/16, 8/16 },
	},
	sounds = mesecon.node_sound.wood,
	on_rightclick = function (pos, node)
		if(mesecon.flipstate(pos, node) == "on") then
			mesecon.receptor_on(pos, mesecon.rules.buttonlike_get(node))
		else
			mesecon.receptor_off(pos, mesecon.rules.buttonlike_get(node))
		end
		minetest.sound_play("mesecons_lever", { pos = pos }, true)
	end
},{
	tiles = {
		"jeija_wall_lever_lever_light_off.png",
		"jeija_wall_lever_front.png",
		"jeija_wall_lever_front_bump.png",
		"jeija_wall_lever_back_edges.png"
	},
	mesh="jeija_wall_lever_off.obj",
	on_rotate = mesecon.buttonlike_onrotate,
	mesecons = {receptor = {
		rules = mesecon.rules.buttonlike_get,
		state = mesecon.state.off
	}},
	groups = {dig_immediate = 2, mesecon_needs_receiver = 1}
},{
	tiles = {
		"jeija_wall_lever_lever_light_on.png",
		"jeija_wall_lever_front.png",
		"jeija_wall_lever_front_bump.png",
		"jeija_wall_lever_back_edges.png"
	},
	mesh="jeija_wall_lever_on.obj",
	on_rotate = false,
	mesecons = {receptor = {
		rules = mesecon.rules.buttonlike_get,
		state = mesecon.state.on
	}},
	groups = {dig_immediate = 2, mesecon_needs_receiver = 1, not_in_creative_inventory = 1}
})

minetest.register_craft({
	output = "mesecons_walllever:wall_lever_off 2",
	recipe = {
	    {"group:mesecon_conductor_craftable"},
		{"mesecons_gamecompat:stone"},
		{"group:stick"},
	}
})


code:
name = mesecons_walllever
depends = mesecons, mesecons_gamecompat, mesecons_receiver


code: Mesecons are the wires, use them to connect effectors with receptors. Wiring works through unloaded blocks; they’re loaded when the signal level changes.


code:
-- naming scheme: wire:(xp)(zp)(xm)(zm)(xpyp)(zpyp)(xmyp)(zmyp)_on/off
-- where x= x direction, z= z direction, y= y direction, p = +1, m = -1, e.g. xpym = {x=1, y=-1, z=0}
-- The (xp)/(zpyp)/.. statements shall be replaced by either 0 or 1
-- Where 0 means the wire has no visual connection to that direction and
-- 1 means that the wire visually connects to that other node.

-- #######################
-- ## Update wire looks ##
-- #######################

-- self_pos = pos of any mesecon node, from_pos = pos of conductor to getconnect for
local wire_getconnect = function (from_pos, self_pos)
	local node = minetest.get_node(self_pos)
	if minetest.registered_nodes[node.name]
	and minetest.registered_nodes[node.name].mesecons then
		-- rules of node to possibly connect to
		local rules
		if (minetest.registered_nodes[node.name].mesecon_wire) then
			rules = mesecon.rules.default
		else
			rules = mesecon.get_any_rules(node)
		end

		for _, r in ipairs(mesecon.flattenrules(rules)) do
			if (vector.equals(vector.add(self_pos, r), from_pos)) then
				return true
			end
		end
	end
	return false
end

-- Update this node
local wire_updateconnect = function (pos)
	local connections = {}

	for _, r in ipairs(mesecon.rules.default) do
		if wire_getconnect(pos, vector.add(pos, r)) then
			table.insert(connections, r)
		end
	end

	local nid = {}
	for _, vec in ipairs(connections) do
		-- flat component
		if vec.x ==  1 then nid[0] = "1" end
		if vec.z ==  1 then nid[1] = "1" end
		if vec.x == -1 then nid[2] = "1" end
		if vec.z == -1 then nid[3] = "1"  end

		-- slopy component
		if vec.y == 1 then
			if vec.x ==  1 then nid[4] = "1" end
			if vec.z ==  1 then nid[5] = "1" end
			if vec.x == -1 then nid[6] = "1" end
			if vec.z == -1 then nid[7] = "1" end
		end
	end

	local nodeid = 	  (nid[0] or "0")..(nid[1] or "0")..(nid[2] or "0")..(nid[3] or "0")
			..(nid[4] or "0")..(nid[5] or "0")..(nid[6] or "0")..(nid[7] or "0")

	local state_suffix = string.find(minetest.get_node(pos).name, "_off") and "_off" or "_on"
	minetest.set_node(pos, {name = "mesecons:wire_"..nodeid..state_suffix})
end

local update_on_place_dig = function (pos, node)
	-- Update placed node (get_node again as it may have been dug)
	local nn = minetest.get_node(pos)
	if (minetest.registered_nodes[nn.name])
	and (minetest.registered_nodes[nn.name].mesecon_wire) then
		wire_updateconnect(pos)
	end

	-- Update nodes around it
	local rules
	if minetest.registered_nodes[node.name]
	and minetest.registered_nodes[node.name].mesecon_wire then
		rules = mesecon.rules.default
	else
		rules = mesecon.get_any_rules(node)
	end
	if (not rules) then return end

	for _, r in ipairs(mesecon.flattenrules(rules)) do
		local np = vector.add(pos, r)
		if minetest.registered_nodes[minetest.get_node(np).name]
		and minetest.registered_nodes[minetest.get_node(np).name].mesecon_wire then
			wire_updateconnect(np)
		end
	end
end

mesecon.register_autoconnect_hook("wire", update_on_place_dig)

-- ############################
-- ## Wire node registration ##
-- ############################
-- Nodeboxes:
local box_center = {-1/16, -.5, -1/16, 1/16, -.5+1/16, 1/16}
local box_bump1 =  { -2/16, -8/16,  -2/16, 2/16, -13/32, 2/16 }

local nbox_nid =
{
	[0] = {1/16, -.5, -1/16, 8/16, -.5+1/16, 1/16}, -- x positive
	[1] = {-1/16, -.5, 1/16, 1/16, -.5+1/16, 8/16}, -- z positive
	[2] = {-8/16, -.5, -1/16, -1/16, -.5+1/16, 1/16}, -- x negative
	[3] = {-1/16, -.5, -8/16, 1/16, -.5+1/16, -1/16}, -- z negative

	[4] = {.5-1/16, -.5+1/16, -1/16, .5, .4999+1/16, 1/16}, -- x positive up
	[5] = {-1/16, -.5+1/16, .5-1/16, 1/16, .4999+1/16, .5}, -- z positive up
	[6] = {-.5, -.5+1/16, -1/16, -.5+1/16, .4999+1/16, 1/16}, -- x negative up
	[7] = {-1/16, -.5+1/16, -.5, 1/16, .4999+1/16, -.5+1/16}  -- z negative up
}

local tiles_off = { "mesecons_wire_off.png" }
local tiles_on = { "mesecons_wire_on.png" }

local selectionbox =
{
	type = "fixed",
	fixed = {-.5, -.5, -.5, .5, -.5+4/16, .5}
}

-- go to the next nodeid (ex.: 01000011 --> 01000100)
local nid_inc = function() end
nid_inc = function (nid)
	local i = 0
	while nid[i-1] ~= 1 do
		nid[i] = (nid[i] ~= 1) and 1 or 0
		i = i + 1
	end

	-- BUT: Skip impossible nodeids:
	if ((nid[0] == 0 and nid[4] == 1) or (nid[1] == 0 and nid[5] == 1)
	or (nid[2] == 0 and nid[6] == 1) or (nid[3] == 0 and nid[7] == 1)) then
		return nid_inc(nid)
	end

	return i <= 8
end

local function register_wires()
	local nid = {}
	while true do
		-- Create group specifiction and nodeid string (see note above for details)
		local nodeid = 	  (nid[0] or "0")..(nid[1] or "0")..(nid[2] or "0")..(nid[3] or "0")
				..(nid[4] or "0")..(nid[5] or "0")..(nid[6] or "0")..(nid[7] or "0")

		-- Calculate nodebox
		local nodebox = {type = "fixed", fixed={box_center}}
		for i=0,7 do
			if nid[i] == 1 then
				table.insert(nodebox.fixed, nbox_nid[i])
			end
		end

		-- Add bump to nodebox if curved
		if (nid[0] == 1 and nid[1] == 1) or (nid[1] == 1 and nid[2] == 1)
		or (nid[2] == 1 and nid[3] == 1) or (nid[3] == 1 and nid[0] == 1) then
			table.insert(nodebox.fixed, box_bump1)
		end

		-- If nothing to connect to, still make a nodebox of a straight wire
		if nodeid == "00000000" then
			nodebox.fixed = {-8/16, -.5, -1/16, 8/16, -.5+1/16, 1/16}
		end

		local rules = {}
		if (nid[0] == 1) then table.insert(rules, vector.new( 1,  0,  0)) end
		if (nid[1] == 1) then table.insert(rules, vector.new( 0,  0,  1)) end
		if (nid[2] == 1) then table.insert(rules, vector.new(-1,  0,  0)) end
		if (nid[3] == 1) then table.insert(rules, vector.new( 0,  0, -1)) end

		if (nid[0] == 1) then table.insert(rules, vector.new( 1, -1,  0)) end
		if (nid[1] == 1) then table.insert(rules, vector.new( 0, -1,  1)) end
		if (nid[2] == 1) then table.insert(rules, vector.new(-1, -1,  0)) end
		if (nid[3] == 1) then table.insert(rules, vector.new( 0, -1, -1)) end

		if (nid[4] == 1) then table.insert(rules, vector.new( 1,  1,  0)) end
		if (nid[5] == 1) then table.insert(rules, vector.new( 0,  1,  1)) end
		if (nid[6] == 1) then table.insert(rules, vector.new(-1,  1,  0)) end
		if (nid[7] == 1) then table.insert(rules, vector.new( 0,  1, -1)) end

		local meseconspec_off = { conductor = {
			rules = rules,
			state = mesecon.state.off,
			onstate = "mesecons:wire_"..nodeid.."_on"
		}}

		local meseconspec_on = { conductor = {
			rules = rules,
			state = mesecon.state.on,
			offstate = "mesecons:wire_"..nodeid.."_off"
		}}

		local groups_on = {dig_immediate = 3, mesecon_conductor_craftable = 1,
			not_in_creative_inventory = 1, not_in_craft_guide = 1}
		local groups_off = {dig_immediate = 3, mesecon_conductor_craftable = 1}
		if nodeid ~= "00000000" then
			groups_off["not_in_creative_inventory"] = 1
			groups_off["not_in_craft_guide"] = 1
		end

		mesecon.register_node(":mesecons:wire_"..nodeid, {
			description = "Mesecon",
			drawtype = "nodebox",
			inventory_image = "mesecons_wire_inv.png",
			wield_image = "mesecons_wire_inv.png",
			paramtype = "light",
			paramtype2 = "facedir",
			is_ground_content = false,
			sunlight_propagates = true,
			selection_box = selectionbox,
			node_box = nodebox,
			walkable = false,
			drop = "mesecons:wire_00000000_off",
			mesecon_wire = true,
			sounds = mesecon.node_sound.default,
			on_rotate = false,
		}, {tiles = tiles_off, mesecons = meseconspec_off, groups = groups_off},
		{tiles = tiles_on, mesecons = meseconspec_on, groups = groups_on})

		if (nid_inc(nid) == false) then return end
	end
end
register_wires()

-- ##############
-- ## Crafting ##
-- ##############
-- (Resolve aliases to avoid bug with cooking/fuel recipes.)

if minetest.registered_aliases["mesecons_gamecompat:mese_crystal_fragment"] then
	minetest.register_craft({
		type = "cooking",
		output = "mesecons:wire_00000000_off 2",
		recipe = minetest.registered_aliases["mesecons_gamecompat:mese_crystal_fragment"],
		cooktime = 3,
	})
end

if minetest.registered_aliases["mesecons_gamecompat:mese_crystal"] then
	minetest.register_craft({
		type = "cooking",
		output = "mesecons:wire_00000000_off 18",
		recipe = minetest.registered_aliases["mesecons_gamecompat:mese_crystal"],
		cooktime = 15,
	})
end

if minetest.registered_aliases["mesecons_gamecompat:mese"] then
	minetest.register_craft({
		type = "cooking",
		output = "mesecons:wire_00000000_off 162",
		recipe = minetest.registered_aliases["mesecons_gamecompat:mese"],
		cooktime = 30,
	})
end


code:
name = mesecons_wires
depends = mesecons, mesecons_gamecompat


code:
[mesecons]

mesecon.resumetime (Startup delay) int 4 1 10
mesecon.overheat_max (Device heat limit) int 20 1 100
mesecon.cooldown_time (Device cooldown time) float 2.0 0.1 10.0
mesecon.cooldown_granularity (Cooldown step length) float 0.5 0.0 1.0

[mesecons_blinkyplant]

mesecon.blinky_plant_interval (Plant blinking interval) int 3 1 5

[mesecons_detector]

mesecon.detector_radius (Player detector scanning radius) int 6 3 16
mesecon.node_detector_distance_max (Node detector distance limit) int 10 1 16

[mesecons_luacontroller]

mesecon.luacontroller_string_rep_max (string:rep result length limit) int 64000 1000 1000000
mesecon.luacontroller_digiline_maxlen (Digiline message size limit) int 50000 1000 1000000
mesecon.luacontroller_maxevents (Controller execution time limit) int 10000 1000 100000
mesecon.luacontroller_memsize (Controller memory limit) int 100000 10000 1000000

# Use node timer for interrupts (runs in active blocks only).
# IID is ignored and at most one interrupt may be queued if this setting is enabled.
mesecon.luacontroller_lightweight_interrupts (Lightweight interrupts) bool false

[mesecons_mvps]

# In pre-existing world, MVPS may not be labelled with the owner.
# Protection handling for them is configurable.
# - normal: allow legacy MVPS to work in unprotected areas only
# - compat: allow legacy MVPS to work everywhere
# - ignore: allow all MVPS to work everywhere
# - restrict: disallow legacy MVPS
# Note that new unowned (e.g. machine-placed) MVPS are always
# handled as in `normal` mode.
mesecon.mvps_protection_mode (MVPS [movestones, pistons] protection handling) enum compat normal,compat,ignore,restrict

[mesecons_movestones]

mesecon.movestone_speed (Speed) int 3 1 10
mesecon.movestone_max_push (Max push) int 50 1 100
mesecon.movestone_max_pull (Max pull) int 50 1 100

[mesecons_pistons]

mesecon.piston_max_push (Max push) int 15 1 100
mesecon.piston_max_pull (Max pull) int 15 1 100

[mesecons_pressureplates]

mesecon.pplate_interval (Check interval) float 0.1 0.1 1.0


code:
MeseCraft Game mod: beds
=======================
See license.txt for license information.

This is a modified version of beds for MeseCraft that dumps the fancy_bed and includes colored versions of the simple bed. Also merges the featuers of bouncy_bed into the mod. Source and functions are based on the mtg beds mod. The colored beds nodes are based on colored beds by Napiophelios which is under MIT license.

Authors of source code
----------------------
Originally by BlockMen (MIT)
Various Minetest developers and contributors (MIT)

Authors of media (textures)
---------------------------
BlockMen (CC BY-SA 3.0)
 All textures unless otherwise noted

TumeniNodes (CC BY-SA 3.0)
 beds_bed_under.png

This mod adds a bed to Minetest which allows players to skip the night.
To sleep, right click on the bed. If playing in singleplayer mode the night gets skipped
immediately. If playing multiplayer you get shown how many other players are in bed too,
if all players are sleeping the night gets skipped. The night skip can be forced if more
than half of the players are lying in bed and use this option.

Another feature is a controlled respawning. If you have slept in bed (not just lying in
it) your respawn point is set to the beds location and you will respawn there after
death.
You can disable the respawn at beds by setting "enable_bed_respawn = false" in
minetest.conf.
You can disable the night skip feature by setting "enable_bed_night_skip = false" in
minetest.conf or by using the /set command in-game.


code:
local reverse = true

local function destruct_bed(pos, n)
	local node = minetest.get_node(pos)
	local other

	if n == 2 then
		local dir = minetest.facedir_to_dir(node.param2)
		other = vector.subtract(pos, dir)
	elseif n == 1 then
		local dir = minetest.facedir_to_dir(node.param2)
		other = vector.add(pos, dir)
	end

	if reverse then
		reverse = not reverse
		minetest.remove_node(other)
		minetest.check_for_falling(other)
		beds.remove_spawns_at(pos)
		beds.remove_spawns_at(other)
	else
		reverse = not reverse
	end
end

function beds.register_bed(name, def)
	minetest.register_node(name .. "_bottom", {
		description = def.description,
		inventory_image = def.inventory_image,
		wield_image = def.wield_image,
		drawtype = "nodebox",
		tiles = def.tiles.bottom,
		paramtype = "light",
		paramtype2 = "facedir",
		is_ground_content = false,
		stack_max = 1,
		groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 3, bed = 1},
		sounds = def.sounds or default.node_sound_wood_defaults(),
		node_box = {
			type = "fixed",
			fixed = def.nodebox.bottom,
		},
		selection_box = {
			type = "fixed",
			fixed = def.selectionbox,
		},

		on_place = function(itemstack, placer, pointed_thing)
			local under = pointed_thing.under
			local node = minetest.get_node(under)
			local udef = minetest.registered_nodes[node.name]
			if udef and udef.on_rightclick and
					not (placer and placer:is_player() and
					placer:get_player_control().sneak) then
				return udef.on_rightclick(under, node, placer, itemstack,
					pointed_thing) or itemstack
			end

			local pos
			if udef and udef.buildable_to then
				pos = under
			else
				pos = pointed_thing.above
			end

			local player_name = placer and placer:get_player_name() or ""

			if minetest.is_protected(pos, player_name) and
					not minetest.check_player_privs(player_name, "protection_bypass") then
				minetest.record_protection_violation(pos, player_name)
				return itemstack
			end

			local node_def = minetest.registered_nodes[minetest.get_node(pos).name]
			if not node_def or not node_def.buildable_to then
				return itemstack
			end

			local dir = placer and placer:get_look_dir() and
				minetest.dir_to_facedir(placer:get_look_dir()) or 0
			local botpos = vector.add(pos, minetest.facedir_to_dir(dir))

			if minetest.is_protected(botpos, player_name) and
					not minetest.check_player_privs(player_name, "protection_bypass") then
				minetest.record_protection_violation(botpos, player_name)
				return itemstack
			end

			local botdef = minetest.registered_nodes[minetest.get_node(botpos).name]
			if not botdef or not botdef.buildable_to then
				return itemstack
			end

			minetest.set_node(pos, {name = name .. "_bottom", param2 = dir})
			minetest.set_node(botpos, {name = name .. "_top", param2 = dir})

			if not (creative and creative.is_enabled_for
					and creative.is_enabled_for(player_name)) then
				itemstack:take_item()
			end
			return itemstack
		end,

		on_destruct = function(pos)
			destruct_bed(pos, 1)
		end,

		on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
			beds.on_rightclick(pos, clicker)
			return itemstack
		end,

		on_rotate = function(pos, node, user, _, new_param2)
			local dir = minetest.facedir_to_dir(node.param2)
			local p = vector.add(pos, dir)
			local node2 = minetest.get_node_or_nil(p)
			if not node2 or not minetest.get_item_group(node2.name, "bed") == 2 or
					not node.param2 == node2.param2 then
				return false
			end
			if minetest.is_protected(p, user:get_player_name()) then
				minetest.record_protection_violation(p, user:get_player_name())
				return false
			end
			if new_param2 % 32 > 3 then
				return false
			end
			local newp = vector.add(pos, minetest.facedir_to_dir(new_param2))
			local node3 = minetest.get_node_or_nil(newp)
			local node_def = node3 and minetest.registered_nodes[node3.name]
			if not node_def or not node_def.buildable_to then
				return false
			end
			if minetest.is_protected(newp, user:get_player_name()) then
				minetest.record_protection_violation(newp, user:get_player_name())
				return false
			end
			node.param2 = new_param2
			-- do not remove_node here - it will trigger destroy_bed()
			minetest.set_node(p, {name = "air"})
			minetest.set_node(pos, node)
			minetest.set_node(newp, {name = name .. "_top", param2 = new_param2})
			return true
		end,
		can_dig = function(pos, player)
			return beds.can_dig(pos)
		end,
	})

	minetest.register_node(name .. "_top", {
		drawtype = "nodebox",
		tiles = def.tiles.top,
		paramtype = "light",
		paramtype2 = "facedir",
		is_ground_content = false,
		pointable = false,
		groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 3, bed = 2},
		sounds = def.sounds or default.node_sound_wood_defaults(),
		drop = name .. "_bottom",
		node_box = {
			type = "fixed",
			fixed = def.nodebox.top,
		},
		on_destruct = function(pos)
			destruct_bed(pos, 2)
		end,
		can_dig = function(pos, player)
			local node = minetest.get_node(pos)
			local dir = minetest.facedir_to_dir(node.param2)
			local p = vector.add(pos, dir)
			return beds.can_dig(p)
		end,
	})

	minetest.register_alias(name, name .. "_bottom")

	minetest.register_craft({
		output = name,
		recipe = def.recipe
	})
end


code:
-- mesecraft_beds/beds.lua

-- support for MT game translation.
local S = beds.get_translator

-- Simple shaped bed

beds.colors = {
	{"black", "Black"},
	{"blue", "Blue"},
	{"brown", "Brown"},
	{"cyan", "Cyan"},
	{"dark_green", "Dark Green"},
	{"dark_grey", "Dark Grey"},
	{"green", "Green"},
	{"grey", "Grey"},
	{"magenta", "Magenta"},
	{"orange", "Orange"},
	{"pink", "Pink"},
	{"red", "Red"},
	{"violet", "Violet"},
	{"white", "White"},
	{"yellow", "Yellow"},
}

for _, row in ipairs(beds.colors) do
local color = row[1]
local desc = row[2]

-- Simple shaped bed

local simple_texture = "beds_bed_inv.png^wool_"..color..".png^beds_bed_inv.png^[makealpha:255,128,128"

beds.register_bed("mesecraft_beds:bed_" ..color, {
	description =  S(desc.. " Bed"),
	inventory_image = simple_texture,
	wield_image = simple_texture,
	tiles = {
		bottom = {
			"wool_"..color..".png",
			"default_wood.png",
			"beds_bed_side_bottom_r_"..color..".png",
			"beds_bed_side_bottom_r_"..color..".png^[transformfx",
			"beds_bed_side_bottom_"..color..".png"
		},
		top = {
			"beds_bed_top_top_"..color..".png",
			"default_wood.png",
			"beds_bed_side_top_r_"..color..".png",
			"beds_bed_side_top_r_"..color..".png^[transformfx",
			"beds_bed_side_top.png",
		}
	},
	nodebox = {
		bottom = {-0.5, -0.5, -0.5, 0.5, 0.0625, 0.5},
		top = {-0.5, -0.5, -0.5, 0.5, 0.0625, 0.5},
	},
	selectionbox = {-0.5, -0.5, -0.5, 0.5, 0.0625, 1.5},
	groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 3, bed = 2, fall_damage_add_percent=-40, bouncy=85},
        sounds = {
		footstep = { name = "bouncy", gain = 0.8 },
                dig = { name = "default_dig_oddly_breakable_by_hand", gain = 1.0 },
                dug = { name = "default_dug_node", gain = 1.0 },
        },
	recipe = {
		{"wool:"..color, "wool:"..color, "wool:white"},
		{"group:wood", "group:wood", "group:wood"}
	},
})

-- Fuel
minetest.register_craft({
	type = "fuel",
	recipe = "beds:bed_"..color,
	burntime = 12,
})
end

-- Aliases for PilzAdam's beds mod, adds compatibility for mods expecting there to bed mtg beds.
minetest.register_alias("beds:bed_bottom", "mesecraft_beds:bed_red_bottom")
minetest.register_alias("beds:bed_top", "mesecraft_beds:bed_red_top")
minetest.register_alias("beds:fancy_bed_bottom", "mesecraft_beds:bed_red_bottom")
minetest.register_alias("beds:fancy_bed_top", "mesecraft_beds:bed_red_top")


code:
local pi = math.pi
local is_sp = minetest.is_singleplayer()
local enable_respawn = minetest.settings:get_bool("enable_bed_respawn")
if enable_respawn == nil then
	enable_respawn = true
end

-- support for MT game translation.
local S = beds.get_translator

-- Helper functions

local function get_look_yaw(pos)
	local rotation = minetest.get_node(pos).param2
	if rotation > 3 then
		rotation = rotation % 4 -- Mask colorfacedir values
	end
	if rotation == 1 then
		return pi / 2, rotation
	elseif rotation == 3 then
		return -pi / 2, rotation
	elseif rotation == 0 then
		return pi, rotation
	else
		return 0, rotation
	end
end

local function is_night_skip_enabled()
	local enable_night_skip = minetest.settings:get_bool("enable_bed_night_skip")
	if enable_night_skip == nil then
		enable_night_skip = true
	end
	return enable_night_skip
end

local function check_in_beds(players)
	local in_bed = beds.player
	if not players then
		players = minetest.get_connected_players()
	end

	for n, player in ipairs(players) do
		local name = player:get_player_name()
		if not in_bed[name] then
			return false
		end
	end

	return #players > 0
end

local function lay_down(player, pos, bed_pos, state, skip)
	local name = player:get_player_name()
	local hud_flags = player:hud_get_flags()

	if not player or not name then
		return
	end

	-- stand up
	if state ~= nil and not state then
		local p = beds.pos[name] or nil
		beds.player[name] = nil
		beds.bed_position[name] = nil
		-- skip here to prevent sending player specific changes (used for leaving players)
		if skip then
			return
		end
		if p then
			player:set_pos(p)
		end

		-- physics, eye_offset, etc
		player:set_eye_offset({x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
		player:set_look_horizontal(math.random(1, 180) / 100)
		player_api.player_attached[name] = false
		player:set_physics_override(1, 1, 1)
		hud_flags.wielditem = true
		player_api.set_animation(player, "stand" , 30)

	-- lay down
	else
		beds.pos[name] = pos
		beds.bed_position[name] = bed_pos
		beds.player[name] = 1

		-- physics, eye_offset, etc
		player:set_eye_offset({x = 0, y = -13, z = 0}, {x = 0, y = 0, z = 0})
		local yaw, param2 = get_look_yaw(bed_pos)
		player:set_look_horizontal(yaw)
		local dir = minetest.facedir_to_dir(param2)
		-- p.y is just above the nodebox height of the 'Simple Bed' (the highest bed),
		-- to avoid sinking down through the bed.
		local p = {
			x = bed_pos.x + dir.x / 2,
			y = bed_pos.y + 0.07,
			z = bed_pos.z + dir.z / 2
		}
		player:set_physics_override(0, 0, 0)
		player:set_pos(p)
		player_api.player_attached[name] = true
		hud_flags.wielditem = false
		player_api.set_animation(player, "lay" , 0)
	end

	player:hud_set_flags(hud_flags)
end

local function get_player_in_bed_count()
	local c = 0
	for _, _ in pairs(beds.player) do
		c = c + 1
	end
	return c
end

local function update_formspecs(finished)
	local ges = #minetest.get_connected_players()
	local player_in_bed = get_player_in_bed_count()
  	local afk_count = afk.afk_count
   	local is_majority = (#minetest.get_connected_players() / 2) < (player_in_bed + afk_count)

	local form_n
	local esc = minetest.formspec_escape
	if finished then
		form_n = beds.formspec .. "label[2.7,9;" .. esc(S("Good morning.")) .. "]"
	else
		form_n = beds.formspec .. "label[2.2,9;" ..
			esc(S("@1 of @2 players are in bed", player_in_bed, ges)) .. "]"
		if is_majority and is_night_skip_enabled() then
			form_n = form_n .. "button_exit[2,6;4,0.75;force;" ..
				esc(S("Force night skip")) .. "]"
		end
	end

	for name,_ in pairs(beds.player) do
		minetest.show_formspec(name, "beds_form", form_n)
	end
end

-- Public functions

function beds.kick_players()
	for name, _ in pairs(beds.player) do
		local player = minetest.get_player_by_name(name)
		lay_down(player, nil, nil, false)
	end
end

function beds.skip_night()
	minetest.set_timeofday(0.23)
end

function beds.on_rightclick(pos, player)
	local name = player:get_player_name()
	local ppos = player:get_pos()
	local tod = minetest.get_timeofday()

	if tod > 0.2 and tod < 0.805 then
		if beds.player[name] then
			lay_down(player, nil, nil, false)
		end
		minetest.chat_send_player(name, S("You can only sleep at night."))
		return
	end

	-- move to bed
	if not beds.player[name] then
		lay_down(player, ppos, pos)
		beds.set_spawns() -- save respawn positions when entering bed
	else
		lay_down(player, nil, nil, false)
	end

	if not is_sp then
		update_formspecs(false)
	end

	-- skip the night and let all players stand up
	if check_in_beds() then
		minetest.after(2, function()
			if not is_sp then
				update_formspecs(is_night_skip_enabled())
			end
			if is_night_skip_enabled() then
				beds.skip_night()
				beds.kick_players()
			end
		end)
	end
end

function beds.can_dig(bed_pos)
	-- Check all players in bed which one is at the expected position
	for _, player_bed_pos in pairs(beds.bed_position) do
		if vector.equals(bed_pos, player_bed_pos) then
			return false
		end
	end
	return true
end

-- Callbacks
-- Only register respawn callback if respawn enabled
if enable_respawn then
	-- respawn player at bed if enabled and valid position is found
	minetest.register_on_respawnplayer(function(player)
		local name = player:get_player_name()
		local pos = beds.spawn[name]
		if pos then
			player:set_pos(pos)
			return true
		end
	end)
end

minetest.register_on_leaveplayer(function(player)
	local name = player:get_player_name()
	lay_down(player, nil, nil, false, true)
	beds.player[name] = nil
	if check_in_beds() then
		minetest.after(2, function()
			update_formspecs(is_night_skip_enabled())
			if is_night_skip_enabled() then
				beds.skip_night()
				beds.kick_players()
			end
		end)
	end
end)

minetest.register_on_player_receive_fields(function(player, formname, fields)
	if formname ~= "beds_form" then
		return
	end

	-- Because "Force night skip" button is a button_exit, it will set fields.quit
	-- and lay_down call will change value of player_in_bed, so it must be taken
	-- earlier.
	local last_player_in_bed = get_player_in_bed_count()

	if fields.quit or fields.leave then
		lay_down(player, nil, nil, false)
		update_formspecs(false)
	end

	if fields.force then
	local afk_count = afk.afk_count
		local is_majority = (#minetest.get_connected_players() / 2) < (last_player_in_bed + afk_count)
		if is_majority and is_night_skip_enabled() then
			update_formspecs(true)
			beds.skip_night()
			beds.kick_players()
		else
			update_formspecs(false)
		end
	end
end)


code:
-- mesecraft_beds/init.lua

-- Load support for game translation.
local S = minetest.get_translator("mesecraft_beds")
local esc = minetest.formspec_escape

beds = {}
beds.player = {}
beds.bed_position = {}
beds.pos = {}
beds.spawn = {}
beds.get_translator = S

beds.formspec = "size[8,11;true]" ..
	"no_prepend[]" ..
	"bgcolor[#080808BB;true]" ..
	"button_exit[2,10;4,0.75;leave;" .. esc(S("Leave Bed")) .. "]"

local modpath = minetest.get_modpath("mesecraft_beds")

-- Load files
dofile(modpath .. "/functions.lua")
dofile(modpath .. "/api.lua")
dofile(modpath .. "/beds.lua")
dofile(modpath .. "/spawns.lua")


code:
# textdomain: beds
Fancy Bed=Schickes Bett
Simple Bed=Schlichtes Bett
Leave Bed=Bett verlassen
Good morning.=Guten Morgen.
@1 of @2 players are in bed=@1 von @2 Spielern sind im Bett
Force night skip=Überspringen der Nacht erzwingen
You can only sleep at night.=Sie können nur nachts schlafen.


code:
# textdomain: beds
Fancy Bed=Cama de lujo
Simple Bed=Cama sencilla
Leave Bed=Abandonar cama
Good morning.=Buenos días.
@1 of @2 players are in bed=@1 de @2 jugadores están en cama
Force night skip=Forzar evitar noche
You can only sleep at night.=Sólo puedes dormir por la noche.


code:
# textdomain: beds
Fancy Bed=Lit chic
Simple Bed=Lit simple
Leave Bed=Se lever du lit
Good morning.=Bonjour.
@1 of @2 players are in bed=@1 joueur(s) sur @2 sont au lit
Force night skip=Forcer le passage de la nuit
You can only sleep at night.=Vous ne pouvez dormir que la nuit.


code:
# textdomain: beds
Leave Bed=Tinggalkan Dipan
Good morning.=Selamat pagi.
@1 of @2 players are in bed=@1 dari @2 pemain sedang tidur
Force night skip=Paksa lewati malam
You can only sleep at night.=Anda hanya boleh tidur pada waktu malam.
Fancy Bed=Dipan Mewah
Simple Bed=Dipan Sederhana


code:
# textdomain: beds
Fancy Bed=Letto decorato
Simple Bed=Letto semplice
Leave Bed=Alzati dal letto


code:
# textdomain: beds
Fancy Bed=Katil Beragam
Simple Bed=Katil Biasa
Leave Bed=Bangun
Good morning.=Selamat pagi.
@1 of @2 players are in bed=@1 daripada @2 pemain sedang tidur
Force night skip=Paksa langkau malam
You can only sleep at night.=Anda hanya boleh tidur pada waktu malam.


code:
# textdomain: beds
Fancy Bed=Детализированная Кровать
Simple Bed=Обычная Кровать
Leave Bed=Встать с кровати
Good morning.=Доброе утро.
@1 of @2 players are in bed=@1 из @2 игроков в кровати
Force night skip=Пропустить ночь
You can only sleep at night.=Вы можете спать только ночью.


code:
# textdomain: beds
Fancy Bed=Fin säng
Simple Bed=Enkel Säng
Leave Bed=Lämna Säng
Good morning.= God morgon.
@1 of @2 players are in bed=@1 av @2 spelar försöker sover.
Force night skip=Tvinga över natten
You can only sleep at night.=Du kan bara sova på natten.


code:
# textdomain: beds
Fancy Bed=花式床
Simple Bed=简易床
Leave Bed=离开床
Good morning.=早安！
@1 of @2 players are in bed=@2位玩家中的@1位在床上
Force night skip=强制跳过夜晚
You can only sleep at night.=你只能在晚上睡觉。


code:
# textdomain: beds
Fancy Bed=花式床
Simple Bed=簡易床
Leave Bed=離開床
Good morning.=早安！
@1 of @2 players are in bed=@2位玩家中的@1位在床上
Force night skip=強制跳過夜晚
You can only sleep at night.=你只能在晚上睡覺。


code:
# textdomain: beds
Leave Bed=
Good morning.=
@1 of @2 players are in bed=
Force night skip=
You can only sleep at night.=
Fancy Bed=
Simple Bed=


code:
name = mesecraft_beds
description = MeseCraft Game mod: mesecraft_beds
depends = default, wool


code:
local world_path = minetest.get_worldpath()
local org_file = world_path .. "/beds_spawns"
local file = world_path .. "/beds_spawns"
local bkwd = false

-- check for PA's beds mod spawns
local cf = io.open(world_path .. "/beds_player_spawns", "r")
if cf ~= nil then
	io.close(cf)
	file = world_path .. "/beds_player_spawns"
	bkwd = true
end

function beds.read_spawns()
	local spawns = beds.spawn
	local input = io.open(file, "r")
	if input and not bkwd then
		repeat
			local x = input:read("*n")
			if x == nil then
				break
			end
			local y = input:read("*n")
			local z = input:read("*n")
			local name = input:read("*l")
			spawns[name:sub(2)] = {x = x, y = y, z = z}
		until input:read(0) == nil
		io.close(input)
	elseif input and bkwd then
		beds.spawn = minetest.deserialize(input:read("*all"))
		input:close()
		beds.save_spawns()
		os.rename(file, file .. ".backup")
		file = org_file
	end
end

beds.read_spawns()

function beds.save_spawns()
	if not beds.spawn then
		return
	end
	local data = {}
	local output = io.open(org_file, "w")
	for k, v in pairs(beds.spawn) do
		table.insert(data, string.format("%.1f %.1f %.1f %s\n", v.x, v.y, v.z, k))
	end
	output:write(table.concat(data))
	io.close(output)
end

function beds.set_spawns()
	for name,_ in pairs(beds.player) do
		local player = minetest.get_player_by_name(name)
		local p = player:get_pos()
		-- but don't change spawn location if borrowing a bed
		if not minetest.is_protected(p, name) then
			beds.spawn[name] = p
		end
	end
	beds.save_spawns()
end

function beds.remove_spawns_at(pos)
	for name, p in pairs(beds.spawn) do
		if vector.equals(vector.round(p), pos) then
			beds.spawn[name] = nil
		end
	end
	beds.save_spawns()
end


code:
local mailbox = {}
screwdriver = screwdriver or {}

local function get_img(img)
	local img_name = img:match("(.*)%.png")
	if img_name then return img_name..".png" end
end

local function img_col(stack)
	local def = minetest.registered_items[stack]
	if not def then return "" end

	if def.inventory_image ~= "" then
		local img = get_img(def.inventory_image)
		if img then return img end
	end

	if def.tiles then
		local tile, img = def.tiles[1]
		if type(tile) == "table" then
			img = get_img(tile.name)
		elseif type(tile) == "string" then
			img = get_img(tile)
		end
		if img then return img end
	end

	return ""
end

function mailbox:formspec(pos, owner, is_owner)
	local spos = pos.x..","..pos.y..","..pos.z
	local meta = minetest.get_meta(pos)
	local giver, img = "", ""

	if is_owner then
		for i = 1, 7 do
			local giving = meta:get_string("giver"..i)
			if giving ~= "" then
				local stack = meta:get_string("stack"..i)
				local giver_name = giving:sub(1,12)
				local stack_name = stack:match("[%w_:]+")
				local stack_count = stack:match("%s(%d+)") or 1

				giver = giver.."#FFFF00,"..giver_name..","..i..
					",#FFFFFF,x "..stack_count..","
				img = img..i.."="..
					img_col(stack_name).."^\\[resize:16x16,"
			end
		end

		return [[ size[9.5,9]
			label[0,0;Mailbox]
			label[6,0;Last donators]
			box[6,0.72;3.3,3.5;#555555]
			listring[current_player;main]
			list[current_player;main;0.75,5.25;8,4;]
			tableoptions[background=#00000000;highlight=#00000000;border=false] ]]..
			"tablecolumns[color;text;image,"..img.."0;color;text]"..
			"table[6,0.75;3.3,4;givers;"..giver.."]"..
			"list[nodemeta:"..spos..";mailbox;0,0.75;6,4;]"..
			"listring[nodemeta:"..spos..";mailbox]"..
			xbg..default.get_hotbar_bg(0.75,5.25)
	end
	return [[ size[8,5]
		list[current_player;main;0,1.25;8,4;] ]]..
		"label[0,0;Send your goods to\n"..
		(minetest.colorize and
			minetest.colorize("#FFFF00", owner) or owner).."]"..
		"list[nodemeta:"..spos..";drop;3.5,0;1,1;]"..
		xbg..default.get_hotbar_bg(0,1.25)
end

function mailbox.dig(pos, player)
	local meta = minetest.get_meta(pos)
	local owner = meta:get_string("owner")
	local player_name = player and player:get_player_name()
	local inv = meta:get_inventory()

	return inv:is_empty("mailbox") and player_name == owner
end

function mailbox.after_place_node(pos, placer)
	local meta = minetest.get_meta(pos)
	local player_name = placer:get_player_name()

	meta:set_string("owner", player_name)
	meta:set_string("infotext", player_name.."'s Mailbox")

	local inv = meta:get_inventory()
	inv:set_size("mailbox", 6*4)
	inv:set_size("drop", 1)
end

function mailbox.rightclick(pos, node, clicker, itemstack, pointed_thing)
	local meta = minetest.get_meta(pos)
	local player = clicker:get_player_name()
	local owner = meta:get_string("owner")

	minetest.show_formspec(player, "mesecraft_mailbox:mailbox", mailbox:formspec(pos,
			       owner, (player == owner)))
	return itemstack
end

function mailbox.put(pos, listname, _, stack, player)
	if listname == "drop" then
		local inv = minetest.get_meta(pos):get_inventory()
		if inv:room_for_item("mailbox", stack) then
			return -1
		else
			minetest.chat_send_player(player:get_player_name(),
						  "The mailbox is full")
		end
	end
	return 0
end

function mailbox.on_put(pos, listname, _, stack, player)
	local meta = minetest.get_meta(pos)
	local inv = meta:get_inventory()

	if listname == "drop" and inv:room_for_item("mailbox", stack) then
		inv:set_list("drop", {})
		inv:add_item("mailbox", stack)

		for i = 7, 2, -1 do
			meta:set_string("giver"..i, meta:get_string("giver"..(i-1)))
			meta:set_string("stack"..i, meta:get_string("stack"..(i-1)))
		end

		meta:set_string("giver1", player:get_player_name())
		meta:set_string("stack1", stack:to_string())
	end
end

function mailbox.allow_take(pos, listname, index, stack, player)
	local meta = minetest.get_meta(pos)

	if player:get_player_name() ~= meta:get_string("owner") then
		return 0
	end
	return stack:get_count()
end

function mailbox.allow_move(pos)
	return 0
end

minetest.register_node("mesecraft_mailbox:mailbox", {
	description = "Mailbox",
	tiles = {"mesecraft_mailbox_top.png", "mesecraft_mailbox_bottom.png",
		 "mesecraft_mailbox_side.png", "mesecraft_mailbox_side.png",
		 "mesecraft_mailbox.png", "mesecraft_mailbox.png"},
	groups = {cracky=3, oddly_breakable_by_hand=1},
	on_rotate = screwdriver.rotate_simple,
	can_dig = mailbox.dig,
	on_rightclick = mailbox.rightclick,
	allow_metadata_inventory_take = mailbox.allow_take,
	allow_metadata_inventory_move = mailbox.allow_move,
	on_metadata_inventory_put = mailbox.on_put,
	allow_metadata_inventory_put = mailbox.put,
	after_place_node = mailbox.after_place_node
})

-- Recipes

minetest.register_craft({
	output = "mesecraft_mailbox:mailbox",
	recipe = {
		{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
		{"dye:red", "default:paper", "dye:red"},
		{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"}
	}
})


code:
name = mesecraft_mailbox
author = mesecraft
title = MeseCraft Mailbox
description = A mailbox where people can drop items into your mailbox.
depends = default, dye
optional_depends =


code:
screwdriver = screwdriver or {}

-- Register the television
minetest.register_node("mesecraft_television:television", {
	description = "Television",
	light_source = 11,
	groups = {cracky=3, oddly_breakable_by_hand=2},
	on_rotate = screwdriver.rotate_simple,
	tiles = {"mesecraft_television_left.png^[transformR270",
		 "mesecraft_television_left.png^[transformR90",
		 "mesecraft_television_left.png^[transformFX",
		 "mesecraft_television_left.png", "mesecraft_television_back.png",
		{name="mesecraft_television_front_animated.png",
		 animation = {type="vertical_frames", length=80.0}} }
})

-- Craft the television
minetest.register_craft({
	output = "mesecraft_television:television",
	recipe = {
		{"default:steel_ingot", "default:copper_ingot", "default:steel_ingot"},
		{"default:steel_ingot", "default:glass", "default:steel_ingot"},
		{"default:steel_ingot", "default:copper_ingot", "default:steel_ingot"}
	}
})


code:
name = mesecraft_television
author = mesecraft
title = MeseCraft Television
description = A decorative television forked from xdecor originally by kilbith.
depends = default
optional_depends =


code:
name = ITEMS
description = Meta-modpack containing items-related mods for MeseCraft.


code:
Minetest mod: moognu
==========================
See license.txt for license information.

Originally published as "nyancat" mod.

Authors of source code
----------------------
Originally by celeron55, Perttu Ahola <celeron55@gmail.com> (LGPL 2.1)
Various Minetest developers and contributors (LGPL 2.1)
Modified by Thomas-S (LGPL 2.1)

Authors of media files
----------------------
VanessaE (CC BY-SA 3.0):
  moognu_rainbow.png

The contributors of http://archive.org/details/M00GNU and tenplus1 (CC BY-SA 3.0):
  moognu_back.png
  moognu_front.png
  moognu_side.png


code: This mod adds a free alternative to the removed Nyan Cats: The MooGNU.


code:
minetest.register_node("moognu:moognu", {
	description = "MooGNU",
	tiles = {"moognu_side.png", "moognu_side.png", "moognu_side.png",
		"moognu_side.png", "moognu_back.png", "moognu_front.png"},
	paramtype = "light",
	light_source = default.LIGHT_MAX,
	paramtype2 = "facedir",
	groups = {cracky = 2},
	is_ground_content = false,
	legacy_facedir_simple = true,
	sounds = default.node_sound_defaults(),
})

minetest.register_node("moognu:moognu_rainbow", {
	description = "MooGNU Rainbow",
	tiles = {
		"moognu_rainbow.png^[transformR90",
		"moognu_rainbow.png^[transformR90",
		"moognu_rainbow.png"
	},
	paramtype = "light",
	light_source = default.LIGHT_MAX,
	paramtype2 = "facedir",
	groups = {cracky = 2},
	is_ground_content = false,
	sounds = default.node_sound_defaults(),
})

minetest.register_craft({
	type = "fuel",
	recipe = "moognu:moognu",
	burntime = 1,
})

minetest.register_craft({
	type = "fuel",
	recipe = "moognu:moognu_rainbow",
	burntime = 1,
})

moognu = {}

function moognu.place(pos, facedir, length)
	if facedir > 3 then
		facedir = 0
	end
	local tailvec = minetest.facedir_to_dir(facedir)
	local p = {x = pos.x, y = pos.y, z = pos.z}
	minetest.set_node(p, {name = "moognu:moognu", param2 = facedir})
	for i = 1, length do
		p.x = p.x + tailvec.x
		p.z = p.z + tailvec.z
		minetest.set_node(p, {name = "moognu:moognu_rainbow", param2 = facedir})
	end
end

function moognu.generate(minp, maxp, seed)
	local height_min = -31000
	local height_max = -32
	if maxp.y < height_min or minp.y > height_max then
		return
	end
	local y_min = math.max(minp.y, height_min)
	local y_max = math.min(maxp.y, height_max)
	local volume = (maxp.x - minp.x + 1) * (y_max - y_min + 1) * (maxp.z - minp.z + 1)
	local pr = PseudoRandom(seed + 9324342)
	local max_num_moognus = math.floor(volume / (16 * 16 * 16))
	for i = 1, max_num_moognus do
		if pr:next(0, 1000) == 0 then
			local x0 = pr:next(minp.x, maxp.x)
			local y0 = pr:next(minp.y, maxp.y)
			local z0 = pr:next(minp.z, maxp.z)
			local p0 = {x = x0, y = y0, z = z0}
			moognu.place(p0, pr:next(0, 3), pr:next(3, 15))
		end
	end
end

minetest.register_on_generated(function(minp, maxp, seed)
	moognu.generate(minp, maxp, seed)
end)

-- Legacy
minetest.register_alias("default:nyancat", "moognu:moognu")
minetest.register_alias("nyancat:nyancat", "moognu:moognu")
minetest.register_alias("default:nyancat_rainbow", "moognu:moognu_rainbow")
minetest.register_alias("nyancat:nyancat_rainbow", "moognu:moognu_rainbow")


code:
name = moognu
depends = default
description = This mod adds a free alternative to the removed Nyan Cats: The MooGNU.


code:
root = true

[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true

[*.{lua,luacheckrc}]
indent_style = tab
indent_size = 4


code:
std = "lua51+minetest"
unused_args = false
allow_defined_top = true
max_line_length = 999

stds.minetest = {
	read_globals = {
		"DIR_DELIM",
		"minetest",
		"core",
		"dump",
		"vector",
		"nodeupdate",
		"VoxelManip",
		"VoxelArea",
		"PseudoRandom",
		"ItemStack",
		"default",
		table = {
			fields = {
				"copy",
			},
		},
	}
}

read_globals = {
	"intllib",
	"protector",
	"isprotect",
	"IsPlayerNodeOwner",
	"HasOwner",
	"getLastOwner",
	"GetNodeOwnerName",
}


code:
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v2.1.0
    hooks:
      - id: end-of-file-fixer
      - id: trailing-whitespace

      - id: mixed-line-ending
        args: [--fix=lf]


code:
language: generic

addons:
  apt:
    packages:
    - luarocks

install:
  - pyenv global 3.6.3
  - pip3 install --user pre-commit
  - luarocks install --local luacheck

script:
  - $HOME/.local/bin/pre-commit run --all-files
  - $HOME/.luarocks/bin/luacheck .


code:
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- `settingtypes.txt` file to allow configuring settings in the main menu.
- Polish translation.

### Changed

- The minimum supported Minetest version is now 5.0.0.
- Stairs+ nodes now emit one light level less compared to full nodes to make up
  for their smaller visual size.

### Fixed

- Fixed a recipe conflict that made Centered Wooden Tiles impossible to craft.

## [1.3.0] - 2019-03-23

### Changed

- Stairs+ are now displayed in the creative inventory by default.
- Localization files now use the gettext `.po` format.
- Updated intllib support to avoid using deprecated functions.

### Fixed

- Node rotation now works correctly when placing Stairs+ nodes.
- Stairs+ glasslike nodes' textures are now easier to see.

## [1.2.0] - 2018-11-24

### Added

- Stairs+ nodes for `basic_materials`'s concrete, cement and brass blocks.
- Listring add for circular saw.
- **Stairs+:** New API function
  `stairsplus:register_custom_subset(subset, modname, subname, recipeitem, fields)`.

### Fixed

- The papyrus crafting recipe override is now properly applied over the
  `default` mod's recipe.
- Centered wooden tiles are now craftable.
- Wool Stairs+ nodes can no longer be used in crafting.
- The circular saw can no longer replace items from the player's inventory
  when it is full.

### Changed

- New crafting recipes for:
  - Stone Tile
  - Circle Stone Bricks
- Stairs+:
  - Moved definitions to `stairsplus.defs` table into a separate file.
  - Moved recipe definitions to `stairsplus.register_recipes` function
    into a separate file.

## [1.1.0] - 2017-10-04

### Added

- 3 new node shapes in the circular saw (thin slabs, available in
  "L-shaped", "corner-shaped" and "U-shaped" variations), all with 1/16
  thickness.
- New Stairs+ nodes:
  - Coral Skeleton
  - Desert Sandstone, Silver Sandstone
  - Desert Sandstone Brick, Silver Sandstone Brick
  - Desert Sandstone Block, Silver Sandstone Block
  - Obsidian Block
  - Sandstone Block
  - Stone Block, Desert Stone Block
  - Straw
  - Tin Block
  - Wool (all colors)
- Other mods can now get a list of all the defined Stairs+ shapes.

## 1.0.0 - 2017-02-19

- Initial versioned release.

[Unreleased]: https://github.com/minetest-mods/moreblocks/compare/v1.3.0...HEAD
[1.3.0]: https://github.com/minetest-mods/moreblocks/compare/v1.2.0...v1.3.0
[1.2.0]: https://github.com/minetest-mods/moreblocks/compare/v1.1.0...v1.2.0
[1.1.0]: https://github.com/minetest-mods/moreblocks/compare/v1.0.0...v1.1.0


code:
# Contributing to More Blocks

Thank you for your interest in More Blocks! Before contributing,
be sure to know about these few guidelines:

- Contributions have to be licensed under the zlib license (or compatible)
  for code, and CC BY-SA 3.0 (or compatible) for assets.
- Make sure to update the changelog, keeping the
  [changelog format](http://keepachangelog.com/en/1.0.0/) we use.
- Don't bump the version yourself. Maintainers will do this when necessary.


code:
# More Blocks

More Blocks for [Minetest](https://www.minetest.net/), a free and open source infinite
world block sandbox game.

[**Forum topic**](https://forum.minetest.net/viewtopic.php?f=11&t=509)

## Installation

### Download the mod

To install More Blocks, clone this Git repository into your Minetest's `mods/`
directory:

```bash
git clone https://github.com/minetest-mods/moreblocks.git
```

You can also
[download a ZIP archive](https://github.com/minetest-mods/moreblocks/archive/master.zip)
of More Blocks. If you do so, you will need to extract the archive then rename
the resulting folder from `moreblocks-master` to `moreblocks` – this is
**absolutely** required, as the mod won't work otherwise.

### Enable the mod

Once you have installed More Blocks, you need to enable it in Minetest.
The procedure is as follows:

#### Using the client's main menu

This is the easiest way to enable More Blocks when playing in singleplayer
(or on a server hosted from a client).

1. Start Minetest and switch to the **Local Game** tab.
2. Select the world you want to enable More Blocks in.
3. Click **Configure**, then enable `moreblocks` by double-clicking it
   (or ticking the **Enabled** checkbox).
4. Save the changes, then start a game on the world you enabled More Blocks on.
5. More Blocks should now be running on your world.

#### Using a text editor

This is the recommended way to enable the mod on a server without using a GUI.

1. Make sure Minetest is not currently running (otherwise, it will overwrite
   the changes when exiting).
2. Open the world's `world.mt` file using a text editor.
3. Add the following line at the end of the file:

```text
load_mod_moreblocks = true
```

If the line is already present in the file, then replace `false` with `true`
on that line.

4. Save the file, then start a game on the world you enabled More Blocks on.
5. More Blocks should now be running on your world.

## Version compatibility

More Blocks is currently primarily tested with Minetest 0.4.17.
It may or may not work with newer or older versions. Issues arising in older
versions than 0.4.17 will generally not be fixed.

## License

Copyright © 2011-2019 Hugo Locurcio and contributors

- More Blocks code is licensed under the zlib license, see
  [`LICENSE.md`](LICENSE.md) for details.
- Unless otherwise specified, More Blocks textures are licensed under
  [CC BY-SA 3.0 Unported](https://creativecommons.org/licenses/by-sa/3.0/).

`moreblocks_copperpatina.png` was created by pithydon, and is licensed under
[CC0 1.0 Universal](https://creativecommons.org/publicdomain/zero/1.0/).


code:
--[[
More Blocks: alias definitions

Copyright © 2011-2019 Hugo Locurcio and contributors.
Licensed under the zlib license. See LICENSE.md for more information.
--]]

-- More Blocks aliases:
minetest.register_alias("sweeper", "moreblocks:sweeper")
minetest.register_alias("circular_saw", "moreblocks:circular_saw")
minetest.register_alias("jungle_stick", "moreblocks:jungle_stick")

-- Old block/item replacement:
minetest.register_alias("moreblocks:oerkkiblock", "default:mossycobble")
minetest.register_alias("moreblocks:screwdriver", "screwdriver:screwdriver")

-- Node and item renaming:
minetest.register_alias("moreblocks:stone_bricks", "default:stonebrick")
minetest.register_alias("moreblocks:stonebrick", "default:stonebrick")
minetest.register_alias("moreblocks:junglewood", "default:junglewood")
minetest.register_alias("moreblocks:jungle_wood", "default:junglewood")
minetest.register_alias("moreblocks:fence_junglewood", "default:fence_junglewood")
minetest.register_alias("moreblocks:fence_jungle_wood", "default:fence_junglewood")
minetest.register_alias("moreblocks:jungle_stick", "default:stick")

for _, t in pairs(circular_saw.names) do
	minetest.register_alias("moreblocks:" .. t[1] .. "_jungle_wood" .. t[2],
			"moreblocks:" .. t[1] .. "_junglewood" .. t[2])
end
minetest.register_alias("moreblocks:horizontaltree", "moreblocks:horizontal_tree")
minetest.register_alias("moreblocks:horizontaljungletree", "moreblocks:horizontal_jungle_tree")
minetest.register_alias("moreblocks:stonesquare", "moreblocks:stone_tile")
minetest.register_alias("moreblocks:circlestonebrick", "moreblocks:circle_stone_bricks")
minetest.register_alias("moreblocks:ironstonebrick", "moreblocks:iron_stone_bricks")
minetest.register_alias("moreblocks:coalstone", "moreblocks:coal_stone")
minetest.register_alias("moreblocks:ironstone", "moreblocks:iron_stone")
minetest.register_alias("moreblocks:woodtile", "moreblocks:wood_tile")
minetest.register_alias("moreblocks:woodtile_full", "moreblocks:wood_tile_full")
minetest.register_alias("moreblocks:woodtile_centered", "moreblocks:wood_tile_centered")
minetest.register_alias("moreblocks:woodtile_up", "moreblocks:wood_tile_offset")
minetest.register_alias("moreblocks:wood_tile_up", "moreblocks:wood_tile_offset")
minetest.register_alias("moreblocks:woodtile_down", "moreblocks:wood_tile_down")
minetest.register_alias("moreblocks:woodtile_left", "moreblocks:wood_tile_left")
minetest.register_alias("moreblocks:woodtile_right", "moreblocks:wood_tile_right")
minetest.register_alias("moreblocks:coalglass", "moreblocks:coal_glass")
minetest.register_alias("moreblocks:ironglass", "moreblocks:iron_glass")
minetest.register_alias("moreblocks:glowglass", "moreblocks:glow_glass")
minetest.register_alias("moreblocks:superglowglass", "moreblocks:super_glow_glass")
minetest.register_alias("moreblocks:trapglass", "moreblocks:trap_glass")
minetest.register_alias("moreblocks:trapstone", "moreblocks:trap_stone")
minetest.register_alias("moreblocks:cactuschecker", "moreblocks:cactus_checker")
minetest.register_alias("moreblocks:coalchecker", "moreblocks:coal_checker")
minetest.register_alias("moreblocks:ironchecker", "moreblocks:iron_checker")
minetest.register_alias("moreblocks:cactusbrick", "moreblocks:cactus_brick")
minetest.register_alias("moreblocks:cleanglass", "moreblocks:clean_glass")
minetest.register_alias("moreblocks:emptybookshelf", "moreblocks:empty_bookshelf")
minetest.register_alias("moreblocks:junglestick", "moreblocks:jungle_stick")
minetest.register_alias("moreblocks:splitstonesquare","moreblocks:split_stone_tile")
minetest.register_alias("moreblocks:allfacestree","moreblocks:all_faces_tree")
minetest.register_alias("moreblocks:empty_bookshelf","moreblocks:empty_shelf")
minetest.register_alias("moreblocks:split_stone_tile_alt","moreblocks:checker_stone_tile")

-- ABM for horizontal trees (fix facedir):
local horizontal_tree_convert_facedir = {7, 12, 9, 18}

minetest.register_abm({
	nodenames = {"moreblocks:horizontal_tree","moreblocks:horizontal_jungle_tree"},
	interval = 1,
	chance = 1,
	action = function(pos, node)
		if node.name == "moreblocks:horizontal_tree" then
			node.name = "default:tree"
		else
			node.name = "default:jungletree"
		end
		node.param2 = node.param2 < 3 and node.param2 or 0
		minetest.set_node(pos, {
			name = node.name,
			param2 = horizontal_tree_convert_facedir[node.param2 + 1]
		})
	end,
})

minetest.register_lbm({
	name = "moreblocks:reduce_wood_tile_redundancy",
	nodenames = {
		"moreblocks:wood_tile_left",
		"moreblocks:wood_tile_down",
		"moreblocks:wood_tile_right",
		"moreblocks:wood_tile_flipped",
	},
	action = function(pos, node)
		if node.name:find("left") then
			minetest.set_node(pos, {name = "moreblocks:wood_tile_offset", param2=1})
		elseif node.name:find("down") then
			minetest.set_node(pos, {name = "moreblocks:wood_tile_offset", param2=2})
		elseif node.name:find("right") then
			minetest.set_node(pos, {name = "moreblocks:wood_tile_offset", param2=3})
		else -- wood_tile_flipped
			minetest.set_node(pos, {name = "moreblocks:wood_tile", param2=1})
		end
		minetest.log('action', "LBM replaced " .. node.name ..
			" at " .. minetest.pos_to_string(pos))
	end,
})


code:
--[[
More Blocks: circular saw

Copyright © 2011-2019 Hugo Locurcio, Sokomine and contributors.
Licensed under the zlib license. See LICENSE.md for more information.
--]]

local S = moreblocks.S
local F = minetest.formspec_escape

circular_saw = {}

circular_saw.known_stairs = setmetatable({}, {
	__newindex = function(k, v)
		local modname = minetest.get_current_modname()
		print(("WARNING: mod %s tried to add node %s to the circular saw"
				.. " manually."):format(modname, v))
	end,
})

-- This is populated by stairsplus:register_all:
circular_saw.known_nodes = {}

-- How many microblocks does this shape at the output inventory cost:
-- It may cause slight loss, but no gain.
circular_saw.cost_in_microblocks = {
	1, 1, 1, 1, 1, 1, 1, 2,
	2, 3, 2, 4, 2, 4, 5, 6,
	7, 1, 1, 2, 4, 6, 7, 8,
	1, 2, 2, 3, 1, 1, 2, 4,
	4, 2, 6, 7, 3, 7, 7, 4,
	8, 3, 2, 6, 2, 1, 3, 4
}

circular_saw.names = {
	{"micro", "_1"},
	{"panel", "_1"},
	{"micro", "_2"},
	{"panel", "_2"},
	{"micro", "_4"},
	{"panel", "_4"},
	{"micro", ""},
	{"panel", ""},

	{"micro", "_12"},
	{"panel", "_12"},
	{"micro", "_14"},
	{"panel", "_14"},
	{"micro", "_15"},
	{"panel", "_15"},
	{"stair", "_outer"},
	{"stair", ""},

	{"stair", "_inner"},
	{"slab", "_1"},
	{"slab", "_2"},
	{"slab", "_quarter"},
	{"slab", ""},
	{"slab", "_three_quarter"},
	{"slab", "_14"},
	{"slab", "_15"},

	{"slab", "_two_sides"},
	{"slab", "_three_sides"},
	{"slab", "_three_sides_u"},
	{"stair", "_half"},
	{"stair", "_alt_1"},
	{"stair", "_alt_2"},
	{"stair", "_alt_4"},
	{"stair", "_alt"},

	{"slope", ""},
	{"slope", "_half"},
	{"slope", "_half_raised"},
	{"slope", "_inner"},
	{"slope", "_inner_half"},
	{"slope", "_inner_half_raised"},
	{"slope", "_inner_cut"},
	{"slope", "_inner_cut_half"},

	{"slope", "_inner_cut_half_raised"},
	{"slope", "_outer"},
	{"slope", "_outer_half"},
	{"slope", "_outer_half_raised"},
	{"slope", "_outer_cut"},
	{"slope", "_outer_cut_half"},
	{"slope", "_outer_cut_half_raised"},
	{"slope", "_cut"},
}

function circular_saw:get_cost(inv, stackname)
	for i, item in pairs(inv:get_list("output")) do
		if item:get_name() == stackname then
			return circular_saw.cost_in_microblocks[i]
		end
	end
end

function circular_saw:get_output_inv(modname, material, amount, max)
	if (not max or max < 1 or max > 99) then max = 99 end

	local list = {}
	local pos = #list

	-- If there is nothing inside, display empty inventory:
	if amount < 1 then
		return list
	end

	for i = 1, #circular_saw.names do
		local t = circular_saw.names[i]
		local cost = circular_saw.cost_in_microblocks[i]
		local balance = math.min(math.floor(amount/cost), max)
		local nodename = modname .. ":" .. t[1] .. "_" .. material .. t[2]
		if  minetest.registered_nodes[nodename] then
			pos = pos + 1
			list[pos] = nodename .. " " .. balance
		end
	end
	return list
end

-- Reset empty circular_saw after last full block has been taken out
-- (or the circular_saw has been placed the first time)
-- Note: max_offered is not reset:
function circular_saw:reset(pos)
	local meta = minetest.get_meta(pos)
	local inv  = meta:get_inventory()
	local owned_by = meta:get_string("owner")

	if owned_by and owned_by ~= "" then
		owned_by = (" (%s)"):format(S("owned by @1", meta:get_string("owner")))
	else
		owned_by = ""
	end

	inv:set_list("input",  {})
	inv:set_list("micro",  {})
	inv:set_list("output", {})

	meta:set_int("anz", 0)
	meta:set_string("infotext", S("Circular Saw is empty") .. owned_by)
end

-- Player has taken something out of the box or placed something inside
-- that amounts to count microblocks:
function circular_saw:update_inventory(pos, amount)
	local meta          = minetest.get_meta(pos)
	local inv           = meta:get_inventory()

	amount = meta:get_int("anz") + amount

	-- The material is recycled automatically.
	inv:set_list("recycle",  {})

	if amount < 1 then -- If the last block is taken out.
		self:reset(pos)
		return
	end

	local stack = inv:get_stack("input",  1)
	-- At least one "normal" block is necessary to see what kind of stairs are requested.
	if stack:is_empty() then
		-- Any microblocks not taken out yet are now lost.
		-- (covers material loss in the machine)
		self:reset(pos)
		return

	end
	local node_name = stack:get_name() or ""
	local node_def = stack:get_definition()
	local name_parts = circular_saw.known_nodes[node_name] or ""
	local modname  = name_parts[1] or ""
	local material = name_parts[2] or ""
	local owned_by = meta:get_string("owner")

	if owned_by and owned_by ~= "" then
		owned_by = (" (%s)"):format(S("owned by @1", meta:get_string("owner")))
	else
		owned_by = ""
	end

	inv:set_list("input", { -- Display as many full blocks as possible:
		node_name.. " " .. math.floor(amount / 8)
	})

	-- The stairnodes made of default nodes use moreblocks namespace, other mods keep own:
	if modname == "default" then
		modname = "moreblocks"
	end
	-- print("circular_saw set to " .. modname .. " : "
	--	.. material .. " with " .. (amount) .. " microblocks.")

	-- 0-7 microblocks may remain left-over:
	inv:set_list("micro", {
		modname .. ":micro_" .. material .. " " .. (amount % 8)
	})
	-- Display:
	inv:set_list("output",
		self:get_output_inv(modname, material, amount,
				meta:get_int("max_offered")))
	-- Store how many microblocks are available:
	meta:set_int("anz", amount)

	meta:set_string("infotext",
		S("Circular Saw is working on @1",
			node_def and node_def.description or material
		) .. owned_by
	)
end

-- The amount of items offered per shape can be configured:
function circular_saw.on_receive_fields(pos, formname, fields, sender)
	local meta = minetest.get_meta(pos)
	local max = tonumber(fields.max_offered)
	if max and max > 0 then
		meta:set_string("max_offered",  max)
		-- Update to show the correct number of items:
		circular_saw:update_inventory(pos, 0)
	end
end

-- Moving the inventory of the circular_saw around is not allowed because it
-- is a fictional inventory. Moving inventory around would be rather
-- impractical and make things more difficult to calculate:
function circular_saw.allow_metadata_inventory_move(
		pos, from_list, from_index, to_list, to_index, count, player)
	return 0
end

-- Only input- and recycle-slot are intended as input slots:
function circular_saw.allow_metadata_inventory_put(
		pos, listname, index, stack, player)
	-- The player is not allowed to put something in there:
	if listname == "output" or listname == "micro" then
		return 0
	end

	local meta = minetest.get_meta(pos)
	local inv  = meta:get_inventory()
	local stackname = stack:get_name()
	local count = stack:get_count()

	-- Only allow those items that are offered in the output inventory to be recycled:
	if listname == "recycle" then
		if not inv:contains_item("output", stackname) then
			return 0
		end
		local stackmax = stack:get_stack_max()
		local instack = inv:get_stack("input", 1)
		local microstack = inv:get_stack("micro", 1)
		local incount = instack:get_count()
		local incost = (incount * 8) + microstack:get_count()
		local maxcost = (stackmax * 8) + 7
		local cost = circular_saw:get_cost(inv, stackname)
		if (incost + cost) > maxcost then
			return math.max((maxcost - incost) / cost, 0)
		end
		return count
	end

	-- Only accept certain blocks as input which are known to be craftable into stairs:
	if listname == "input" then
		if not inv:is_empty("input") then
			if inv:get_stack("input", index):get_name() ~= stackname then
				return 0
			end
		end
		if not inv:is_empty("micro") then
			local microstackname = inv:get_stack("micro", 1):get_name():gsub("^.+:micro_", "", 1)
			local cutstackname = stackname:gsub("^.+:", "", 1)
			if microstackname ~= cutstackname then
				return 0
			end
		end
		for name, t in pairs(circular_saw.known_nodes) do
			if name == stackname and inv:room_for_item("input", stack) then
				return count
			end
		end
		return 0
	end
end

-- Taking is allowed from all slots (even the internal microblock slot).
-- Putting something in is slightly more complicated than taking anything
-- because we have to make sure it is of a suitable material:
function circular_saw.on_metadata_inventory_put(
		pos, listname, index, stack, player)
	-- We need to find out if the circular_saw is already set to a
	-- specific material or not:
	local meta = minetest.get_meta(pos)
	local inv  = meta:get_inventory()
	local stackname = stack:get_name()
	local count = stack:get_count()

	-- Putting something into the input slot is only possible if that had
	-- been empty before or did contain something of the same material:
	if listname == "input" then
		-- Each new block is worth 8 microblocks:
		circular_saw:update_inventory(pos, 8 * count)
	elseif listname == "recycle" then
		-- Lets look which shape this represents:
		local cost = circular_saw:get_cost(inv, stackname)
		local input_stack = inv:get_stack("input", 1)
		-- check if this would not exceed input itemstack max_stacks
		if input_stack:get_count() + ((cost * count) / 8) <= input_stack:get_stack_max() then
			circular_saw:update_inventory(pos, cost * count)
		end
	end
end

function circular_saw.allow_metadata_inventory_take(pos, listname, index, stack, player)
	local meta          = minetest.get_meta(pos)
	local inv           = meta:get_inventory()
	local input_stack = inv:get_stack(listname,  index)
	local player_inv = player:get_inventory()
	if not player_inv:room_for_item("main", input_stack) then
		return 0
	else return stack:get_count()
	end
end

function circular_saw.on_metadata_inventory_take(
		pos, listname, index, stack, player)

	-- Prevent (inbuilt) swapping between inventories with different blocks
	-- corrupting player inventory or Saw with 'unknown' items.
	local meta          = minetest.get_meta(pos)
	local inv           = meta:get_inventory()
	local input_stack = inv:get_stack(listname,  index)
	if not input_stack:is_empty() and input_stack:get_name()~=stack:get_name() then
		local player_inv = player:get_inventory()
		if player_inv:room_for_item("main", input_stack) then
			player_inv:add_item("main", input_stack)
		end

		circular_saw:reset(pos)
		return
	end

	-- If it is one of the offered stairs: find out how many
	-- microblocks have to be subtracted:
	if listname == "output" then
		-- We do know how much each block at each position costs:
		local cost = circular_saw.cost_in_microblocks[index]
				* stack:get_count()

		circular_saw:update_inventory(pos, -cost)
	elseif listname == "micro" then
		-- Each microblock costs 1 microblock:
		circular_saw:update_inventory(pos, -stack:get_count())
	elseif listname == "input" then
		-- Each normal (= full) block taken costs 8 microblocks:
		circular_saw:update_inventory(pos, 8 * -stack:get_count())
	end
	-- The recycle field plays no role here since it is processed immediately.
end

function circular_saw.on_construct(pos)
	local meta = minetest.get_meta(pos)
	local fancy_inv = default.gui_bg..default.gui_bg_img..default.gui_slots
	meta:set_string(
		"formspec", "size[11,10]"..fancy_inv..
		"label[0,0;" ..F(S("Input\nmaterial")).. "]" ..
		"list[current_name;input;1.5,0;1,1;]" ..
		"label[0,1;" ..F(S("Left-over")).. "]" ..
		"list[current_name;micro;1.5,1;1,1;]" ..
		"label[0,2;" ..F(S("Recycle\noutput")).. "]" ..
		"list[current_name;recycle;1.5,2;1,1;]" ..
		"field[0.3,3.5;1,1;max_offered;" ..F(S("Max")).. ":;${max_offered}]" ..
		"button[1,3.2;1,1;Set;" ..F(S("Set")).. "]" ..
		"list[current_name;output;2.8,0;8,6;]" ..
		"list[current_player;main;1.5,6.25;8,4;]" ..
		"listring[current_name;output]" ..
		"listring[current_player;main]" ..
		"listring[current_name;input]" ..
		"listring[current_player;main]" ..
		"listring[current_name;micro]" ..
		"listring[current_player;main]" ..
		"listring[current_name;recycle]" ..
		"listring[current_player;main]"
	)

	meta:set_int("anz", 0) -- No microblocks inside yet.
	meta:set_string("max_offered", 99) -- How many items of this kind are offered by default?
	meta:set_string("infotext", S("Circular Saw is empty"))

	local inv = meta:get_inventory()
	inv:set_size("input", 1)    -- Input slot for full blocks of material x.
	inv:set_size("micro", 1)    -- Storage for 1-7 surplus microblocks.
	inv:set_size("recycle", 1)  -- Surplus partial blocks can be placed here.
	inv:set_size("output", 6*8) -- 6x8 versions of stair-parts of material x.

	circular_saw:reset(pos)
end

function circular_saw.can_dig(pos,player)
	local meta = minetest.get_meta(pos)
	local inv = meta:get_inventory()
	if not inv:is_empty("input") or
	   not inv:is_empty("micro") or
	   not inv:is_empty("recycle") then
		return false
	end
	-- Can be dug by anyone when empty, not only by the owner:
	return true
end

minetest.register_node("moreblocks:circular_saw",  {
	description = S("Circular Saw"),
	drawtype = "nodebox",
	node_box = {
		type = "fixed",
		fixed = {
			{-0.4, -0.5, -0.4, -0.25, 0.25, -0.25}, -- Leg
			{0.25, -0.5, 0.25, 0.4, 0.25, 0.4}, -- Leg
			{-0.4, -0.5, 0.25, -0.25, 0.25, 0.4}, -- Leg
			{0.25, -0.5, -0.4, 0.4, 0.25, -0.25}, -- Leg
			{-0.5, 0.25, -0.5, 0.5, 0.375, 0.5}, -- Tabletop
			{-0.01, 0.4375, -0.125, 0.01, 0.5, 0.125}, -- Saw blade (top)
			{-0.01, 0.375, -0.1875, 0.01, 0.4375, 0.1875}, -- Saw blade (bottom)
			{-0.25, -0.0625, -0.25, 0.25, 0.25, 0.25}, -- Motor case
		},
	},
	tiles = {"moreblocks_circular_saw_top.png",
		"moreblocks_circular_saw_bottom.png",
		"moreblocks_circular_saw_side.png"},
	paramtype = "light",
	sunlight_propagates = true,
	paramtype2 = "facedir",
	groups = {choppy = 2,oddly_breakable_by_hand = 2},
	sounds = default.node_sound_wood_defaults(),
	on_construct = circular_saw.on_construct,
	can_dig = circular_saw.can_dig,
	-- Set the owner of this circular saw.
	after_place_node = function(pos, placer)
		local meta = minetest.get_meta(pos)
		local owner = placer and placer:get_player_name() or ""
		local owned_by = owner

		if owner ~= "" then
			owned_by = (" (%s)"):format(S("owned by @1", owner))
		end

		meta:set_string("owner",  owner)
		meta:set_string("infotext", S("Circular Saw is empty") .. owned_by)
	end,

	-- The amount of items offered per shape can be configured:
	on_receive_fields = circular_saw.on_receive_fields,
	allow_metadata_inventory_move = circular_saw.allow_metadata_inventory_move,
	-- Only input- and recycle-slot are intended as input slots:
	allow_metadata_inventory_put = circular_saw.allow_metadata_inventory_put,
	allow_metadata_inventory_take = circular_saw.allow_metadata_inventory_take,
	-- Taking is allowed from all slots (even the internal microblock slot). Moving is forbidden.
	-- Putting something in is slightly more complicated than taking anything because we have to make sure it is of a suitable material:
	on_metadata_inventory_put = circular_saw.on_metadata_inventory_put,
	on_metadata_inventory_take = circular_saw.on_metadata_inventory_take,
})


code:
--[[
More Blocks: configuration handling

Copyright © 2011-2019 Hugo Locurcio and contributors.
Licensed under the zlib license. See LICENSE.md for more information.
--]]

moreblocks.config = {}

local function getbool_default(setting, default)
	local value = minetest.settings:get_bool(setting)
	if value == nil then
		value = default
	end
	return value
end

local function setting(settingtype, name, default)
	if settingtype == "bool" then
		moreblocks.config[name] =
			getbool_default("moreblocks." .. name, default)
	else
		moreblocks.config[name] =
			minetest.settings:get("moreblocks." .. name) or default
	end
end

-- Show stairs/slabs/panels/microblocks in creative inventory (true or false):
setting("bool", "stairsplus_in_creative_inventory", false)


code:
--[[
More Blocks: crafting recipes

Copyright © 2011-2019 Hugo Locurcio and contributors.
Licensed under the zlib license. See LICENSE.md for more information.
--]]

minetest.register_craft({
	output = "default:stick",
	recipe = {{"default:dry_shrub"},}
})

minetest.register_craft({
	output = "default:stick",
	recipe = {{"group:sapling"},}
})

minetest.register_craft({
	output = "default:wood",
	recipe = {
		{"default:stick", "default:stick"},
		{"default:stick", "default:stick"},
	}
})

minetest.register_craft({
	output = "default:dirt_with_grass",
	type = "shapeless",
	recipe = {"default:junglegrass", "default:dirt"},
})

minetest.register_craft({
	output = "default:mossycobble",
	type = "shapeless",
	recipe = {"default:junglegrass", "default:cobble"},
})

minetest.register_craft({
	output = "moreblocks:wood_tile 9",
	recipe = {
		{"group:wood", "group:wood", "group:wood"},
		{"group:wood", "group:wood", "group:wood"},
		{"group:wood", "group:wood", "group:wood"},
	}
})

-- This must be registered after `moreblocks:wood_tile` to avoid recipe conflicts,
-- since `moreblocks:wood_tile` is part of `group:wood`
minetest.register_craft({
	output = "moreblocks:wood_tile_center 9",
	recipe = {
		{"group:wood", "group:wood", "group:wood"},
		{"group:wood", "moreblocks:wood_tile", "group:wood"},
		{"group:wood", "group:wood", "group:wood"},
	}
})

minetest.register_craft({
	type = "shapeless",
	output = "moreblocks:wood_tile",
	recipe = {"moreblocks:wood_tile_flipped"}
})

minetest.register_craft({
	output = "moreblocks:wood_tile_full 4",
	recipe = {
		{"moreblocks:wood_tile", "moreblocks:wood_tile"},
		{"moreblocks:wood_tile", "moreblocks:wood_tile"},
	}
})

minetest.register_craft({
	output = "moreblocks:wood_tile_offset",
	recipe = {
		{"default:stick"},
		{"moreblocks:wood_tile_center"},
	}
})

minetest.register_craft({
	type = "shapeless",
	output = "moreblocks:wood_tile_offset",
	recipe = {"moreblocks:wood_tile_down"}
})

minetest.register_craft({
	type = "shapeless",
	output = "moreblocks:wood_tile_offset",
	recipe = {"moreblocks:wood_tile_left"}
})

minetest.register_craft({
	type = "shapeless",
	output = "moreblocks:wood_tile_offset",
	recipe = {"moreblocks:wood_tile_right"}
})

minetest.register_craft({
	output = "moreblocks:circle_stone_bricks 5",
	recipe = {
		{"", "default:stone", ""},
		{"default:stone", "default:coal_lump", "default:stone"},
		{"", "default:stone", ""},
	}
})

minetest.register_craft({
	output = "moreblocks:all_faces_tree 8",
	recipe = {
		{"default:tree", "default:tree", "default:tree"},
		{"default:tree", "", "default:tree"},
		{"default:tree", "default:tree", "default:tree"},
	}
})

minetest.register_craft({
	output = "moreblocks:all_faces_jungle_tree 8",
	recipe = {
		{"default:jungletree", "default:jungletree", "default:jungletree"},
		{"default:jungletree", "", "default:jungletree"},
		{"default:jungletree", "default:jungletree", "default:jungletree"},
	}
})

minetest.register_craft({
	output = "moreblocks:all_faces_pine_tree 8",
	recipe = {
		{"default:pine_tree", "default:pine_tree", "default:pine_tree"},
		{"default:pine_tree", "", "default:pine_tree"},
		{"default:pine_tree", "default:pine_tree", "default:pine_tree"},
	}
})

minetest.register_craft({
	output = "moreblocks:all_faces_acacia_tree 8",
	recipe = {
		{"default:acacia_tree", "default:acacia_tree", "default:acacia_tree"},
		{"default:acacia_tree", "", "default:acacia_tree"},
		{"default:acacia_tree", "default:acacia_tree", "default:acacia_tree"},
	}
})

minetest.register_craft({
	output = "moreblocks:all_faces_aspen_tree 8",
	recipe = {
		{"default:aspen_tree", "default:aspen_tree", "default:aspen_tree"},
		{"default:aspen_tree", "", "default:aspen_tree"},
		{"default:aspen_tree", "default:aspen_tree", "default:aspen_tree"},
	}
})

minetest.register_craft({
	output = "moreblocks:sweeper 4",
	recipe = {
		{"default:junglegrass"},
		{"default:stick"},
	}
})

minetest.register_craft({
	output = "moreblocks:stone_tile 9",
	recipe = {
		{"default:cobble", "default:cobble", "default:cobble"},
		{"default:cobble", "default:stone", "default:cobble"},
		{"default:cobble", "default:cobble", "default:cobble"},
	}
})

minetest.register_craft({
	output = "moreblocks:split_stone_tile",
	recipe = {
		{"moreblocks:stone_tile"},
	}
})

minetest.register_craft({
	output = "moreblocks:checker_stone_tile",
	recipe = {
		{"moreblocks:split_stone_tile"},
	}
})

-- When approaching the below craft, loop back to cobblestone, which can then be used to craft stone tiles again
minetest.register_craft({
	output = "default:cobble",
	recipe = {
		{"moreblocks:checker_stone_tile"},
	}
})

minetest.register_craft({
	output = "moreblocks:grey_bricks 2",
	type = "shapeless",
	recipe =  {"default:stone", "default:brick"},
})

minetest.register_craft({
	output = "moreblocks:grey_bricks 2",
	type = "shapeless",
	recipe =  {"default:stonebrick", "default:brick"},
})

minetest.register_craft({
	output = "moreblocks:empty_shelf",
	type = "shapeless",
	recipe = {"moreblocks:sweeper", "default:bookshelf"},
	replacements = {{"default:bookshelf", "default:book 3"}},
	-- When obtaining an empty shelf, return the books used in it as well
})

minetest.register_craft({
	output = "moreblocks:empty_shelf",
	type = "shapeless",
	recipe = {"moreblocks:sweeper", "vessels:shelf"},
	replacements = {{"vessels:shelf", "vessels:glass_bottle 3"}},
})

minetest.register_craft({
	type = "shapeless",
	output = "default:bookshelf",
	recipe = {"moreblocks:empty_shelf", "default:book", "default:book", "default:book"},
})

minetest.register_craft({
	output = "moreblocks:empty_shelf",
	recipe = {
		{"group:wood", "group:wood", "group:wood"},
		{"", "", ""},
		{"group:wood", "group:wood", "group:wood"},
	}
})

minetest.register_craft({
	output = "moreblocks:coal_stone_bricks 4",
	recipe = {
		{"moreblocks:coal_stone", "moreblocks:coal_stone"},
		{"moreblocks:coal_stone", "moreblocks:coal_stone"},
	}
})

minetest.register_craft({
	output = "moreblocks:iron_stone_bricks 4",
	recipe = {
		{"moreblocks:iron_stone", "moreblocks:iron_stone"},
		{"moreblocks:iron_stone", "moreblocks:iron_stone"},
	}
})

minetest.register_craft({
	output = "moreblocks:plankstone 4",
	recipe = {
		{"group:stone", "group:wood"},
		{"group:wood", "group:stone"},
	}
})

minetest.register_craft({
	output = "moreblocks:plankstone 4",
	recipe = {
		{"group:wood", "group:stone"},
		{"group:stone", "group:wood"},
	}
})

minetest.register_craft({
	output = "moreblocks:coal_checker 4",
	recipe = {
		{"default:stone", "default:coal_lump"},
		{"default:coal_lump", "default:stone"},
	}
})

minetest.register_craft({
	output = "moreblocks:coal_checker 4",
	recipe = {
		{"default:coal_lump", "default:stone"},
		{"default:stone", "default:coal_lump"},
	}
})

minetest.register_craft({
	output = "moreblocks:iron_checker 4",
	recipe = {
		{"default:steel_ingot", "default:stone"},
		{"default:stone", "default:steel_ingot"},
	}
})

minetest.register_craft({
	output = "moreblocks:iron_checker 4",
	recipe = {
		{"default:stone", "default:steel_ingot"},
		{"default:steel_ingot", "default:stone"},
	}
})

minetest.register_craft({
	output = "default:chest_locked",
	type = "shapeless",
	recipe = {"default:steel_ingot", "default:chest"},
})
minetest.register_craft({
	output = "default:chest_locked",
	type = "shapeless",
	recipe = {"default:copper_ingot", "default:chest"},
})

minetest.register_craft({
	output = "default:chest_locked",
	type = "shapeless",
	recipe = {"default:bronze_ingot", "default:chest"},
})

minetest.register_craft({
	output = "default:chest_locked",
	type = "shapeless",
	recipe = {"default:gold_ingot", "default:chest"},
})

minetest.register_craft({
	output = "moreblocks:iron_glass",
	type = "shapeless",
	recipe = {"default:steel_ingot", "default:glass"},
})

minetest.register_craft({
	output = "default:glass",
	type = "shapeless",
	recipe = {"default:coal_lump", "moreblocks:iron_glass"},
})

minetest.register_craft({
	output = "moreblocks:coal_glass",
	type = "shapeless",
	recipe = {"default:coal_lump", "default:glass"},
})

minetest.register_craft({
	output = "default:glass",
	type = "shapeless",
	recipe = {"default:steel_ingot", "moreblocks:coal_glass"},
})

minetest.register_craft({
	output = "moreblocks:clean_glass",
	type = "shapeless",
	recipe = {"moreblocks:sweeper", "default:glass"},
})

minetest.register_craft({
	output = "moreblocks:glow_glass",
	type = "shapeless",
	recipe = {"default:mese_crystal_fragment", "default:glass"},
})

minetest.register_craft({
	output = "moreblocks:trap_glow_glass",
	type = "shapeless",
	recipe = {"default:mese_crystal_fragment", "default:glass", "default:torch"},
})

minetest.register_craft({
	output = "moreblocks:trap_glow_glass",
	type = "shapeless",
	recipe = {"default:torch", "moreblocks:glow_glass"},
})

minetest.register_craft({
	output = "moreblocks:super_glow_glass",
	type = "shapeless",
	recipe = {"default:mese_crystal_fragment", "default:mese_crystal_fragment", "default:glass"},
})

minetest.register_craft({
	output = "moreblocks:super_glow_glass",
	type = "shapeless",
	recipe = {"default:mese_crystal_fragment", "moreblocks:glow_glass"},
})

minetest.register_craft({
	output = "moreblocks:trap_super_glow_glass",
	type = "shapeless",
	recipe = {"default:mese_crystal_fragment", "default:glass", "default:mese_crystal_fragment", "default:torch"},
})

minetest.register_craft({
	output = "moreblocks:trap_super_glow_glass",
	type = "shapeless",
	recipe = {"default:torch", "moreblocks:super_glow_glass"},
})

minetest.register_craft({
	output = "moreblocks:coal_stone",
	type = "shapeless",
	recipe = {"default:coal_lump", "default:stone"},
})

minetest.register_craft({
	output = "default:stone",
	type = "shapeless",
	recipe = {"default:steel_ingot", "moreblocks:coal_stone"},
})

minetest.register_craft({
	output = "moreblocks:iron_stone",
	type = "shapeless",
	recipe = {"default:steel_ingot", "default:stone"},
})

minetest.register_craft({
	output = "default:stone",
	type = "shapeless",
	recipe = {"default:coal_lump", "moreblocks:iron_stone"},
})

minetest.register_craft({
	output = "moreblocks:trap_stone",
	type = "shapeless",
	recipe = {"default:mese_crystal_fragment", "default:stone"},
})

minetest.register_craft({
	output = "moreblocks:trap_desert_stone",
	type = "shapeless",
	recipe = {"default:mese_crystal_fragment", "default:desert_stone"},
})

minetest.register_craft({
	output = "moreblocks:trap_glass",
	type = "shapeless",
	recipe = {"default:torch", "default:glass"},
})

minetest.register_craft({
	output = "moreblocks:trap_obsidian_glass",
	type = "shapeless",
	recipe = {"default:mese_crystal_fragment", "default:obsidian_glass"},
})

minetest.register_craft({
	output = "moreblocks:trap_obsidian",
	type = "shapeless",
	recipe = {"default:mese_crystal_fragment", "default:obsidian"},
})

minetest.register_craft({
	output = "moreblocks:trap_sandstone",
	type = "shapeless",
	recipe = {"default:mese_crystal_fragment", "default:sandstone"},
})

minetest.register_craft({
	output = "moreblocks:cactus_brick",
	type = "shapeless",
	recipe = {"default:cactus", "default:brick"},
})

minetest.register_craft({
	output = "moreblocks:cactus_checker 4",
	recipe = {
		{"default:cactus", "default:stone"},
		{"default:stone", "default:cactus"},
	}
})

minetest.register_craft({
	output = "moreblocks:cactuschecker 4",
	recipe = {
		{"default:stone", "default:cactus"},
		{"default:cactus", "default:stone"},
	}
})

minetest.register_craft({
	output = "moreblocks:rope 3",
	recipe = {
		{"default:junglegrass"},
		{"default:junglegrass"},
		{"default:junglegrass"},
	}
})

minetest.register_craft({
	output = "moreblocks:dirt_compressed",
	recipe = {
		{'default:dirt', 'default:dirt', 'default:dirt'},
		{'default:dirt', 'default:dirt', 'default:dirt'},
		{'default:dirt', 'default:dirt', 'default:dirt'},
	}
})

minetest.register_craft({
	output = "default:dirt 9",
	recipe = {{"moreblocks:dirt_compressed"}},
})

minetest.register_craft({
	output = "moreblocks:cobble_compressed",
	recipe = {
		{"default:cobble", "default:cobble", "default:cobble"},
		{"default:cobble", "default:cobble", "default:cobble"},
		{"default:cobble", "default:cobble", "default:cobble"},
	}
})

minetest.register_craft({
	output = "default:cobble 9",
	recipe = {
		{"moreblocks:cobble_compressed"},
	}
})

minetest.register_craft({
	type = "cooking", output = "moreblocks:tar", recipe = "default:pine_tree",
})

minetest.register_craft({
	type = "shapeless",
	output = "moreblocks:copperpatina",
	recipe = {"group:water_bucket", "default:copperblock"},
	replacements = {
		{"group:water_bucket", "mesecraft_bucket:bucket_empty"}
	}
})

minetest.register_craft({
	output = "default:copper_ingot 9",
	recipe = {
		{"moreblocks:copperpatina"},
	}
})

if minetest.settings:get_bool("moreblocks.circular_saw_crafting") ~= false then -- “If nil or true then”
	minetest.register_craft({
		output = "moreblocks:circular_saw",
		recipe = {
			{ "",  "default:steel_ingot",  "" },
			{ "group:wood",  "group:wood",  "group:wood"},
			{ "group:wood",  "",  "group:wood"},
		}
	})
end


code:
--[[
=====================================================================
** More Blocks **
By Calinou, with the help of ShadowNinja and VanessaE.

Copyright © 2011-2019 Hugo Locurcio and contributors.
Licensed under the zlib license. See LICENSE.md for more information.
=====================================================================
--]]

moreblocks = {}

local modpath = minetest.get_modpath("moreblocks")

local S, NS = dofile(modpath .. "/intllib.lua")
moreblocks.S = S
moreblocks.NS = NS

dofile(modpath .. "/config.lua")
dofile(modpath .. "/circular_saw.lua")
dofile(modpath .. "/stairsplus/init.lua")
dofile(modpath .. "/nodes.lua")
dofile(modpath .. "/redefinitions.lua")
dofile(modpath .. "/crafting.lua")
dofile(modpath .. "/aliases.lua")


code:
-- Fallback functions for when `intllib` is not installed.
-- Code released under Unlicense <http://unlicense.org>.

-- Get the latest version of this file at:
--   https://raw.githubusercontent.com/minetest-mods/intllib/master/lib/intllib.lua

local function format(str, ...)
	local args = { ... }
	local function repl(escape, open, num, close)
		if escape == "" then
			local replacement = tostring(args[tonumber(num)])
			if open == "" then
				replacement = replacement..close
			end
			return replacement
		else
			return "@"..open..num..close
		end
	end
	return (str:gsub("(@?)@(%(?)(%d+)(%)?)", repl))
end

local gettext, ngettext
if minetest.get_modpath("intllib") then
	if intllib.make_gettext_pair then
		-- New method using gettext.
		gettext, ngettext = intllib.make_gettext_pair()
	else
		-- Old method using text files.
		gettext = intllib.Getter()
	end
end

-- Fill in missing functions.

gettext = gettext or function(msgid, ...)
	return format(msgid, ...)
end

ngettext = ngettext or function(msgid, msgid_plural, n, ...)
	return format(n==1 and msgid or msgid_plural, ...)
end

return gettext, ngettext


code:
# German translation for More Blocks.
# Copyright © 2011-2019 Hugo Locurcio and contributors
# This file is distributed under the same license as the More Blocks package.
# Xanthin, 2014.
# CodeXP <codexp@gmx.net>, 2018.
msgid ""
msgstr ""
"Project-Id-Version: More Blocks\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-07-13 12:37+0200\n"
"PO-Revision-Date: \n"
"Last-Translator: CodeXP <codexp@gmx.net>\n"
"Language-Team: \n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

#: circular_saw.lua
msgid "Circular Saw"
msgstr "Kreissäge"

#: circular_saw.lua
msgid ""
"Input\n"
"material"
msgstr ""
"Ausgangs-\n"
"material"

#: circular_saw.lua
msgid "Left-over"
msgstr "Rest"

#: circular_saw.lua
msgid "Max"
msgstr "Anzahl"

#: circular_saw.lua
msgid ""
"Recycle\n"
"output"
msgstr ""
"Wiederver-\n"
"werten"

#: circular_saw.lua
msgid "Set"
msgstr "Ok"

#: circular_saw.lua
msgid "owned by @1"
msgstr "gehört @1"

#: circular_saw.lua
msgid "Circular Saw is empty"
msgstr "Kreissäge ist leer"

#: circular_saw.lua
msgid "Circular Saw is working on @1"
msgstr "Kreissäge arbeitet mit @1"

#: init.lua
msgid "[moreblocks] loaded."
msgstr "[moreblocks] geladen."

#: nodes.lua
msgid "Deprecated"
msgstr "veraltet"

#: nodes.lua
msgid "All-faces Acacia Tree"
msgstr "allseitiger Akazienbaumstamm"

#: nodes.lua
msgid "All-faces Aspen Tree"
msgstr "allseitiger Espenbaumstamm"

#: nodes.lua
msgid "All-faces Jungle Tree"
msgstr "allseitiger Tropenbaumstamm"

#: nodes.lua
msgid "All-faces Pine Tree"
msgstr "allseitiger Kieferbaumstamm"

#: nodes.lua
msgid "All-faces Tree"
msgstr "allseitiger Baumstamm"

#: nodes.lua
msgid "Cactus Brick"
msgstr "Kaktusziegel"

#: nodes.lua
msgid "Cactus Checker"
msgstr "Kaktus-Mosaik"

#: nodes.lua
msgid "Centered Wooden Tile"
msgstr "Holzfliese mittig"

#: nodes.lua
msgid "Checker Stone Tile"
msgstr "Stein-Mosaik"

#: nodes.lua
msgid "Circle Stone Bricks"
msgstr "Kreissteinziegel"

#: nodes.lua
msgid "Clean Glass"
msgstr "Klares Glas"

#: nodes.lua
msgid "Coal Checker"
msgstr "Kohlen-Mosaik"

#: nodes.lua
msgid "Coal Glass"
msgstr "Kohleglas"

#: nodes.lua
msgid "Coal Stone"
msgstr "Kohlestein"

#: nodes.lua
msgid "Coal Stone Bricks"
msgstr "Kohlesteinziegel"

#: nodes.lua
msgid "Compressed Cobblestone"
msgstr "Gepresster Kopfsteinpflaster"

#: nodes.lua
msgid "Compressed Dirt"
msgstr "Gepresste Erde"

#: nodes.lua
msgid "Copper Patina Block"
msgstr "Kupfer Edelrostblock"

#: nodes.lua
msgid "Empty Shelf"
msgstr "Leeres Regal"

#: nodes.lua
msgid "Full Wooden Tile"
msgstr "Vollholzfliese"

#: nodes.lua
msgid "Glow Glass"
msgstr "Leuchtglas"

#: nodes.lua
msgid "Iron Checker"
msgstr "Metall-Mosaik"

#: nodes.lua
msgid "Iron Glass"
msgstr "metallisiertes Glas"

#: nodes.lua
msgid "Iron Stone"
msgstr "Eisenstein"

#: nodes.lua
msgid "Iron Stone Bricks"
msgstr "Eisensteinziegel"

#: nodes.lua
msgid "Plankstone"
msgstr "Brettstein"

#: nodes.lua
msgid "Rope"
msgstr "Seil"

#: nodes.lua
msgid "Split Stone Tile"
msgstr "Geteilte Steinfliese"

#: nodes.lua
msgid "Stone Bricks"
msgstr "Steinziegel"

#: nodes.lua
msgid "Stone Tile"
msgstr "Steinfliese"

#: nodes.lua
msgid "Super Glow Glass"
msgstr "Superleuchtglas"

#: nodes.lua
msgid "Sweeper"
msgstr "Besen"

#: nodes.lua
msgid "Tar"
msgstr "Teer"

#: nodes.lua
msgid "Trap Desert Stone"
msgstr "Wüstensteinfalle"

#: nodes.lua
msgid "Trap Glass"
msgstr "Glasfalle"

#: nodes.lua
msgid "Trap Glow Glass"
msgstr "Leuchtglasfalle"

#: nodes.lua
msgid "Trap Obsidian"
msgstr "Obsidianfalle"

#: nodes.lua
msgid "Trap Obsidian Glass"
msgstr "Obsidianglasfalle"

#: nodes.lua
msgid "Trap Sandstone"
msgstr "Sandsteinfalle"

#: nodes.lua
msgid "Trap Stone"
msgstr "Steinfalle"

#: nodes.lua
msgid "Trap Super Glow Glass"
msgstr "Superleuchtglasfalle"

#: nodes.lua
msgid "Wooden Tile"
msgstr "Holzfliese"

#: nodes.lua
msgid "Offset Wooden Tile"
msgstr "Holzfliese versetzt"

#: nodes.lua
msgid "Downwards Wooden Tile"
msgstr "Holzfliese unten"

#: nodes.lua
msgid "Leftwards Wooden Tile"
msgstr "Holzfliese links"

#: nodes.lua
msgid "Rightwards Wooden Tile"
msgstr "Holzfliese rechts"

#: ownership.lua
msgid "Sorry, @1 owns that spot."
msgstr "Tut mir leid, dieser Bereich gehört @1."

#: ownership.lua
msgid "someone"
msgstr "jemand"

#: stairsplus/common.lua
#, lua-format
msgid "%s Microblock"
msgstr "%smikroblock"

#: stairsplus/common.lua stairsplus/slabs.lua
#, lua-format
msgid "%s Slab"
msgstr "%splatte"

#: stairsplus/common.lua
#, lua-format
msgid "%s Slope"
msgstr "%sneigung"

#: stairsplus/common.lua
#, lua-format
msgid "%s Panel"
msgstr "%spaneel"

#: stairsplus/common.lua
#, lua-format
msgid "%s Stairs"
msgstr "%streppe"