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
