-- turtle_mine_coords.lua (CC:Tweaked) -- Mine a rectangular volume defined by two GPS corners (x1,x2 then y1,y2 then z1,z2). -- Uses GPS only to pick and reach the nearest corner, then mines with relative moves. -- Slot 1 = fuel. Slots 2..16 = filler for water/lava. Rednet protocol tmine.v1. local PROTO = "tmine.v1" -- ---------- Modem / Rednet ---------- local function openAnyModem() for _,side in ipairs(rs.getSides()) do if peripheral.getType(side) == "modem" then local m = peripheral.wrap(side) if m and m.isWireless and m.isWireless() then rednet.open(side); return true end end end return false end assert(openAnyModem(), "No wireless modem found/opened") local function log(msg) print(msg) rednet.broadcast({id=os.getComputerID(), msg=msg, t=os.epoch("utc")}, PROTO) end -- ---------- GPS ---------- local function gpsPos() local x,y,z = gps.locate(2.0); return x,y,z end do local x,y,z=gpsPos(); assert(x and y and z,"GPS not available"); log(("GPS lock: (%.1f, %.1f, %.1f)"):format(x,y,z)) end -- ---------- Fuel ---------- local function refuel(minFuel) if turtle.getFuelLevel()=="unlimited" then return true end minFuel = minFuel or 400 if turtle.getFuelLevel() >= minFuel then return true end local keep = turtle.getSelectedSlot() turtle.select(1) while turtle.getFuelLevel() < minFuel do if turtle.getItemCount(1)==0 then turtle.select(keep); log("Fuel low; slot1 empty"); return false end turtle.refuel(1) end turtle.select(keep); return true end -- ---------- Liquids / Filler ---------- local function selectFillSlot() for s=2,16 do if turtle.getItemCount(s)>0 then turtle.select(s); return true end end return false end local function isLiquid(info) return info and info.name and (info.name:find("water") or info.name:find("lava")) end local function damFront() local ok,d=turtle.inspect(); if ok and isLiquid(d) then if selectFillSlot() then if turtle.place() then log("Dam front") end end end end local function damUp() local ok,d=turtle.inspectUp(); if ok and isLiquid(d) then if selectFillSlot() then if turtle.placeUp() then log("Dam up") end end end end local function damDown() local ok,d=turtle.inspectDown(); if ok and isLiquid(d) then if selectFillSlot() then if turtle.placeDown() then log("Dam down") end end end end -- ---------- Dig-safe moves ---------- local function fwd() while true do damFront() local ok,d=turtle.inspect(); if ok and not isLiquid(d) then turtle.dig() end if turtle.forward() then assertInside("forward"); return true end sleep(0.1) end end local function up() while true do damUp() local ok,d=turtle.inspectUp(); if ok and not isLiquid(d) then turtle.digUp() end if turtle.up() then assertInside("up"); return true end sleep(0.1) end end local function down() while true do damDown() local ok,d=turtle.inspectDown(); if ok and not isLiquid(d) then turtle.digDown() end if turtle.down() then assertInside("down"); return true end sleep(0.1) end end ---------- Heading control ---------- local heading = 0 -- 0=+X,1=+Z,2=-X,3=-Z local function right() turtle.turnRight(); heading=(heading+1)%4 end local function left() turtle.turnLeft(); heading=(heading+3)%4 end local function face(dir) local d=(dir-heading)%4 if d==1 then right() elseif d==2 then right(); right() elseif d==3 then left() end end -- ---------- Move to absolute GPS corner (one-time) ---------- local function moveAxis(axis, delta) if delta==0 then return end if axis=="x" then face(delta>0 and 0 or 2); for i=1,math.abs(delta) do refuel(200); fwd() end elseif axis=="z" then face(delta>0 and 1 or 3); for i=1,math.abs(delta) do refuel(200); fwd() end elseif axis=="y" then local step = delta>0 and up or down; for i=1,math.abs(delta) do refuel(200); step() end end end local function gotoXYZ(tx,ty,tz) local x,y,z = gpsPos(); assert(x,"GPS lost") moveAxis("x", math.floor(tx - x + 0.5)) x,y,z = gpsPos() moveAxis("z", math.floor(tz - z + 0.5)) x,y,z = gpsPos() moveAxis("y", math.floor(ty - y + 0.5)) end -- ---------- Vertical step actions ---------- local function step_3layer() damUp(); local okU,du=turtle.inspectUp(); if okU and not isLiquid(du) then turtle.digUp() end damDown(); local okD,dd=turtle.inspectDown(); if okD and not isLiquid(dd) then turtle.digDown() end end local function step_2layer() damDown(); local okD,dd=turtle.inspectDown(); if okD and not isLiquid(dd) then turtle.digDown() end end local function step_1layer() end -- ---------- Serpentine over XZ (relative, bounded) ---------- -- Start at the chosen origin corner on the current Y layer. -- enterDirX: 0 for +X travel on first row, 2 for -X. -- Directions based on chosen corner local DIR_X_POS = (sx==1) and 0 or 2 -- face(+X in world) local DIR_X_NEG = (sx==1) and 2 or 0 -- face(-X in world) local DIR_Z_STEP= (sz==1) and 1 or 3 -- step toward interior along Z local DIR_Z_BACK= (sz==1) and 3 or 1 -- return toward origin along Z -- enterDirX must be either DIR_X_POS or DIR_X_NEG local function serpentine_pass(nx, nz, enterDirX, stepAction) -- First row face(enterDirX) stepAction() for i=2,nx do fwd(); stepAction() end -- Remaining rows local curDir = enterDirX for row=1,(nz-1) do -- advance one row along Z (toward interior) face(DIR_Z_STEP); fwd() -- flip X direction curDir = (curDir==DIR_X_POS) and DIR_X_NEG or DIR_X_POS face(curDir) stepAction() for i=2,nx do fwd(); stepAction() end end -- Return to origin corner in-plane if (nz % 2)==1 then -- We ended on the far X edge; go back along X to origin edge face((curDir==DIR_X_POS) and DIR_X_NEG or DIR_X_POS) for i=2,nx do fwd() end end -- Go back along Z to origin face(DIR_Z_BACK) for i=2,nz do fwd() end end -- ---------- Input ---------- local function readNum(p) term.write(p); local s=read(); local n=tonumber(s); assert(n,"number"); return n end term.clear(); term.setCursorPos(1,1) print("Volume Miner by Coordinates (slot1=fuel; 2..16 filler)") print("Enter X limits first, then Y, then Z. Any order allowed within each pair.") local x1 = readNum("x1: "); local x2 = readNum("x2: ") local y1 = readNum("y1: "); local y2 = readNum("y2: ") local z1 = readNum("z1: "); local z2 = readNum("z2: ") local minX,maxX = math.floor(math.min(x1,x2)), math.floor(math.max(x1,x2)) local minY,maxY = math.floor(math.min(y1,y2)), math.floor(math.max(y1,y2)) local minZ,maxZ = math.floor(math.min(z1,z2)), math.floor(math.max(z1,z2)) local nx = maxX - minX + 1 local ny = maxY - minY + 1 local nz = maxZ - minZ + 1 assert(nx>0 and ny>0 and nz>0, "empty volume") local function assertInside(where) local x,y,z = gps.locate(2.0) if not x then error("GPS lost during "..where, 0) end if x < minX or x > maxX or y < minY or y > maxY or z < minZ or z > maxZ then error(("ABORT: left volume at %s (%.0f,%.0f,%.0f)"):format(where,x,y,z), 0) end end -- Choose the nearest of the four bottom-layer corners (we’ll handle vertical later) local cx,cy,cz = gpsPos(); assert(cx,"GPS lost") local candidates = { {minX,minY,minZ}, {maxX,minY,minZ}, {minX,minY,maxZ}, {maxX,minY,maxZ}, } local best,bd=nil,1e18 for _,c in ipairs(candidates) do local d=math.abs(c[1]-cx)+math.abs(c[2]-cy)+math.abs(c[3]-cz) if d %dx%dx%d"):format(minX,maxX,minY,maxY,minZ,maxZ,nx,ny,nz)) log(("Origin corner: (%d,%d,%d) dir sx=%d sz=%d"):format(ox,oy,oz,sx,sz)) -- Go to origin corner once gotoXYZ(ox,oy,oz) -- Orient first-row X direction based on sx local enterDirX = (sx==1) and DIR_X_POS or DIR_X_NEG -- Before each pass, ensure we are at the plane origin corner (we already are after our return) local currentY = oy local remaining = ny -- Helper: raise/lower to specific absolute Y by relative move (no GPS during mining) local function goToYAbs(targetY) local x,y,z = gpsPos(); assert(x,"GPS lost") local dy = targetY - y if dy>0 then for i=1,dy do up() end elseif dy<0 then for i=1,-dy do down() end end end assertInside("start") -- Vertical policy loop while remaining > 0 do refuel(nx*nz*math.min(remaining,3) + 300) if remaining >= 3 then -- Middle of the 3-layer chunk local midY = currentY + 1 goToYAbs(midY) -- Serpentine on this layer, clearing up and down each cell serpentine_pass(nx, nz, enterDirX, step_3layer); assertInside("after 3-layer") currentY = currentY + 3 remaining = remaining - 3 elseif remaining == 2 then -- Upper of the 2-layer chunk local upperY = currentY + 1 goToYAbs(upperY) serpentine_pass(nx, nz, enterDirX, step_2layer); assertInside("after 2-layer") currentY = currentY + 2 remaining = remaining - 2 else -- remaining == 1 goToYAbs(currentY) serpentine_pass(nx, nz, enterDirX, step_1layer); assertInside("after 1-layer") currentY = currentY + 1 remaining = remaining - 1 end -- After each pass, we are returned to the same XZ origin corner by serpentine_pass. end local ex,ey,ez = gpsPos() log(("Complete. End GPS: (%.1f, %.1f, %.1f)"):format(ex or -1, ey or -1, ez or -1)) print("Mining complete.")