local S = ...

local function get_stair_param(node)
	local stair = core.get_item_group(node.name, "stair")
	if stair == 2 then
		if node.param2 < 12 then
			return node.param2 + 4
		else
			return node.param2 - 4
		end
	elseif stair == 3 then
		if node.param2 < 12 then
			return node.param2 + 8
		else
			return node.param2 - 8
		end
	end
	return node.param2
end

local function get_stair_from_param(param, stairs)
	if param < 12 then
		if param < 4 then
			return {name = stairs[1], param2 = param}
		elseif param < 8 then
			return {name = stairs[2], param2 = param - 4}
		else
			return {name = stairs[3], param2 = param - 8}
		end
	else
		if param >= 20 then
			return {name = stairs[1], param2 = param}
		elseif param >= 16 then
			return {name = stairs[2], param2 = param + 4}
		else
			return {name = stairs[3], param2 = param + 8}
		end
	end
end

local function stair_param_to_connect(param, ceiling)
	local out = {false, false, false, false, false, false, false, false}
	if not ceiling then
		if param == 0 then
			out[3] = true
			out[8] = true
		elseif param == 1 then
			out[2] = true
			out[5] = true
		elseif param == 2 then
			out[4] = true
			out[7] = true
		elseif param == 3 then
			out[1] = true
			out[6] = true
		elseif param == 4 then
			out[1] = true
			out[8] = true
		elseif param == 5 then
			out[2] = true
			out[3] = true
		elseif param == 6 then
			out[4] = true
			out[5] = true
		elseif param == 7 then
			out[6] = true
			out[7] = true
		elseif param == 8 then
			out[3] = true
			out[6] = true
		elseif param == 9 then
			out[5] = true
			out[8] = true
		elseif param == 10 then
			out[2] = true
			out[7] = true
		elseif param == 11 then
			out[1] = true
			out[4] = true
		end
	else
		if param == 12 then
			out[5] = true
			out[8] = true
		elseif param == 13 then
			out[3] = true
			out[6] = true
		elseif param == 14 then
			out[1] = true
			out[4] = true
		elseif param == 15 then
			out[2] = true
			out[7] = true
		elseif param == 16 then
			out[2] = true
			out[3] = true
		elseif param == 17 then
			out[1] = true
			out[8] = true
		elseif param == 18 then
			out[6] = true
			out[7] = true
		elseif param == 19 then
			out[4] = true
			out[5] = true
		elseif param == 20 then
			out[3] = true
			out[8] = true
		elseif param == 21 then
			out[1] = true
			out[6] = true
		elseif param == 22 then
			out[4] = true
			out[7] = true
		elseif param == 23 then
			out[2] = true
			out[5] = true
		end
	end
	return out
end

local function stair_connect_to_param(connect, ceiling)
	local param
	if not ceiling then
		if connect[3] and connect[8] then
			param = 0
		elseif connect[2] and connect[5] then
			param = 1
		elseif connect[4] and connect[7] then
			param = 2
		elseif connect[1] and connect[6] then
			param = 3
		elseif connect[1] and connect[8] then
			param = 4
		elseif connect[2] and connect[3] then
			param = 5
		elseif connect[4] and connect[5] then
			param = 6
		elseif connect[6] and connect[7] then
			param = 7
		elseif connect[3] and connect[6] then
			param = 8
		elseif connect[5] and connect[8] then
			param = 9
		elseif connect[2] and connect[7] then
			param = 10
		elseif connect[1] and connect[4] then
			param = 11
		end
	else
		if connect[5] and connect[8] then
			param = 12
		elseif connect[3] and connect[6] then
			param = 13
		elseif connect[1] and connect[4] then
			param = 14
		elseif connect[2] and connect[7] then
			param = 15
		elseif connect[2] and connect[3] then
			param = 16
		elseif connect[1] and connect[8] then
			param = 17
		elseif connect[6] and connect[7] then
			param = 18
		elseif connect[4] and connect[5] then
			param = 19
		elseif connect[3] and connect[8] then
			param = 20
		elseif connect[1] and connect[6] then
			param = 21
		elseif connect[4] and connect[7] then
			param = 22
		elseif connect[2] and connect[5] then
			param = 23
		end
	end
	return param
end

