Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- 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<bd then bd=d; best=c end
- end
- local ox,oy,oz = table.unpack(best)
- local sx = (ox==minX) and 1 or -1
- local sz = (oz==minZ) and 1 or -1
- local sy = 1 -- we will mine upward in chunks; oy is at minY
- log(("Box X[%d..%d] Y[%d..%d] Z[%d..%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.")
Add Comment
Please, Sign In to add comment