local NAME = minetest.get_current_modname() local ENERGYCOST = { static_strut = 20, dynamic_struct = 24, hardness_mod = 1, mining = 25, } local MAX_ENERGY = 3000 local FORMSPEC = sparktech.add_inventory(19.8,8, "list[current_name;quarry;0,0;16,6;]") local MAX_SIZE = 64 local function Position(x, y, z) --- --- Returns a valid pos as used by the game return {x=x, y=y, z=z} end local function try_drain_energy(target_pos, amount) --- --- Returns true if drained, false otherwise --- Removes amount energy from target_pos if energy >= amount local target = minetest.get_meta(target_pos) local current = target:get_int("energy") if current >= amount then target:set_int("energy", current - amount) return true else return false end end local function try_remove_item(target_pos, listname, itemname, amount) local inv = minetest.get_inventory({type="node", pos=target_pos}) local stack = ItemStack(itemname) local amount = amount or 1 stack:set_count(amount) local result = inv:remove_item(listname, stack) if result:get_count() ~= amount then inv:add_item(listname, result) else return true end return false end local function on_construct(pos, player) player:get_meta():set_string(NAME .. ":quarry_pos" , minetest.pos_to_string(pos)) local meta = minetest.get_meta(pos) meta:set_string("formspec", FORMSPEC) local inventory = meta:get_inventory() inventory:set_size('quarry', 96) end local function dig_node(pos, quarrypos) local node = minetest.get_node(pos) if node.name ~= "air" and sparktech.drain_energy(quarrypos, ENERGYCOST.mining) then local quarry = minetest.get_meta(quarrypos) local quarry_inv = quarry:get_inventory() sparktech.dig_node(pos, quarry_inv, "quarry", nil) end return node.name ~= "air" end local function on_marker_placed(pos, quarry_pos, player) -- Validate position if quarry_pos.x == pos.x and quarry_pos.y == pos.y and quarry_pos.z == pos.z then -- Invalid position, marker replaced quarry somehow return -- TODO Report failure? -- TODO clear clipboard in quarry on_break end local minx, maxx = math.order(pos.x, quarry_pos.x) local miny, maxy = math.order(pos.y, quarry_pos.y) local minz, maxz = math.order(pos.z, quarry_pos.z) local diffx = maxx - minx local diffy = maxy - miny local diffz = maxz - minz if diffx < 2 or diffx >= MAX_SIZE or diffy < 2 or diffy >= MAX_SIZE or diffz < 2 or diffz >= MAX_SIZE then notify.hud.sendtext(player, "Invalid dimensions for quarry 3x3x3") return end -- Set quarry metadata local meta = minetest.get_meta(quarry_pos) meta:set_string("marker", minetest.pos_to_string(pos)) meta:set_int("current_frame", 1) minetest.get_node_timer(quarry_pos):start(1.0) end local function marker_construct(pos, player) local quarry_pos = minetest.string_to_pos(player:get_meta():get_string(NAME .. ":quarry_pos")) local quarry = minetest.get_node(quarry_pos) on_marker_placed(pos, quarry_pos, player) end local function place_strut(position, quarrypos) if minetest.get_node(position).name == "air" then local placed = false if try_drain_energy(quarrypos, ENERGYCOST.static_strut) then if try_remove_item(quarrypos, "quarry", NAME .. ":static_strut") then minetest.set_node(position, { name = NAME .. ":static_strut"}) placed = true end end return true, placed end return false, false end local function prepare_area(pos, pos2) local placement_done = true local minx, maxx = math.order(pos.x, pos2.x) local miny, maxy = math.order(pos.y, pos2.y) local minz, maxz = math.order(pos.z, pos2.z) for x=minx , maxx do for y=miny, maxy do for z=minz, maxz do -- dont remove quarry or marker if not (x == pos.x and y == pos.y and z == pos.z) then local count = 0 if x == pos.x then count = count +1 end if x == pos2.x then count = count +1 end if y == pos.y then count = count +1 end if y == pos2.y then count = count +1 end if z == pos.z then count = count +1 end if z == pos2.z then count = count +1 end if count >= 2 then local node = minetest.get_node(Position(x, y, z)) if node.name ~= NAME .. ":static_strut" then if node.name ~= "air" then dig_node(Position(x, y, z), pos) return false end local incomplete, placed = place_strut(Position(x, y, z), pos) if placed then return false end if incomplete then placement_done = false end end else if dig_node(Position(x, y, z), pos) then return false end end end end end end return placement_done --true: cleared end local function timer_trigger(pos, elapsed) local meta = minetest.get_meta(pos) if not meta then assert("FUCK") end local framenum = meta:get_int("current_frame") local marker_pos = minetest.string_to_pos(meta:get_string("marker")) while true do -- Make this section breakable if framenum < 0 then -- Operation Phase -- local start_pos = minetest.string_to_pos(meta:get_string("dig_area_start")) local end_pos = minetest.string_to_pos(meta:get_string("dig_area_end")) if not start_pos or not end_pos then return end local height = start_pos.y + framenum local exitloop = false for x=start_pos.x, end_pos.x do for z=start_pos.z, end_pos.z do if dig_node(Position(x, height, z), pos) then exitloop = true end if exitloop then break end end if exitloop then break end end if not exitloop then -- Layer cleared, next layer framenum = framenum - 1 end elseif framenum == 1 then -- preparation phase if prepare_area(pos, marker_pos) then framenum = 0 end else --shrink the operational area here to a 2d space with one piece of border taken away to drill there -- local posx, pos2x = math.order(pos.x, marker_pos.x) local posy, pos2y = math.order(pos.y, marker_pos.y) local posz, pos2z = math.order(pos.z, marker_pos.z) posx = posx +1 pos2x = pos2x -1 posz = posz + 1 pos2z = pos2z -1 meta:set_string("dig_area_start", minetest.pos_to_string(Position(posx, posy, posz))) meta:set_string("dig_area_end", minetest.pos_to_string(Position(pos2x, posy, pos2z))) -- can use this last z as counter, or ignore it framenum = -1 end break end meta:set_int("current_frame", framenum) if framenum >= -MAX_SIZE then minetest.get_node_timer(pos):start(0.1) end end minetest.register_node( NAME .. ":quarry_marker", { descritption = "quarry marker", tiles = { NAME .. "marker.png" }, groups = { sparktech_techy = 1 }, after_place_node = marker_construct, }) minetest.register_node( NAME .. ":static_strut", { description = "supporting strut", drawtype = "nodebox", paramtype = "light", connects_to = { NAME .. ":static_strut", NAME .. ":quarry_marker", NAME .. ":lv_quarry" }, tiles = { NAME .. "_strut.png" }, node_box = { type = "connected", fixed = {-0.2, -0.2, -0.2, 0.2, 0.2, 0.2}, connect_top = {-0.2, 0.2, -0.2, 0.2, 0.5, 0.2}, connect_bottom = {-0.2, -0.5, -0.2, 0.2, -0.2, 0.2}, connect_back = {-0.2, -0.2, 0.2, 0.2, 0.2, 0.5}, connect_right = {0.2, -0.2, -0.2, 0.5, 0.2, 0.2}, connect_front = {-0.2, -0.2, -0.5, 0.2, 0.2, -0.2}, connect_left = {-0.5, -0.2, -0.2, -0.2, 0.2, 0.2}, }, groups = { sparktech_techy = 1 } }) minetest.register_node( NAME .. ":lv_quarry", { description = "Electric Quarry", tiles = { NAME .. "_steel_sideplate.png", NAME .. "_steel_sideplate.png", NAME .. "_steel_sideplate.png", NAME .. "_steel_sideplate.png", NAME .. "_steel_backplate.png", NAME .. "_quarry_frontplate.png" }, paramtype2 = "facedir", groups = { sparktech_techy = WRENCHABLE, sparktech_energy_type = ENERGY_CONSUMER, sparktech_net_trigger = TRUE, sparktech_energy_max = MAX_ENERGY, sparktech_energy_wakeup = ENERGYCOST.mining }, on_timer = timer_trigger, after_place_node = on_construct, --on_destruct = function(pos, player) player:get_meta():set_string(NAME .. ":quarry_pos" , "") end, allow_metadata_inventory_put = function(_,_,_, stack) return stack:get_count() end, allow_metadata_inventory_take = function(_, _, _, stack) return stack:get_count() end }) minetest.register_craft({ output = NAME .. ":lv_quarry", recipe = { { NAME .. ":static_strut", "sparktool:handdrill", NAME .. ":static_strut" }, { NAME .. ":static_strut", "group:steel_chasis", NAME .. ":static_strut" }, { NAME .. ":static_strut", "sparkcore:cable", NAME .. ":static_strut" } } }) minetest.register_craft({ output = NAME .. ":static_strut 16", recipe = { { "group:steel_plate", "group:steel_plate", "group:steel_plate" }, { "", "", "" }, { "group:steel_plate", "group:steel_plate", "group:steel_plate" } } })