local function after_dig_node(pos, oldnode)
	local param = get_stair_param(oldnode)
	local ceiling
	if param < 12 then
		ceiling = false
	else
		ceiling = true
	end
	local connect = stair_param_to_connect(param, ceiling)
	local t = {
		{pos = {x = pos.x, y = pos.y, z = pos.z + 2}},
		{pos = {x = pos.x - 1, y = pos.y, z = pos.z + 1}},
		{pos = {x = pos.x, y = pos.y, z = pos.z + 1}},
		{pos = {x = pos.x + 1, y = pos.y, z = pos.z + 1}},
		{pos = {x = pos.x - 2, y = pos.y, z = pos.z}},
		{pos = {x = pos.x - 1, y = pos.y, z = pos.z}},
		{pos = pos, connect = connect},
		{pos = {x = pos.x + 1, y = pos.y, z = pos.z}},
		{pos = {x = pos.x + 2, y = pos.y, z = pos.z}},
		{pos = {x = pos.x - 1, y = pos.y, z = pos.z - 1}},
		{pos = {x = pos.x, y = pos.y, z = pos.z - 1}},
		{pos = {x = pos.x + 1, y = pos.y, z = pos.z - 1}},
		{pos = {x = pos.x, y = pos.y, z = pos.z - 2}}
	}
	for i,v in ipairs(t) do
		if not v.connect then
			local node = core.get_node(v.pos)
			local node_def = core.registered_nodes[node.name]
			if not node_def then
				return
			end
			if node_def._stairs then
				t[i].stairs = node_def._stairs
				t[i].connect = stair_param_to_connect(get_stair_param(node), ceiling)
			else
				t[i].connect = {false, false, false, false, false, false, false, false}
			end
		end
	end
	local function swap_stair(index, n1, n2)
		local connect = {false, false, false, false, false, false, false, false}
		connect[n1] = true
		connect[n2] = true
		local node = get_stair_from_param(stair_connect_to_param(connect, ceiling), t[index].stairs)
		if core.get_meta(t[index].pos):get_int("screwdriver:fixed") <= 0 then
			core.swap_node(t[index].pos, node)
		end
	end
	if t[3].stairs then
		if t[7].connect[1] and t[3].connect[6] then
			if t[3].connect[1] and t[1].connect[6] then
				if t[2].connect[3] then
					swap_stair(3, 1, 8)
				elseif t[4].connect[7] then
					swap_stair(3, 1, 4)
				end
			elseif t[3].connect[7] then
				swap_stair(3, 4, 7)
			elseif t[3].connect[3] then
				swap_stair(3, 3, 8)
			end
		elseif t[7].connect[2] and t[3].connect[5] then
			if t[3].connect[2] and t[1].connect[5] then
				if t[4].connect[8] then
					swap_stair(3, 2, 3)
				elseif t[2].connect[4] then
					swap_stair(3, 2, 7)
				end
			elseif t[3].connect[4] then
				swap_stair(3, 4, 7)
			elseif t[3].connect[8] then
				swap_stair(3, 3, 8)
			end
		end
	end
	if t[8].stairs then
		if t[7].connect[3] and t[8].connect[8] then
			if t[8].connect[3] and t[9].connect[8] then
				if t[4].connect[5] then
					swap_stair(8, 2, 3)
				elseif t[12].connect[1] then
					swap_stair(8, 3, 6)
				end
			elseif t[8].connect[1] then
				swap_stair(8, 1, 6)
			elseif t[8].connect[5] then
				swap_stair(8, 2, 5)
			end
		elseif t[7].connect[4] and t[8].connect[7] then
			if t[8].connect[4] and t[9].connect[7] then
				if t[12].connect[2] then
					swap_stair(8, 4, 5)
				elseif t[4].connect[6] then
					swap_stair(8, 1, 4)
				end
			elseif t[8].connect[6] then
				swap_stair(8, 1, 6)
			elseif t[8].connect[2] then
				swap_stair(8, 2, 5)
			end
		end
	end
	if t[11].stairs then
		if t[7].connect[5] and t[11].connect[2] then
			if t[11].connect[5] and t[13].connect[2] then
				if t[12].connect[7] then
					swap_stair(11, 4, 5)
				elseif t[10].connect[3] then
					swap_stair(11, 5, 8)
				end
			elseif t[11].connect[3] then
				swap_stair(11, 3, 8)
			elseif t[11].connect[7] then
				swap_stair(11, 4, 7)
			end
		elseif t[7].connect[6] and t[11].connect[1] then
			if t[11].connect[6] and t[13].connect[1] then
				if t[10].connect[4] then
					swap_stair(11, 6, 7)
				elseif t[12].connect[8] then
					swap_stair(11, 3, 6)
				end
			elseif t[11].connect[8] then
				swap_stair(11, 3, 8)
			elseif t[11].connect[4] then
				swap_stair(11, 4, 7)
			end
		end
	end
	if t[6].stairs then
		if t[7].connect[7] and t[6].connect[4] then
			if t[6].connect[7] and t[5].connect[4] then
				if t[10].connect[1] then
					swap_stair(6, 6, 7)
				elseif t[2].connect[5] then
					swap_stair(6, 2, 7)
				end
			elseif t[6].connect[5] then
				swap_stair(6, 2, 5)
			elseif t[6].connect[1] then
				swap_stair(6, 1, 6)
			end
		elseif t[7].connect[8] and t[6].connect[3] then
			if t[6].connect[8] and t[5].connect[3] then
				if t[2].connect[6] then
					swap_stair(6, 1, 8)
				elseif t[10].connect[2] then
					swap_stair(6, 5, 8)
				end
			elseif t[6].connect[2] then
				swap_stair(6, 2, 5)
			elseif t[6].connect[6] then
				swap_stair(6, 1, 6)
			end
		end
	end
