-- mine_volume.lua (CC:Tweaked Turtle) -- Mines a prompted rectangular volume from a prompted relative start offset. -- Optionally fills voids below the lowest Y of that volume with cobble (slot 2). -- Assumptions: -- - A fuel container is directly below start (y = -1). -- - A dump container is directly below that (y = -2). -- - Slot 2 contains cobblestone at start. Never fully consume or dump it. -- ======= User-tunable constants ======= local MIN_FUEL_BUFFER = 500 local COBBLE_SLOT = 2 local COBBLE_RESERVE = 16 local RETURN_INTERVAL_STEPS = 400 -- ====================================== local t = turtle -- state local pos = {x=0,y=0,z=0} -- start is (0,0,0) -- heading: 0=+X, 1=+Z, 2=-X, 3=-Z local heading = 0 local start_heading = heading -- capture initial facing to restore at the end -- utility: safe read local function read_num(prompt) while true do io.write(prompt); local s = read() local n = tonumber(s) if n and math.floor(n) == n then return n end print("Enter an integer.") end end local function read_yesno(prompt) while true do io.write(prompt.." [y/n]: "); local s = (read() or ""):lower() if s=="y" or s=="yes" then return true end if s=="n" or s=="no" then return false end end end -- movement wrappers local function select_nonempty() for i=1,16 do if t.getItemCount(i)>0 then t.select(i); return true end end return false end local function ensure_dig_forward() local tries = 0 while t.detect() do t.dig(); sleep(0.1); tries = tries + 1 if tries>50 then break end end end local function ensure_dig_up() local tries = 0 while t.detectUp() do t.digUp(); sleep(0.1); tries = tries + 1 if tries>50 then break end end end local function ensure_dig_down() local tries = 0 while t.detectDown() do t.digDown(); sleep(0.1); tries = tries + 1 if tries>50 then break end end end local function forward() local tries=0 while not t.forward() do ensure_dig_forward() if not t.forward() then t.attack(); sleep(0.1) tries=tries+1; if tries>50 then return false end end end if heading==0 then pos.x=pos.x+1 elseif heading==1 then pos.z=pos.z+1 elseif heading==2 then pos.x=pos.x-1 else pos.z=pos.z-1 end return true end local function up() local tries=0 while not t.up() do ensure_dig_up() if not t.up() then t.attackUp(); sleep(0.1) tries=tries+1; if tries>50 then return false end end end pos.y=pos.y+1; return true end local function down() local tries=0 while not t.down() do ensure_dig_down() if not t.down() then t.attackDown(); sleep(0.1) tries=tries+1; if tries>50 then return false end end end pos.y=pos.y-1; return true end local function turnLeft() heading=(heading+3)%4; t.turnLeft() end local function turnRight() heading=(heading+1)%4; t.turnRight() end local function face(dir) while heading~=dir do local diff = (dir - heading) % 4 if diff==1 then turnRight() elseif diff==3 then turnLeft() else turnRight() end end end local function mine_step_forward() ensure_dig_forward() forward() ensure_dig_up() ensure_dig_down() end -- inventory helpers local function free_slots() local free=0 for i=1,16 do if i~=COBBLE_SLOT and t.getItemCount(i)==0 then free=free+1 end end return free end local function need_dump() return free_slots()==0 end -- refuel from the fuel container directly below start local function refuel_from_home() for _=1,8 do for i=1,16 do if i~=COBBLE_SLOT then t.select(i) t.suckDown(64) if t.refuel(64) then if turtle.getFuelLevel()>=MIN_FUEL_BUFFER then return end else t.dropDown(64) end end end sleep(0.2) end end -- go_home with optional final facing local function go_home(final_face_dir) while pos.y>0 do up() end while pos.y<0 do down() end if pos.x>0 then face(2); for _=1,pos.x do forward() end elseif pos.x<0 then face(0); for _=1,-pos.x do forward() end end if pos.z>0 then face(3); for _=1,pos.z do forward() end elseif pos.z<0 then face(1); for _=1,-pos.z do forward() end end if final_face_dir~=nil then face(final_face_dir) end end -- service pocket near dump chest; preserves caller state local function ensure_dump_service() local saved = {x=pos.x,y=pos.y,z=pos.z,h=heading} -- assume starting from home face(0) ensure_dig_forward(); forward() -- (1,0,0) ensure_dig_down(); down() -- (1,-1,0) ensure_dig_down(); down() -- (1,-2,0) face(2); if t.detect() then t.dig() end forward() -- (0,-2,0) face(0); forward() -- (1,-2,0) up(); up() -- (1,0,0) face(2); forward() -- (0,0,0) face(saved.h) -- restore explicit pos since we tracked moves pos = {x=saved.x,y=saved.y,z=saved.z}; heading = saved.h end -- dump inventory except reserved cobble; preserves caller state and returns to home local function dump_at_home() local saved = {x=pos.x,y=pos.y,z=pos.z,h=heading} -- to cavity face(0); forward() -- (1,0,0); pos updated down(); down() -- (1,-2,0) face(2); forward() -- (0,-2,0) face(2) for i=1,16 do if i~=COBBLE_SLOT then local cnt = t.getItemCount(i) if cnt>0 then t.select(i); t.drop(64) end end end -- back to home face(0); forward() -- (1,-2,0) up(); up() -- (1,0,0) face(2); forward() -- (0,0,0) face(saved.h) pos = {x=saved.x,y=saved.y,z=saved.z}; heading = saved.h end local function goto_rel(tx,ty,tz) while pos.y < ty do up() end while pos.y > ty do down() end if pos.x < tx then face(0); for _=1, tx-pos.x do mine_step_forward() end elseif pos.x > tx then face(2); for _=1, pos.x-tx do mine_step_forward() end end if pos.z < tz then face(1); for _=1, tz-pos.z do mine_step_forward() end elseif pos.z > tz then face(3); for _=1, pos.z-tz do mine_step_forward() end end end local function ensure_fuel() if t.getFuelLevel()=="unlimited" then return end if t.getFuelLevel() < MIN_FUEL_BUFFER then local saved = {x=pos.x,y=pos.y,z=pos.z,h=heading} go_home() refuel_from_home() ensure_dump_service() goto_rel(saved.x,saved.y,saved.z); face(saved.h) end end local function maybe_fill_void_below(filling_enabled) if not filling_enabled then return end if t.detectDown() then return end local cnt = t.getItemCount(COBBLE_SLOT) if cnt and cnt > COBBLE_RESERVE then t.select(COBBLE_SLOT) t.placeDown() end end local function mine_cell(floorY, filling_enabled) ensure_dig_up() ensure_dig_down() if pos.y==floorY then maybe_fill_void_below(filling_enabled) end end local step_counter = 0 local function periodic_service() step_counter = step_counter + 1 if step_counter >= RETURN_INTERVAL_STEPS or need_dump() or (t.getFuelLevel()~="unlimited" and t.getFuelLevel()=1): ")) local Z = math.abs(read_num("Z (>=1): ")) local Y = math.abs(read_num("Y (>=1): ")) print("Enter relative start offset vector from current position.") local sx = read_num("Start offset dx (right +, left -): ") local sy = read_num("Start offset dy (up +, down -): ") local sz = read_num("Start offset dz (forward +, back -): ") local fill_voids = read_yesno("Fill empty space below the volume’s lowest Y with cobble from slot 2?") print("Preparing…") ensure_fuel() go_home() -- ensure pos=(0,0,0) ensure_dump_service() refuel_from_home() -- move to start offset goto_rel(sx, sy, sz) -- define floorY in current relative coordinates local floorY = pos.y -- mine by layers from floor up for layer=0,(Y-1) do goto_rel(pos.x, floorY + layer, pos.z) local dirX = 1 goto_rel(sx, floorY + layer, sz) face(0) for rz=0,(Z-1) do if dirX==1 then face(0) else face(2) end for rx=0,(X-1) do mine_cell(floorY, fill_voids) if not (rx==X-1 and rz==Z-1) then if rx < X-1 then ensure_fuel() mine_step_forward() end end periodic_service() end if rz < Z-1 then face(1); mine_step_forward() dirX = 1 - dirX end end end -- finish: return home, unload/refuel, then restore original facing go_home() ensure_dump_service() dump_at_home() refuel_from_home() face(start_heading) print("Done.")