local exchangeclone = exchangeclone -- Calculates the cheapest recipe given an itemstring. -- Would probably benefit from another function, since there's quite a bit -- of duplicate code. local function get_cheapest_recipe(itemstring, log) itemstring = ItemStack(itemstring):get_name() local recipes = exchangeclone.recipes[itemstring] if not recipes then return end local cheapest for _, recipe in pairs(recipes) do local ingredient_cost = 0 local output_count = ItemStack(recipe.output):get_count() local skip = false local identical_replacements = {} if recipe.replacements then for _, replacement in pairs(recipe.replacements) do if replacement[1] == replacement[2] then identical_replacements[replacement[1]] = (identical_replacements[replacement[1]] or 0) + 1 end end end if not recipe.type or exchangeclone.craft_types[recipe.type].type == "shaped" then for _, row in pairs(recipe.recipe) do for _, item in pairs(row) do if item ~= "" then if item == itemstring then output_count = math.max(0, output_count - 1) else local replaced = identical_replacements[item] if replaced and replaced > 0 then identical_replacements[item] = replaced - 1 else local cost = exchangeclone.get_item_emc(item) if (not cost) or cost == 0 then skip = item else ingredient_cost = ingredient_cost + cost end end end end end end elseif exchangeclone.craft_types[recipe.type].type == "shapeless" then for _, item in pairs(recipe.recipe) do if item ~= "" then if item == itemstring then output_count = math.max(0, output_count - 1) else local replaced = identical_replacements[item] if replaced and replaced > 0 then identical_replacements[item] = replaced - 1 else local cost = exchangeclone.get_item_emc(item) if (not cost) or cost == 0 then skip = item else ingredient_cost = ingredient_cost + cost end end end end end elseif exchangeclone.craft_types[recipe.type].type == "cooking" then local item = recipe.recipe if item ~= "" then if item == itemstring then output_count = math.max(0, output_count - 1) else local replaced = identical_replacements[item] if replaced and replaced > 0 then identical_replacements[item] = replaced - 1 else local cost = exchangeclone.get_item_emc(item) if (not cost) or cost == 0 then skip = item else ingredient_cost = ingredient_cost + cost end end end end elseif exchangeclone.craft_types[recipe.type].type == "emc" then ingredient_cost = recipe.recipe end if recipe.replacements and not skip then for _, item in pairs(recipe.replacements) do if item[1] ~= item[2] then local cost = exchangeclone.get_item_emc(item[2]) if (not cost) or cost == 0 then skip = item[2] else ingredient_cost = ingredient_cost - cost end end end end if output_count < 1 then skip = true end if not skip then local total_cost = math.floor(ingredient_cost*20/math.max(1, output_count))/20 -- allow .05, won't work with huge numbers if (not cheapest) or (cheapest[1] > total_cost) then cheapest = {total_cost, recipe} end end if log then minetest.log("action", dump({ recipe = recipe, ingredient_cost = ingredient_cost, output_count = output_count })) end end return cheapest and cheapest[1] end exchangeclone.emc_values = {} -- Sets the EMC value of an item, must be called during load time. local function register_emc(itemstring, emc_value) if not (emc_value and itemstring) then return end emc_value = math.floor(emc_value*20)/20 -- floor to nearest .05 if emc_value < 0 then return end local def = minetest.registered_items[itemstring] if not def then return end local description = def.description or "" -- Override EMC value if it already exists local existing_emc_value = description:find("EMC: ([%d%.,]+)") if existing_emc_value then description = description:gsub("EMC: ([%d%.,]+)", "EMC: "..exchangeclone.format_number(emc_value)) else if description[#description] ~= "\n" then description = description.."\n" end description = description.."EMC: "..exchangeclone.format_number(emc_value) end minetest.override_item(itemstring, { description = description, emc_value = emc_value, }) if emc_value > 0 then exchangeclone.emc_values[itemstring] = emc_value else exchangeclone.emc_values[itemstring] = nil end end local auto = {} if exchangeclone.exile then local seen_unknown_crafting_types = {} local did_cooking_warning = false local replacements_actions = {} -- Exile doesn't have lava buckets and uses an alternative, -- so just eat the input item replacements_actions[dump({{ exchangeclone.itemstrings.lava_bucket, exchangeclone.itemstrings.empty_bucket, }})] = {just_eat_input = true} -- we're already using a philosopher's stone to do the crafting, -- don't add to recipe so we don't need two replacements_actions[dump({{ "exchangeclone:philosophers_stone", "exchangeclone:philosophers_stone", }})] = {remove_from_input = "exchangeclone:philosophers_stone"} -- used for recipe for iron band -- crafting mod doesn't support -- replacements, there is another recipe for the iron band, -- so just ignore the recipe replacements_actions[dump({{ "exchangeclone:volcanite_amulet", "exchangeclone:volcanite_amulet", }})] = {ignore_recipe = true} local replacement_itemstrings = { ["group:tree"] = "group:log", } for _, recipes in pairs(exchangeclone.recipes) do for _, recipe in ipairs(recipes) do local mt_craft_type = recipe.type and exchangeclone.craft_types[recipe.type].type if not mt_craft_type or mt_craft_type == "shaped" or mt_craft_type == "shapeless" then ---@type table local item_counts = {} local remove_from_input = nil local ignore_recipe = false if recipe.replacements then local replacements_value = dump(recipe.replacements) local replacements_action = replacements_actions[replacements_value] assert(replacements_action, "[ExchangeClone] unimplemented replacements style: "..replacements_value) if replacements_action.remove_from_input then remove_from_input = replacements_action.remove_from_input elseif replacements_action.ignore_recipe then ignore_recipe = true else assert(replacements_action.just_eat_input, "unhandled replacements_action"..dump(replacements_action)) end end local worklist = table.copy(recipe.recipe) while #worklist > 0 do local item = table.remove(worklist) if type(item) == "table" then for _, v in ipairs(item) do table.insert(worklist, v) end elseif item and item ~= remove_from_input and item ~= "" then local count = item_counts[item] or 0 item_counts[item] = count + 1 end end local items_array = {} for itemstring, count in pairs(item_counts) do itemstring = replacement_itemstrings[itemstring] or itemstring local item = ItemStack(itemstring) item:set_count(count) if not itemstring:find("^group:") and not item:is_known() then ignore_recipe = true break end assert(item:to_string() ~= "", dump({itemstring=itemstring,count=count,recipe=recipe})) table.insert(items_array, item:to_string()) end if not ignore_recipe then local final_recipe = { type = "exchangeclone_crafting", output = recipe.output, items = items_array, always_known = true, } minetest.log("[ExchangeClone]: registered Exile crafting recipe: \n"..dump(final_recipe)) crafting.register_recipe(final_recipe) end elseif mt_craft_type == "cooking" then if not did_cooking_warning then minetest.log("warning", "[ExchangeClone] cooking crafts aren't implemented for Exile, ignoring") end did_cooking_warning = true else local unknown_craft_type = dump(mt_craft_type) if not seen_unknown_crafting_types[unknown_craft_type] then minetest.log("warning", "[ExchangeClone] unknown minetest crafting type: "..unknown_craft_type) end seen_unknown_crafting_types[unknown_craft_type] = true end end end for craft_type, recipes in pairs(crafting.recipes) do if craft_type ~= "exchangeclone_crafting" then exchangeclone.register_craft_type(craft_type, "shapeless") for _, orig_recipe in ipairs(recipes) do local recipe = {} for _, item in ipairs(orig_recipe.items) do item = ItemStack(item) for _ = 1, item:get_count() do table.insert(recipe, item:get_name()) end end exchangeclone.register_craft({ type = orig_recipe.type, output = orig_recipe.output, recipe = recipe, }) end end end exchangeclone.register_craft_type("thawing", "cooking", true) exchangeclone.register_craft({ type = "thawing", output = "nodes_nature:freshwater_source", recipe = "nodes_nature:ice", }) exchangeclone.register_craft({ type = "thawing", output = "nodes_nature:salt_water_source", recipe = "nodes_nature:sea_ice", }) exchangeclone.register_craft_type("roasting", "cooking") exchangeclone.register_craft({ type = "roasting", output = "tech:iron_bloom", recipe = "tech:iron_and_slag", }) exchangeclone.register_craft({ type = "roasting", output = "tech:iron_and_slag", recipe = "tech:iron_smelting_mix", }) exchangeclone.register_craft({ type = "roasting", output = "tech:green_glass_ingot", recipe = "tech:green_glass_mix", }) exchangeclone.register_craft({ type = "roasting", output = "tech:clear_glass_ingot", recipe = "tech:clear_glass_mix", }) exchangeclone.register_craft({ type = "roasting", output = "tech:quicklime", recipe = "tech:crushed_lime", }) exchangeclone.register_craft_type("melting", "shapeless") exchangeclone.register_craft({ type = "melting", output = "tech:pane_tray_clear", recipe = {"tech:clear_glass_ingot", "tech:pane_tray"}, }) exchangeclone.register_craft({ type = "melting", output = "tech:pane_tray_green", recipe = {"tech:green_glass_ingot", "tech:pane_tray"}, }) exchangeclone.register_craft_type("start_fire", "cooking") exchangeclone.register_craft({ type = "start_fire", output = "tech:small_wood_fire", recipe = "tech:small_wood_fire_unlit", }) exchangeclone.register_craft({ type = "start_fire", output = "tech:large_wood_fire", recipe = "tech:large_wood_fire_unlit", }) exchangeclone.register_craft({ type = "start_fire", output = "tech:small_charcoal_fire", recipe = "tech:charcoal", }) exchangeclone.register_craft({ type = "start_fire", output = "tech:large_charcoal_fire", recipe = "tech:charcoal_block", }) exchangeclone.register_craft_type("extinguish_fire", "cooking", true) exchangeclone.register_craft({ type = "extinguish_fire", output = "tech:small_wood_fire_ext", recipe = "tech:small_wood_fire", }) exchangeclone.register_craft({ type = "extinguish_fire", output = "tech:large_wood_fire_ext", recipe = "tech:large_wood_fire", }) exchangeclone.register_craft({ type = "extinguish_fire", output = "tech:small_charcoal_fire_ext", recipe = "tech:small_charcoal_fire", }) exchangeclone.register_craft({ type = "extinguish_fire", output = "tech:large_charcoal_fire_ext", recipe = "tech:large_charcoal_fire", }) exchangeclone.register_craft_type("to_smoldering", "cooking", true) exchangeclone.register_craft({ type = "to_smoldering", output = "tech:small_wood_fire_smoldering", recipe = "tech:small_wood_fire", }) exchangeclone.register_craft({ type = "to_smoldering", output = "tech:large_wood_fire_smoldering", recipe = "tech:large_wood_fire", }) exchangeclone.register_craft({ type = "to_smoldering", output = "tech:small_charcoal_fire_smoldering", recipe = "tech:small_charcoal_fire", }) exchangeclone.register_craft({ type = "to_smoldering", output = "tech:large_charcoal_fire_smoldering", recipe = "tech:large_charcoal_fire", }) exchangeclone.register_craft_type("hammer_place", "cooking") exchangeclone.register_craft({ type = "hammer_place", output = "tech:hammer_basalt_placed", recipe = "tech:hammer_basalt", }) exchangeclone.register_craft({ type = "hammer_place", output = "tech:hammer_granite_placed", recipe = "tech:hammer_granite", }) exchangeclone.register_craft_type("retting", "cooking") exchangeclone.register_craft({ type = "retting", output = "tech:retted_cana_bundle", recipe = "tech:unretted_cana_bundle", }) local extended_sed_list = table.copy(sed_list) local artificial_seds = {broken_pottery_block = {mod_name = 'tech'}} for name, _ in pairs(artificial_seds) do table.insert(extended_sed_list, {name}) end local water_pots = { "tech:clay_water_pot", "tech:wooden_water_pot", "tech:glass_bottle_green", "tech:glass_bottle_clear", } local wetnesses = { [""] = {water_pot_suffix = "", source = ""}, ["_wet"] = {water_pot_suffix = "_freshwater", source = "nodes_nature:freshwater_source"}, ["_wet_salty"] = {water_pot_suffix = "_salt_water", source = "nodes_nature:salt_water_source"}, } local ag_soils = { {ag = "", depleted = ""}, {ag = "_agricultural_soil", depleted = ""}, {ag = "_agricultural_soil", depleted = "_depleted"}, } exchangeclone.register_craft_type("make_ag_depleted", "cooking") exchangeclone.register_craft_type("ag_soil_to_soil", "cooking") exchangeclone.register_craft_type("wetten", "shapeless") for _, v in ipairs(extended_sed_list) do local name = v[1] local mod_name = "nodes_nature" if artificial_seds[name] then mod_name = artificial_seds[name].mod_name end for wetness, wetness_data in pairs(wetnesses) do for _, ag_soil in ipairs(ag_soils) do if wetness == "_wet" or (wetness == "_wet_salty" and ag_soil.ag == "") then exchangeclone.register_craft({ type = "wetten", output = mod_name..":"..name..ag_soil.ag..wetness..ag_soil.depleted, recipe = { mod_name..":"..name..ag_soil.ag..ag_soil.depleted, water_pots[1]..wetness_data.water_pot_suffix, }, replacements = {{water_pots[1]..wetness_data.water_pot_suffix, water_pots[1]}}, }) end end if wetness ~= "_wet_salty" then exchangeclone.register_craft({ type = "make_ag_depleted", output = mod_name..":"..name.."_agricultural_soil"..wetness.."_depleted", recipe = mod_name..":"..name..wetness, }) end end end exchangeclone.register_craft_type("fill_water_pot", "shapeless") for wetness, wetness_data in pairs(wetnesses) do if wetness ~= "" then for _, water_pot in ipairs(water_pots) do exchangeclone.register_craft({ type = "fill_water_pot", output = water_pot..wetness_data.water_pot_suffix, recipe = { water_pot, wetness_data.source, }, }) end end end for _, v in ipairs(soil_list) do local name = v[1] local sed_name = v[4] for wetness, wetness_data in pairs(wetnesses) do if wetness ~= "_wet_salty" then exchangeclone.register_craft({ type = "ag_soil_to_soil", output = "nodes_nature:"..name..wetness, recipe = "nodes_nature:"..sed_name.."_agricultural_soil"..wetness, }) end end end end -- Handle stonecutter recipes and decaychains in Mineclonia if exchangeclone.mcla then exchangeclone.register_craft_type("stonecutting", "cooking") -- TODO: Check recipe_yield for every Mineclonia update local recipe_yield = { --maps itemgroup to the respective recipe yield, default is 1 ["slab"] = 2, ["cut_copper"] = 4, } for result, def in pairs(minetest.registered_items) do if minetest.get_item_group(result,"not_in_creative_inventory") == 0 then if def._mcl_stonecutter_recipes then for _, source in pairs(def._mcl_stonecutter_recipes) do local yield = 1 for k,v in pairs(recipe_yield) do if minetest.get_item_group(result,k) > 0 then yield = v end end exchangeclone.register_craft({output = result.." "..yield, type = "stonecutting", recipe = source}) end end end end if mcl_copper then exchangeclone.register_craft_type("decaychain", "cooking") exchangeclone.register_craft_type("preserving", "cooking") local decaychains = mcl_copper.registered_decaychains for name, data in pairs(decaychains) do for i, itemstring in ipairs(data.nodes) do if minetest.get_item_group(name,"not_in_creative_inventory") == 0 then local preserved_itemstring = itemstring.."_preserved" exchangeclone.register_craft({output = preserved_itemstring, type = "preserving", recipe = {itemstring, "group:"..data.preserve_group}}) if i > 1 then exchangeclone.register_craft({output = itemstring, type = "decaychain", recipe = data.nodes[i-1]}) end end end end end end -- Register clock/compass aliases, handle enchanted/netherite stuff, potions, and concrete, and register coral EMC values if exchangeclone.mcl then for i = 0, 31 do exchangeclone.register_alias("mcl_compass:18", "mcl_compass:"..i) exchangeclone.register_alias("mcl_compass:18", "mcl_compass:"..i.."_lodestone") end for i = 0, 63 do exchangeclone.register_alias("mcl_clock:clock", "mcl_clock:clock_"..i) end exchangeclone.register_alias("doc_identifier:identifier_solid", "doc_identifier:identifier_liquid") exchangeclone.register_alias("mcl_books:writable_book", "mcl_books:written_book") exchangeclone.register_craft({output = "mcl_bamboo:bamboo_block_stripped", type = "cooking", recipe = "mcl_bamboo:bamboo_block"}) -- Potions exchangeclone.register_craft_type("brewing", "shapeless") local function add_potion_recipe(info) if not info.bases then info.bases = {"mcl_potions:awkward"} end for _, base in pairs(info.bases) do local ingredient = info.ingredient local normal = "mcl_potions:"..info.name local splash = normal.."_splash" local lingering = normal.."_lingering" exchangeclone.register_craft({output = normal.." 3", type = "brewing", recipe = {base, base, base, ingredient}}) exchangeclone.register_craft({output = normal.."_splash 3", type = "brewing", recipe = {normal, normal, normal, "mcl_mobitems:gunpowder"}}) exchangeclone.register_craft({output = normal.."_lingering 3", type = "brewing", recipe = {normal, normal, normal, "mcl_potions:dragon_breath"}}) if info.plus then exchangeclone.register_craft({output = normal.."_plus 3", type = "brewing", recipe = {normal, normal, normal, "mcl_nether:glowstone_dust"}}) exchangeclone.register_craft({output = normal.."_plus_splash 3", type = "brewing", recipe = {splash, splash, splash, "mcl_nether:glowstone_dust"}}) exchangeclone.register_craft({output = normal.."_plus_lingering 3", type = "brewing", recipe = {lingering, lingering, lingering, "mcl_nether:glowstone_dust"}}) end if info.two then exchangeclone.register_craft({output = normal.."_2 3", type = "brewing", recipe = {normal, normal, normal, "mesecons:redstone"}}) exchangeclone.register_craft({output = normal.."_2_splash 3", type = "brewing", recipe = {splash, splash, splash, "mesecons:redstone"}}) exchangeclone.register_craft({output = normal.."_2_lingering 3", type = "brewing", recipe = {lingering, lingering, lingering, "mesecons:redstone"}}) end end end for _, info in pairs(exchangeclone.mcl_potion_data) do add_potion_recipe(info) end -- Enchanted/netherite tools exchangeclone.register_craft_type("upgrading", "shapeless") for name, def in pairs(minetest.registered_items) do if def._mcl_enchanting_enchanted_tool then exchangeclone.register_alias(name, def._mcl_enchanting_enchanted_tool) end if def._mcl_upgrade_item then if not name:find("enchanted") then exchangeclone.register_craft({output = def._mcl_upgrade_item, type = "upgrading", recipe = {name, "mcl_nether:netherite_ingot"}}) end end end exchangeclone.register_craft_type("hardening", "cooking") -- Concrete and banners/shields (don't remember why the shields don't work) for color, color_data in pairs(exchangeclone.colors) do exchangeclone.register_craft({output = "mcl_colorblocks:concrete_"..color, type = "hardening", recipe = "mcl_colorblocks:concrete_powder_"..color}) --exchangeclone.register_craft({output = "mcl_shields:shield_"..color, type = "shapeless", recipe = {"mcl_banners:banner_item_"..color, "mcl_shields:shield"}}) end -- Maps exchangeclone.register_alias("mcl_maps:empty_map", "mcl_maps:filled_map") local mcl_skins_enabled = minetest.global_exists("mcl_skins") if mcl_skins_enabled then -- Generate a node for every skin local list = mcl_skins.get_skin_list() for _, skin in pairs(list) do exchangeclone.register_alias("mcl_maps:empty_map", "mcl_maps:filled_map_" .. skin.id) end else exchangeclone.register_alias("mcl_maps:empty_map", "mcl_maps:filled_map_hand") end -- Sponges exchangeclone.register_alias("mcl_sponges:sponge", "mcl_sponges:sponge_wet") exchangeclone.register_alias("mcl_sponges:sponge", "mcl_sponges:sponge_wet_river_water") end -- Register copper block/stonecutting EMC recipes in MineClone2 if exchangeclone.mcl2 then exchangeclone.register_craft_type("oxidation", "cooking") local states = {"", "_exposed", "_weathered", "_oxidized"} for i = 2, #states do exchangeclone.register_craft({output = "mcl_copper:block"..states[i], type = "oxidation", recipe = "mcl_copper:block"..states[i-1]}) end exchangeclone.register_craft_type("stonecutting", "cooking") for input, outputs in pairs(mcl_stonecutter.registered_recipes) do for output, amount in pairs(outputs) do exchangeclone.register_craft({output = output.." "..amount, type = "stonecutting", recipe = input}) end end end if exchangeclone.mtg then exchangeclone.register_alias("default:book", "default:book_written") end if minetest.global_exists("logistica") then exchangeclone.register_craft_type("lava_furnace", "shapeless") -- weird that it's not cooking but I can't see any way around that exchangeclone.register_craft({ output = "logistica:silverin", type = "lava_furnace", recipe = { exchangeclone.mcl and "mcl_core:sand" or "default:silver_sand", exchangeclone.itemstrings.ice } }) exchangeclone.register_craft({ output = "logistica:silverin_circuit", type = "lava_furnace", recipe = { "logistica:silverin_slice", exchangeclone.mcl and "mesecons:redstone" or "default:mese_crystal_fragment" } }) exchangeclone.register_craft({ output = "logistica:silverin_mirror_box", type = "lava_furnace", recipe = { exchangeclone.itemstrings.glass, "logistica:silverin_slice", "logistica:silverin_slice", "logistica:silverin_slice", "logistica:silverin_slice", "logistica:silverin_slice", "logistica:silverin_slice", } }) exchangeclone.register_craft({ output = "logistica:silverin_plate", type = "lava_furnace", recipe = { "logistica:silverin", exchangeclone.itemstrings.iron, } }) exchangeclone.register_craft({ output = "logistica:wireless_crystal", type = "lava_furnace", recipe = { "logistica:silverin", exchangeclone.itemstrings.emeraldworth, } }) end -- Up to this point, no EMC values have actually been set. -- Register group EMC values local groupnames = {} for index, group in ipairs(exchangeclone.group_values) do groupnames[#groupnames + 1] = group[1] --Get list of group names end local grouped_items = exchangeclone.get_group_items(groupnames, true, true) for index, group in ipairs(exchangeclone.group_values) do for i, item in pairs(grouped_items[group[1]]) do register_emc(item, group[2]) end end -- Register base EMC values for itemstring, emc_value in pairs(exchangeclone.base_emc_values) do register_emc(itemstring, emc_value) end --minetest.log('[ExchangeClone] recipes:\n' .. dump(exchangeclone.recipes)) -- Register `exchangeclone_custom_emc` values and decide whether to automatically register EMC values for itemstring, def in pairs(minetest.registered_items) do if def.exchangeclone_custom_emc then register_emc(itemstring, def.exchangeclone_custom_emc) else itemstring = exchangeclone.handle_alias(itemstring) or itemstring def = minetest.registered_items[itemstring] -- in case itemstring changed local _, _, mod_name, item_name = itemstring:find("([%d_%l]+):([%d_%l]+)") local add_to_auto = def and item_name and mod_name add_to_auto = add_to_auto and def.description and def.description ~= "" if minetest.get_item_group(itemstring, "not_in_creative_inventory") ~= 0 and mod_name ~= "mcl_compass" then add_to_auto = false elseif exchangeclone.exile and minetest.get_item_group(itemstring, "natural_slope") ~= 0 then add_to_auto = false elseif exchangeclone.get_item_emc(itemstring) then add_to_auto = false end if add_to_auto and exchangeclone.recipes[itemstring] then auto[itemstring] = true elseif add_to_auto then minetest.log("[ExchangeClone] skipping " .. itemstring .. "\n" .. dump(def)) end end end -- handle aliases in exchangeclone.recipes for itemstring, recipes in pairs(exchangeclone.recipes) do local new_name = ItemStack(itemstring):get_name() if new_name and new_name ~= "" and new_name ~= itemstring then exchangeclone.recipes[new_name] = exchangeclone.recipes[new_name] or {} for _, recipe in pairs(recipes) do table.insert(exchangeclone.recipes[new_name], recipe) end end end local old_auto local same = false local i = 1 -- Automatically register EMC values while not same do minetest.log("action", "[ExchangeClone] \tIteration #"..i) if auto == {} then break end if old_auto then same = true for itemstring, _ in pairs(old_auto) do if itemstring ~= "" and not auto[itemstring] then same = false break end end end if same then minetest.log("action", "[ExchangeClone]\tNo change, stopping.") break end old_auto = table.copy(auto) for itemstring, _ in pairs(auto) do local cheapest = get_cheapest_recipe(itemstring) if cheapest then register_emc(itemstring, cheapest) auto[itemstring] = nil end end i = i + 1 end if exchangeclone.mcl then register_emc("mcl_campfires:campfire", exchangeclone.get_item_emc("mcl_campfires:campfire_lit")) register_emc("mcl_campfires:soul_campfire", exchangeclone.get_item_emc("mcl_campfires:soul_campfire_lit")) -- Recovery compasses use a random compass frame for the crafting recipe... Incredibly irritating. for i = 0, 31 do if exchangeclone.get_item_emc("mcl_compass:"..i.."_recovery") then for j = 0, 31 do exchangeclone.register_alias("mcl_compass:"..i.."_recovery", "mcl_compass:"..j.."_recovery") end break end end end local cheapest_color = {""} for color, color_data in pairs(exchangeclone.colors) do local dye_itemstring = (exchangeclone.mcl and "mcl_dye:" or "dye:")..color local dye_emc = exchangeclone.get_item_emc(dye_itemstring) if dye_emc then if (not cheapest_color[2]) or (dye_emc < cheapest_color[2]) then cheapest_color[1] = color cheapest_color[2] = dye_emc end end end cheapest_color = cheapest_color[1] -- No idea why I'm doing it this way. local cheapest_advanced_itemstring = "exchangeclone:advanced_alchemical_chest_"..cheapest_color for color, color_data in pairs(exchangeclone.colors) do local advanced_itemstring = "exchangeclone:advanced_alchemical_chest_"..color register_emc(advanced_itemstring, exchangeclone.get_item_emc(cheapest_advanced_itemstring)) end -- Adds EMC values to aliased items, even though they're not used (just so it's displayed) for alias, itemstring in pairs(exchangeclone.emc_aliases) do register_emc(itemstring, exchangeclone.get_item_emc(alias)) end minetest.log("items without EMC" .. dump(auto)) -- Delete unnecessary data (waste of memory) if not exchangeclone.keep_data then exchangeclone.recipes = nil exchangeclone.base_emc_values = nil end