end

local function after_place_node(pos, placer, itemstack, pointed_thing)
	local node = core.get_node(pos)
	local ceiling = false
	if placer:get_look_vertical() < 0 then
		ceiling = true
		if node.param2 == 0 then node.param2 = 20
		elseif node.param2 == 1 then node.param2 = 23
		elseif node.param2 == 2 then node.param2 = 22
		elseif node.param2 == 3 then node.param2 = 21
		end
	end
	local def = core.registered_nodes[node.name]
	local connect = stair_param_to_connect(get_stair_param(node), ceiling)
	local t = {
		{pos = {x = pos.x - 1, y = pos.y, z = pos.z + 1}},
		{pos = {x = pos.x, y = pos.y, z = pos.z + 1}},
		{pos = {x = pos.x + 1, y = pos.y, z = pos.z + 1}},
		{pos = {x = pos.x - 1, y = pos.y, z = pos.z}},
		{pos = pos, stairs = {node.name, def._stairs[2], def._stairs[3]}, connect = connect},
		{pos = {x = pos.x + 1, y = pos.y, z = pos.z}},
		{pos = {x = pos.x - 1, y = pos.y, z = pos.z - 1}},
		{pos = {x = pos.x, y = pos.y, z = pos.z - 1}},
		{pos = {x = pos.x + 1, y = pos.y, z = pos.z - 1}},
	}
	for i,v in ipairs(t) do
		if not v.connect then
			local node = core.get_node(v.pos)
			local node_def = core.registered_nodes[node.name]
			if not node_def then
				return
			end
			if node_def._stairs then
				t[i].stairs = node_def._stairs
				t[i].connect = stair_param_to_connect(get_stair_param(node), ceiling)
			else
				t[i].connect = {false, false, false, false, false, false, false, false}
			end
		end
	end
	local function reset_node(n1, n2)
		local connect = {false, false, false, false, false, false, false, false}
		connect[n1] = true
		connect[n2] = true
		node = get_stair_from_param(stair_connect_to_param(connect, ceiling), t[5].stairs)
	end
	local function swap_stair(index, n1, n2)
		local connect = {false, false, false, false, false, false, false, false}
		connect[n1] = true
		connect[n2] = true
		local node = get_stair_from_param(stair_connect_to_param(connect, ceiling), t[index].stairs)
		t[index].connect = connect
		if core.get_meta(t[index].pos):get_int("screwdriver:fixed") <= 0 then
			core.swap_node(t[index].pos, node)
		end
	end
	if connect[3] then
		if t[4].connect[2] and t[4].connect[5] and t[1].connect[5] and not t[7].connect[2] then
			swap_stair(4, 2, 3)
		elseif t[4].connect[1] and t[4].connect[6] and t[7].connect[1] and not t[1].connect[6] then
			swap_stair(4, 3, 6)
		end
		if t[6].connect[1] and t[6].connect[6] and t[3].connect[6] and not t[9].connect[1] then
			swap_stair(6, 1, 8)
		elseif t[6].connect[2] and t[6].connect[5] and t[9].connect[2] and not t[3].connect[5] then
			swap_stair(6, 5, 8)
		end
		if t[4].connect[3] ~= t[6].connect[8] then
			if t[4].connect[3] then
				if t[2].connect[6] then
					reset_node(1, 8)
				elseif t[8].connect[2] then
					reset_node(5, 8)
				elseif t[2].connect[4] and t[2].connect[7] and t[1].connect[4] and not t[3].connect[7] then
					swap_stair(2, 6, 7)
					reset_node(1, 8)
				elseif t[2].connect[3] and t[2].connect[8] and t[3].connect[8] and not t[1].connect[3] then
					swap_stair(2, 3, 6)
					reset_node(1, 8)
				elseif t[8].connect[3] and t[8].connect[8] and t[9].connect[8] and not t[7].connect[3] then
					swap_stair(8, 2, 3)
					reset_node(5, 8)
				elseif t[8].connect[4] and t[8].connect[7] and t[7].connect[4] and not t[9].connect[7] then
					swap_stair(8, 2, 7)
					reset_node(5, 8)
				end
			else
				if t[2].connect[5] then
					reset_node(2, 3)
				elseif t[8].connect[1] then
					reset_node(3, 6)
				elseif t[2].connect[4] and t[2].connect[7] and t[3].connect[7] and not t[1].connect[4] then
					swap_stair(2, 4, 5)
					reset_node(2, 3)
				elseif t[2].connect[3] and t[2].connect[8] and t[1].connect[3] and not t[3].connect[8] then
					swap_stair(2, 5, 8)
					reset_node(2, 3)
				elseif t[8].connect[3] and t[8].connect[8] and t[7].connect[3] and not t[9].connect[8] then
					swap_stair(8, 1, 8)
					reset_node(3, 6)
				elseif t[8].connect[4] and t[8].connect[7] and t[9].connect[7] and not t[7].connect[4] then
					swap_stair(8, 1, 4)
					reset_node(3, 6)
				end
			end
		end
	elseif connect[2] then
		if t[2].connect[4] and t[2].connect[7] and t[3].connect[7] and not t[1].connect[4] then
			swap_stair(2, 4, 5)
		elseif t[2].connect[3] and t[2].connect[8] and t[1].connect[3] and not t[3].connect[8] then
			swap_stair(2, 5, 8)
		end
		if t[8].connect[3] and t[8].connect[8] and t[9].connect[8] and not t[7].connect[3] then
			swap_stair(8, 2, 3)
		elseif t[8].connect[4] and t[8].connect[7] and t[7].connect[4] and not t[9].connect[7] then
			swap_stair(8, 2, 7)
		end
		if t[2].connect[5] ~= t[8].connect[2] then
			if t[2].connect[5] then
				if t[6].connect[8] then
					reset_node(2, 3)
				elseif t[4].connect[4] then
					reset_node(2, 7)
				elseif t[6].connect[1] and t[6].connect[6] and t[3].connect[6] and not t[9].connect[1] then
					swap_stair(6, 1, 8)
					reset_node(2, 3)
				elseif t[6].connect[2] and t[6].connect[5] and t[9].connect[2] and not t[3].connect[5] then
					swap_stair(6, 5, 8)
					reset_node(2, 3)
				elseif t[4].connect[2] and t[4].connect[5] and t[7].connect[2] and not t[1].connect[5] then
					swap_stair(4, 4, 5)
					reset_node(2, 7)
				elseif t[4].connect[1] and t[4].connect[6] and t[1].connect[6] and not t[7].connect[1] then
					swap_stair(4, 1, 4)
					reset_node(2, 7)
				end
			else
				if t[6].connect[7] then
					reset_node(4, 5)
				elseif t[4].connect[3] then
					reset_node(5, 8)
				elseif t[6].connect[1] and t[6].connect[6] and t[9].connect[1] and not t[3].connect[6] then
					swap_stair(6, 6, 7)
					reset_node(4, 5)
				elseif t[6].connect[2] and t[6].connect[5] and t[3].connect[5] and not t[9].connect[2] then
					swap_stair(6, 2, 7)
					reset_node(4, 5)
				elseif t[4].connect[2] and t[4].connect[5] and t[1].connect[5] and not t[7].connect[2] then
					swap_stair(4, 2, 3)
					reset_node(5, 8)
				elseif t[4].connect[1] and t[4].connect[6] and t[7].connect[1] and not t[1].connect[6] then
					swap_stair(4, 3, 6)
					reset_node(5, 8)
				end
			end
		end
	elseif connect[4] then
		if t[6].connect[1] and t[6].connect[6] and t[9].connect[1] and not t[3].connect[6] then
			swap_stair(6, 6, 7)
		elseif t[6].connect[2] and t[6].connect[5] and t[3].connect[5] and not t[9].connect[2] then
			swap_stair(6, 2, 7)
		end
		if t[4].connect[2] and t[4].connect[5] and t[7].connect[2] and not t[1].connect[5] then
			swap_stair(4, 4, 5)
		elseif t[4].connect[1] and t[4].connect[6] and t[1].connect[6] and not t[7].connect[1] then
			swap_stair(4, 1, 4)
		end
		if t[4].connect[4] ~= t[6].connect[7] then
			if t[4].connect[4] then
				if t[8].connect[1] then
					reset_node(6, 7)
				elseif t[2].connect[5] then
					reset_node(2, 7)
				elseif t[8].connect[3] and t[8].connect[8] and t[7].connect[3] and not t[9].connect[8] then
					swap_stair(8, 1, 8)
					reset_node(6, 7)
				elseif t[8].connect[4] and t[8].connect[7] and t[9].connect[7] and not t[7].connect[4] then
					swap_stair(8, 1, 4)
					reset_node(6, 7)
				elseif t[2].connect[4] and t[2].connect[7] and t[3].connect[7] and not t[1].connect[4] then
					swap_stair(2, 4, 5)
					reset_node(2, 7)
				elseif t[2].connect[3] and t[2].connect[8] and t[1].connect[3] and not t[3].connect[8] then
					swap_stair(2, 5, 8)
					reset_node(2, 7)
				end
			else
				if t[8].connect[2] then
					reset_node(4, 5)
				elseif t[2].connect[6] then
					reset_node(1, 4)
				elseif t[8].connect[3] and t[8].connect[8] and t[9].connect[8] and not t[7].connect[3] then
					swap_stair(8, 2, 3)
					reset_node(4, 5)
				elseif t[8].connect[4] and t[8].connect[7] and t[7].connect[4] and not t[9].connect[7] then
					swap_stair(8, 2, 7)
					reset_node(4, 5)
				elseif t[2].connect[4] and t[2].connect[7] and t[1].connect[4] and not t[3].connect[7] then
					swap_stair(2, 6, 7)
					reset_node(1, 4)
				elseif t[2].connect[3] and t[2].connect[8] and t[3].connect[8] and not t[1].connect[3] then
					swap_stair(2, 3, 6)
					reset_node(1, 4)
				end
			end
		end
	elseif connect[1] then
		if t[8].connect[3] and t[8].connect[8] and t[7].connect[3] and not t[9].connect[8] then
			swap_stair(8, 1, 8)
		elseif t[8].connect[4] and t[8].connect[7] and t[9].connect[7] and not t[7].connect[4] then
			swap_stair(8, 1, 4)
		end
		if t[2].connect[4] and t[2].connect[7] and t[1].connect[4] and not t[3].connect[7] then
			swap_stair(2, 6, 7)
		elseif t[2].connect[3] and t[2].connect[8] and t[3].connect[8] and not t[1].connect[3] then
			swap_stair(2, 3, 6)
		end
		if t[2].connect[6] ~= t[8].connect[1] then
			if t[2].connect[6] then
				if t[4].connect[3] then
					reset_node(1, 8)
				elseif t[6].connect[7] then
					reset_node(1, 4)
				elseif t[4].connect[2] and t[4].connect[5] and t[1].connect[5] and not t[7].connect[2] then
					swap_stair(4, 2, 3)
					reset_node(1, 8)
				elseif t[4].connect[1] and t[4].connect[6] and t[7].connect[1] and not t[1].connect[6] then
					swap_stair(4, 3, 6)
					reset_node(1, 8)
				elseif t[6].connect[1] and t[6].connect[6] and t[9].connect[1] and not t[3].connect[6] then
					swap_stair(6, 6, 7)
					reset_node(1, 4)
				elseif t[6].connect[2] and t[6].connect[5] and t[3].connect[5] and not t[9].connect[2] then
					swap_stair(6, 2, 7)
					reset_node(1, 4)
				end
			else
				if t[4].connect[4] then
					reset_node(6, 7)
				elseif t[6].connect[8] then
					reset_node(3, 6)
				elseif t[4].connect[2] and t[4].connect[5] and t[7].connect[2] and not t[1].connect[5] then
					swap_stair(4, 4, 5)
					reset_node(6, 7)
				elseif t[4].connect[1] and t[4].connect[6] and t[1].connect[6] and not t[7].connect[1] then
					swap_stair(4, 1, 4)
					reset_node(6, 7)
				elseif t[6].connect[1] and t[6].connect[6] and t[3].connect[6] and not t[9].connect[1] then
					swap_stair(6, 1, 8)
					reset_node(3, 6)
				elseif t[6].connect[2] and t[6].connect[5] and t[9].connect[2] and not t[3].connect[5] then
					swap_stair(6, 5, 8)
					reset_node(3, 6)
				end
			end
		end
	end
	core.swap_node(pos, node)
