PyuTest.make_ore = function(id, desc, options)
	local default_options = {
		scarcity = 5 * 5 * 5,
		y_max = PyuTest.WORLD_TOP,
		y_min = PyuTest.OVERWORLD_BOTTOM,
		wherein = {},

		ore_strength = PyuTest.BLOCK_NORMAL,
		ore_conf = {},
		ore_groups = {},
		ore_drop = nil,
		ore_drop_count = 1,
		ore_sounds = nil,
		ore_stone = { "pyutest-stone.png" },
		ore_color = nil,
		ore_blast_resistance = 3
	}

	local conf = {}

	for k, v in pairs(options) do
		conf[k] = v
	end

	for k, v in pairs(default_options) do
		if conf[k] == nil then
			conf[k] = v
		end
	end

	core.register_node(id, PyuTest.util.tableconcat({
		description = Translate(desc),
		groups = PyuTest.util.tableconcat({
			cracky = conf.ore_strength,
			mineral = 1,
		}, conf.ore_groups),
		drop = conf.ore_drop .. " " .. tostring(conf.ore_drop_count or 1),
		sounds = PyuTest.make_node_sounds(conf.ore_sounds),
		tiles = conf.ore_stone,
		overlay_tiles = { { name = "pyutest-ore-overlay.png", color = conf.ore_color } },
		_pyutest_blast_resistance = conf.ore_blast_resistance
	}, conf.ore_conf))

	core.register_ore({
		ore_type = "scatter",
		ore = id,
		wherein = conf.wherein,
		clust_scarcity = conf.scarcity,
		clust_num_ores = 4,
		clust_size = 3,
		y_max = conf.y_max,
		y_min = conf.y_min,
	})

	core.register_ore({
		ore_type = "scatter",
		ore = id,
		wherein = conf.wherein,
		clust_scarcity = conf.scarcity * 2.2,
		clust_num_ores = 9,
		clust_size = 3,
		y_max = conf.y_max,
		y_min = conf.y_min,
	})

	core.register_ore({
		ore_type = "scatter",
		ore = id,
		wherein = conf.wherein,
		clust_scarcity = conf.scarcity * 3,
		clust_num_ores = 18,
		clust_size = 6,
		y_max = conf.y_max,
		y_min = conf.y_min,
	})

	return conf
end

PyuTest.make_ore_and_item = function(id, desc, item_id_suffix, item_description_suffix, options)
	local default_options = {
		ore_options = {},

		item_conf = {},
		item_groups = {},
		item_texture = nil,

		make_raw = false,
		raw_conf = {},
		raw_groups = {},
		raw_texture = {},

		block_conf = {},
		block_color = nil,
		block_tiles = {},
		block_groups = {},
		block_shiny = false,
	}
	local conf = {}

	for k, v in pairs(options) do
		conf[k] = v
	end

	for k, v in pairs(default_options) do
		if conf[k] == nil then
			conf[k] = v
		end
	end

	local oid = id .. "_ore"
	local iid = id .. "_" .. item_id_suffix
	local rid = conf.make_raw and id .. "_raw" or nil

	local ore_conf = PyuTest.make_ore(oid, desc .. " Ore", PyuTest.util.tableconcat(conf.ore_options, {
		ore_drop = conf.ore_options.ore_drop or (rid or iid)
	}))

	core.register_craftitem(iid, PyuTest.util.tableconcat({
		description = Translate(desc .. " " .. item_description_suffix),
		groups = PyuTest.util.tableconcat({
			mineral = 1
		}, conf.item_groups),
		wield_image = conf.item_texture,
		inventory_image = conf.item_texture
	}, conf.item_conf))

	if conf.make_raw then
		core.register_craftitem(rid, PyuTest.util.tableconcat({
			description = Translate("Raw " .. desc),
			groups = PyuTest.util.tableconcat({
				mineral = 1,
				raw_mineral = 1
			}, conf.raw_groups),
			wield_image = conf.raw_texture,
			inventory_image = conf.raw_texture
		}, conf.raw_conf))

		core.register_craft({
			type = "cooking",
			output = iid,
			recipe = rid
		})
	end

	PyuTest.make_building_blocks(id, desc, conf.block_tiles, conf.block_color, PyuTest.util.tableconcat({
		cracky = ore_conf.ore_strength
	}, conf.block_groups), PyuTest.util.tableconcat(conf.block_conf, {
		overlay_tiles = conf.block_shiny and {
			"pyutest-shiny-metal-overlay.png"
		} or nil
	}))

	local bid = id .. "_block"

	core.override_item(bid, {
		description = desc .. " Block"
	})

	core.register_craft({
		output = bid,
		recipe = {
			{ iid, iid },
			{ iid, iid }
		}
	})

	core.register_craft({
		output = iid .. " 4",
		recipe = {
			bid
		},
		type = "shapeless"
	})
end
