local structures = {} local ores = {} local TIMER = 10 local function determine_structure(controller, player) local below1 = vector.add(controller, {x=0,y=-1,z=0}) local below2 = vector.add(below1, {x=0,y=-1,z=0}) local miners = 0 local nodes = {} local cpos = minetest.pos_to_string(controller) if ele.helpers.node_compare(below1, "elepower_mining:miner_core") and ele.helpers.node_compare(below2, "elepower_mining:miner_drill") then table.insert(nodes, below1) table.insert(nodes, below2) miners = 1 end if miners == 0 then if structures[cpos] then structures[cpos] = nil end return false end for x = -1, 1 do for z = -1, 1 do if not (x == 0 and z == 0) then local duct = vector.add(controller, {x=x,y=-1,z=z}) local appr = vector.add(duct, {x=0,y=-1,z=0}) if ele.helpers.node_compare(appr, "elepower_mining:miner_drill") and ele.helpers.node_compare(duct, "group:fluid_transport") then table.insert(nodes, duct) table.insert(nodes, appr) miners = miners + 1 end end end end structures[cpos] = { miners = miners, nodes = nodes } if player then minetest.chat_send_player(player, string.format("Miner structure complete (detected %d drills)!", miners)) end local t = minetest.get_node_timer(controller) if not t:is_started() then t:start(1.0) end return true, miners, nodes end local function random_ore() for ore, probability in pairs(ores) do if math.random(probability) == 1 then return ore end end end local function get_mining_results(drills) local results = {} local amount = math.random(0, drills) -- Run mining operations for i = 0, amount do local picked -- Run three tries trying to find a random ore for j = 0, 3 do picked = random_ore() if picked then break end end -- If a random ore was found, add it to results if picked then local count = math.random(1, 3) local stack = ItemStack(picked) stack:set_count(count) table.insert(results, stack) end end return results end local function get_formspec(timer, power, buffer, state) if not timer then timer = 0 end return "size[8,8.5]".. default.gui_bg.. default.gui_bg_img.. default.gui_slots.. ele.formspec.power_meter(power).. ele.formspec.state_switcher(0, 2.5, state).. ele.formspec.fluid_bar(7, 0, buffer).. ele.formspec.create_bar(1, 0, 100 - timer, "#00ff11", true).. "list[context;dst;1.5,0;5,3;]".. "list[current_player;main;0,4.25;8,1;]".. "list[current_player;main;0,5.5;8,3;8]".. "listring[current_player;main]".. "listring[context;dst]".. "listring[current_player;main]".. default.get_hotbar_bg(0, 4.25) end local function on_timer(pos, elapsed) local refresh = false local meta = minetest.get_meta(pos) local inv = meta:get_inventory() local buffer = fluid_lib.get_buffer_data(pos, "water") local state = meta:get_int("state") local work = meta:get_int("work") local is_enabled = ele.helpers.state_enabled(meta, pos, state) local capacity = ele.helpers.get_node_property(meta, pos, "capacity") local usage = ele.helpers.get_node_property(meta, pos, "usage") local storage = ele.helpers.get_node_property(meta, pos, "storage") local pow_buffer = {capacity = capacity, storage = storage, usage = 0} local active = "with Invalid structure - Punch to redetect" local miners = 0 local pts = minetest.pos_to_string(pos) while true do if not structures[pts] then break end active = "Idle" miners = structures[pts].miners usage = usage * miners if storage < usage then active = "Out of Power!" break end active = string.format("Mining with %d miners", miners) pow_buffer.usage = usage local coolant = 500 * miners if buffer.amount < coolant then active = "Out of Water!" break end if work < TIMER then work = work + 1 pow_buffer.storage = pow_buffer.storage - usage buffer.amount = buffer.amount - coolant break end -- Get some lumps local added = 0 local itms = get_mining_results(miners) for _,stack in pairs(itms) do if inv:room_for_item("dst", stack) then inv:add_item("dst", stack) added = added + 1 end end -- If the inventory is full and the miner mined something, stop the clock if added == 0 and #itms > 0 then active = "Inventory full!" refresh = false break end pow_buffer.storage = pow_buffer.storage - usage buffer.amount = buffer.amount - coolant work = 0 refresh = true break end local wp = math.floor(work / TIMER * 100) meta:set_string("infotext", ("Miner %s\n%s"):format(active, ele.capacity_text(capacity, storage))) meta:set_string("formspec", get_formspec(wp, pow_buffer, buffer, state)) meta:set_int("storage", pow_buffer.storage) meta:set_int("water_fluid_storage", buffer.amount) meta:set_string("water_fluid", "default:water_source") meta:set_int("work", work) return refresh end local function recalc_on_break(pos) for core,data in pairs(structures) do local cp = minetest.string_to_pos(core) local match = false for _,ipos in pairs(data.nodes) do if vector.equals(pos, ipos) then match = true determine_structure(cp) break end end if match then break end end end ele.register_machine("elepower_mining:miner_controller", { description = "Miner Controller\nMachine Component", tiles = { "elepower_machine_top.png^elepower_power_port.png", "elepower_machine_base.png^elepower_power_port.png", "elepower_machine_side.png^elepower_power_port.png", "elepower_machine_side.png^elepower_power_port.png", "elepower_machine_side.png^elepower_power_port.png", "elepower_machine_side.png^elenuclear_fusion_controller.png", }, fluid_buffers = { water = { capacity = 16000, accepts = {"default:water_source"}, drainable = false, }, }, ele_capacity = 320000, ele_inrush = 1200, ele_usage = 128, paramtype2 = "facedir", groups = {fluid_container = 1, oddly_breakable_by_hand = 1, cracky = 1, tube = 1, ele_user = 1}, on_construct = function (pos) local meta = minetest.get_meta(pos) local inv = meta:get_inventory() inv:set_size("dst", 5*3) meta:set_string("formspec", get_formspec()) end, on_timer = on_timer, on_punch = function (pos, node, puncher, pointed_thing) determine_structure(pos, puncher:get_player_name()) minetest.node_punch(pos, node, puncher, pointed_thing) end, }) minetest.register_node("elepower_mining:miner_core", { description = "Miner Core\nMachine Component", tiles = { "elepower_mining_core.png^elepower_power_port.png", "elepower_mining_core.png^elepower_power_port.png", "elepower_mining_core.png^elepower_power_port.png", "elepower_mining_core.png^elepower_power_port.png", "elepower_mining_core.png^elepower_power_port.png", "elepower_mining_core.png^elepower_power_port.png", }, groups = {fluid_container = 1, oddly_breakable_by_hand = 1, cracky = 1}, after_dig_node = recalc_on_break, }) minetest.register_node("elepower_mining:miner_drill", { description = "Miner Drill\nMachine Component", tiles = { "elepower_machine_top.png^elepower_power_port.png", "elepower_mining_apparatus_base.png", "elepower_machine_side.png^elepower_mining_apparatus_side.png", "elepower_machine_side.png^elepower_mining_apparatus_side.png", "elepower_machine_side.png^elepower_mining_apparatus_side.png", "elepower_machine_side.png^elepower_mining_apparatus_side.png", }, groups = {fluid_container = 1, oddly_breakable_by_hand = 1, cracky = 1}, after_dig_node = recalc_on_break, }) minetest.register_lbm({ label = "Enable Miners on load", name = "elepower_mining:load_miner_controllers", nodenames = {"elepower_mining:miner_controller"}, run_at_every_load = true, action = function (pos) determine_structure(pos) end, }) -- The following code is borrowed from the gravelsieve mod by Joachim Stolberg, licensed under LGPLv2.1+ -- https://github.com/joe7575/techpack/blob/master/gravelsieve/ local PROBABILITY_FACTOR = 3 local ore_rarity = 1.16 local ore_max_elevation = 0 local ore_min_elevation = -30912 local y_spread = math.max(1 + ore_max_elevation - ore_min_elevation, 1) local function harmonic_sum(a, b) return 1 / ((1 / a) + (1 / b)) end local function calculate_probability(item) local ymax = math.min(item.y_max, ore_max_elevation) local ymin = math.max(item.y_min, ore_min_elevation) return (ore_rarity / PROBABILITY_FACTOR) * item.clust_scarcity / (item.clust_num_ores * ((ymax - ymin) / y_spread)) end local function add_ores() for _,item in pairs(minetest.registered_ores) do if minetest.registered_nodes[item.ore] then local drop = minetest.registered_nodes[item.ore].drop if type(drop) == "string" and drop ~= item.ore and drop ~= "" and item.ore_type == "scatter" and item.wherein == "default:stone" and item.clust_scarcity ~= nil and item.clust_scarcity > 0 and item.clust_num_ores ~= nil and item.clust_num_ores > 0 and item.y_max ~= nil and item.y_min ~= nil then local probability = calculate_probability(item) if probability > 0 then local cur_probability = ores[drop] if cur_probability then ores[drop] = harmonic_sum(cur_probability, probability) else ores[drop] = probability end end end end end local overall_probability = 0.0 for name,probability in pairs(ores) do minetest.log("info", ("[elepower_mining] %-32s %.02f"):format(name, probability)) overall_probability = overall_probability + 1.0/probability end minetest.log("info", ("[elepower_mining] Overall probability %f"):format(overall_probability)) end minetest.after(1, add_ores)