end

local function rotate_and_place(itemstack, placer, pointed_thing)
	local p0 = pointed_thing.under
	local p1 = pointed_thing.above
	local param2 = 0

	if placer then
		local placer_pos = placer:get_pos()
		if placer_pos then
			local diff = vector.subtract(p1, placer_pos)
			param2 = core.dir_to_facedir(diff)
			-- The player places a node on the side face of the node they are standing on
			if p0.y == p1.y and math.abs(diff.x) <= 0.5 and math.abs(diff.z) <= 0.5 and diff.y < 0 then
				-- Reverse node direction
				param2 = (param2 + 2) % 4
			end
		end

		local finepos = core.pointed_thing_to_face_pos(placer, pointed_thing)
		local fpos = finepos.y % 1

		if p0.y - 1 == p1.y or (fpos > 0 and fpos < 0.5)
				or (fpos < -0.5 and fpos > -0.999999999) then
			param2 = param2 + 20
			if param2 == 21 then
				param2 = 23
			elseif param2 == 23 then
				param2 = 21
			end
		end
	end
	return core.item_place(itemstack, placer, pointed_thing, param2)
end

local function register_inverted_lbm(subnode_name, node_name, ...)
	local arg = {...}
	return core.register_lbm({
		label = "Update inverted stairs from " .. node_name,
		name = ":" .. arg[1] .. "_inverted_stair_replace",
		nodenames = arg,
		run_at_every_load = true,
		action = function(pos, node, dtime_s)
			local n = {}
			n.name = subnode_name
			n.param2 = node.param2 + 20
			if n.param2 == 21 then
				n.param2 = 23
			elseif n.param2 == 23 then
				n.param2 = 21
			end
			core.set_node(pos, n)
		end
	})
end

local function register_corner_lbm(subnode_name, node_name, ...)
	local arg = {...}
	return core.register_lbm({
		label = "Update corners from " .. node_name,
		name = ":" .. arg[1] .. "_corner_replace",
		nodenames = arg,
		run_at_every_load = true,
		action = function(pos, node, dtime_s)
			local n = {name = subnode_name, param2 = 0}
			if node.param2 == 0 then
				n.param2 = 11
			elseif node.param2 == 1 then
				n.param2 = 16
			elseif node.param2 == 2 then
				n.param2 = 18
			elseif node.param2 == 3 then
				n.param2 = 14
			end
			core.set_node(pos, n)
		end
	})
end

subnodes.register_kind("stairs:stair", {
	node_override = {
		drawtype = "nodebox",
		paramtype = "light",
		paramtype2 = "facedir",
		node_box = {
			type = "fixed",
			fixed = {
				{-0.5, -0.5, -0.5, 0.5, 0.0, 0.5},
				{-0.5, 0.0, 0.0, 0.5, 0.5, 0.5},
			},
		},
		groups = {stair = 1},

		on_place = function(itemstack, placer, pointed_thing)
			local rc = voxelgarden.call_on_rightclick(itemstack, placer, pointed_thing)
			if rc then return rc end

			return rotate_and_place(itemstack, placer, pointed_thing)
		end,

		after_place_node = after_place_node,
		after_dig_node = after_dig_node,
	},
	volume_factor = 3/4,

	get_readable_name = function(base_description)
		return S("@1 Stair", base_description)
	end,

	get_crafts = function(n, m)
		return {
			output = n .. " 8",
			recipe = {
				{"", "", m},
				{"", m, m},
				{m, m, m}
			}
		}, {
			output = n .. " 8",
			recipe = {
				{m, "", ""},
				{m, m, ""},
				{m, m, m}
			}
		}, { -- Use 4 stairs to craft 3 full nodes again (1:1)
			output = m .. " 3",
			recipe = {
				{n, n},
				{n, n}
			}
		}
	end,

	after_register = function(subnode_name, node_name)
		local _, outer_name = subnodes.make_name_subname(node_name, "stairs:outer_stair")
		local _, inner_name = subnodes.make_name_subname(node_name, "stairs:inner_stair")
		core.override_item(subnode_name, {_stairs = {subnode_name, outer_name, inner_name}})

		local _, old_name, old_name2 = subnodes.make_name_subname(node_name, "stairsplus:stair")
		core.register_alias(old_name, subnode_name)
		core.register_alias(old_name2, subnode_name)
		register_inverted_lbm(subnode_name, node_name, old_name .. "_inverted", old_name2 .. "_inverted")
		voxelgarden.register_item_conversion(old_name .. "_inverted", subnode_name)
		voxelgarden.register_item_conversion(old_name2 .. "_inverted", subnode_name)

		local _, corner_name, corner_name2 = subnodes.make_name_subname(node_name, "stairsplus:corner")
		register_corner_lbm(subnode_name, node_name, corner_name, corner_name2)
		voxelgarden.register_item_conversion(corner_name, subnode_name)
		voxelgarden.register_item_conversion(corner_name2, subnode_name)
	end
})

subnodes.register_kind("stairs:outer_stair", {
	node_override = {
		drawtype = "nodebox",
		paramtype = "light",
		paramtype2 = "facedir",
		node_box = {
			type = "fixed",
			fixed = {
				{-0.5, -0.5, -0.5, 0.5, 0, 0.5},
				{-0.5, 0, 0, 0, 0.5, 0.5},
			},
		},
		groups = {not_in_creative_inventory = 1, stair = 2},
		after_dig_node = after_dig_node,
	},
	volume_factor = 5/8,

	get_readable_name = function(base_description)
		return S("Outer @1 Stair", base_description)
	end,
	drop = subnodes.create_drop_kind("stairs:stair"),
	after_register = function(subnode_name, node_name)
		local _, main_name = subnodes.make_name_subname(node_name, "stairs:stair")
		local _, inner_name = subnodes.make_name_subname(node_name, "stairs:inner_stair")
		core.override_item(subnode_name, {_stairs = {main_name, subnode_name, inner_name}})

		local _, old_basename, old_basename2 = subnodes.make_name_subname(node_name, "stairsplus:corner")
		local old_name, old_name2 = old_basename .. "_outer", old_basename2 .. "_outer"
		core.register_alias(old_name, subnode_name)
		register_inverted_lbm(subnode_name, node_name, old_name .. "_inverted", old_name2 .. "_inverted")
		voxelgarden.register_item_conversion(old_name .. "_inverted", subnode_name)
		voxelgarden.register_item_conversion(old_name2 .. "_inverted", subnode_name)
	end
})

subnodes.register_kind("stairs:inner_stair", {
	node_override = {
		drawtype = "nodebox",
		paramtype = "light",
		paramtype2 = "facedir",
		node_box = {
			type = "fixed",
			fixed = {
				{-0.5, -0.5, -0.5, 0.5, 0, 0.5},
				{-0.5, 0, 0, 0.5, 0.5, 0.5},
				{-0.5, 0, -0.5, 0, 0.5, 0},
			},
		},
		groups = {not_in_creative_inventory = 1, stair = 3},
		after_dig_node = after_dig_node,
	},
	volume_factor = 7/8,

	get_readable_name = function(base_description)
		return S("Inner @1 Stair", base_description)
	end,
	drop = subnodes.create_drop_kind("stairs:stair"),
	after_register = function(subnode_name, node_name)
		local _, main_name = subnodes.make_name_subname(node_name, "stairs:stair")
		local _, outer_name = subnodes.make_name_subname(node_name, "stairs:outer_stair")
		core.override_item(subnode_name, {_stairs = {main_name, outer_name, subnode_name}})

		local _, old_basename, old_basename2 = subnodes.make_name_subname(node_name, "stairsplus:corner")
		local old_name, old_name2 = old_basename .. "_inner", old_basename2 .. "_inner"
		core.register_alias(old_name, subnode_name)
		register_inverted_lbm(subnode_name, node_name, old_name .. "_inverted", old_name2 .. "_inverted")
		voxelgarden.register_item_conversion(old_name .. "_inverted", subnode_name)
		voxelgarden.register_item_conversion(old_name2 .. "_inverted", subnode_name)
	end
})
