-- drop_line.lua (CC:Tweaked) -- Usage: -- drop_line [numPasses] -- Examples: -- drop_line right 4 -- drop_line up -- -- Behavior: -- 1) right 4 -> Measure first pass length until front obstacle; then do 4 passes, -- shifting 1 block to the right between passes in zig-zag (R,R then L,L ...). -- 2) up -> After each pass, move up 1 and turn around; repeat until "up" is blocked. -- When "up" is blocked, do ONE FINAL opposite-direction pass that also places -- a block behind on each step, then stop. local args = {...} if #args < 1 then print("Usage: drop_line [numPasses]") return end local incDir = string.lower(args[1]) local fixedPasses = nil if args[2] ~= nil then fixedPasses = tonumber(args[2]) if not fixedPasses or fixedPasses < 1 then print("Invalid numPasses: "..tostring(args[2])) return end end local function isUnlimitedFuel() return turtle.getFuelLevel() == "unlimited" end local function tryRefuelAll() if isUnlimitedFuel() then return true end for slot=1,16 do local detail = turtle.getItemDetail(slot) if detail then turtle.select(slot) -- One big gulp; if not fuel, refuel() returns false and nothing is consumed turtle.refuel(64) if isUnlimitedFuel() then return true end end end return turtle.getFuelLevel() > 0 or isUnlimitedFuel() end local function ensureFuel() if not tryRefuelAll() then print("Warning: out of fuel and no refuel items found.") end end local function attackClear(moveFn, detectFn, digFn, attackFn) -- Keep trying to clear entities; return true if space is clear after attempts local tries = 0 while detectFn() do digFn() attackFn() tries = tries + 1 if tries > 8 then break end end return not detectFn() end local function forward() local tries = 0 while not turtle.forward() do -- If blocked, try to dig/attack attackClear(turtle.forward, turtle.detect, turtle.dig, turtle.attack) if turtle.forward() then return true end tries = tries + 1 if tries > 8 then return false end sleep(0.1) end return true end local function up() local tries = 0 while not turtle.up() do attackClear(turtle.up, turtle.detectUp, turtle.digUp, turtle.attackUp) if turtle.up() then return true end tries = tries + 1 if tries > 6 then return false end sleep(0.1) end return true end local function down() local tries = 0 while not turtle.down() do attackClear(turtle.down, turtle.detectDown, turtle.digDown, turtle.attackDown) if turtle.down() then return true end tries = tries + 1 if tries > 6 then return false end sleep(0.1) end return true end local function turnRight() turtle.turnRight() end local function turnLeft() turtle.turnLeft() end local function turnAround() turnRight(); turnRight() end local function selectPlaceableSlot() -- Pick any slot with an item; prefer non-fuel if possible by trying all slots -- We just cycle from 1..16 each time; quickest working heuristic. for slot=1,16 do local data = turtle.getItemDetail(slot) if data and data.count > 0 then turtle.select(slot) return true end end return false end local function placeDownEnsured() if turtle.detectDown() then return true end if not selectPlaceableSlot() then return false end return turtle.placeDown() end local function placeFrontEnsured() if turtle.detect() then return true end if not selectPlaceableSlot() then return false end return turtle.place() end local function placeBehindEnsured() -- Turn around, place forward, turn back turnAround() local ok = placeFrontEnsured() turnAround() return ok end local function stepForwardWithPlacement(opts) -- opts: { dropDown=true/false, dropBehind=false } local dropDown = opts and opts.dropDown ~= false -- default true local dropBehind = opts and opts.dropBehind == true if dropDown then if not placeDownEnsured() then print("No placeable blocks for placeDown()") return false end end if not forward() then print("Blocked: cannot move forward.") return false end if dropBehind then if not placeBehindEnsured() then print("No placeable blocks for placeBehind()") -- Not fatal; keep going end end return true end local function measureFirstPassLength() -- Perform the measuring pass WITHOUT consuming its endpoint turn logic. -- We drop down each step, move forward until front is blocked. local steps = 0 while not turtle.detect() do if not stepForwardWithPlacement({dropDown=true}) then return nil, "Failed during first-pass forward movement." end steps = steps + 1 end return steps end local function doPass(steps, opts) -- Walk exactly 'steps' forward-steps, dropping blocks each step. -- opts: { dropDown=true/false, dropBehind=false } for i=1,steps do if not stepForwardWithPlacement(opts) then return false, "Pass interrupted by obstacle." end end return true end local function incrementRightTurnback(passIndex) -- Zig-zag lateral shift "right": odd passes end -> R, forward 1, R; even -> L, forward 1, L if passIndex % 2 == 1 then turnRight() if not forward() then return false, "Cannot shift right between passes." end turnRight() else turnLeft() if not forward() then return false, "Cannot shift right between passes." end turnLeft() end return true end local function incrementLeftTurnback(passIndex) -- Mirror of "right" if passIndex % 2 == 1 then turnLeft() if not forward() then return false, "Cannot shift left between passes." end turnLeft() else turnRight() if not forward() then return false, "Cannot shift left between passes." end turnRight() end return true end local function incrementUpTurnback() if not up() then return false end turnAround() return true end local function incrementDownTurnback() if not down() then return false end turnAround() return true end local function doRightFixedPasses(totalPasses, passLen) for p=1,totalPasses-1 do -- After each pass except the last, increment lateral + turnback local ok, msg = nil, nil if p % 2 == 1 then ok, msg = incrementRightTurnback(p) else ok, msg = incrementRightTurnback(p) end if not ok then return false, msg end -- next pass runs opposite direction but same length end return true end local function doLeftFixedPasses(totalPasses, passLen) for p=1,totalPasses-1 do local ok, msg = incrementLeftTurnback(p) if not ok then return false, msg end end return true end -- MAIN FLOW ensureFuel() -- Validate increment direction local inc = incDir if inc ~= "right" and inc ~= "left" and inc ~= "up" and inc ~= "down" then print("incrementDir must be one of: right, left, up, down") return end -- 1) First pass: go forward, drop-down each step, stop when front obstacle encountered local firstLen, err = measureFirstPassLength() if not firstLen then print("First pass failed: "..tostring(err)) return end -- If zero-length (immediately blocked), just stop if firstLen == 0 then print("First pass length 0; nothing to do.") return end -- 2) Execute the remaining passes per mode: if fixedPasses ~= nil then -- Fixed number of passes (e.g., "right 4") -- We already completed pass #1 (at current position, facing the obstacle). -- Now we must do (fixedPasses-1) further passes of the same length, -- shifting in the requested lateral direction between passes. for p=2,fixedPasses do -- Increment step+turnback before each new pass (except pass #1 which we already did) local ok, msg if inc == "right" then ok, msg = incrementRightTurnback(p-1) elseif inc == "left" then ok, msg = incrementLeftTurnback(p-1) elseif inc == "up" then ok, msg = incrementUpTurnback() elseif inc == "down" then ok, msg = incrementDownTurnback() end if not ok then print("Increment failed between passes: "..tostring(msg or "")) return end local ok2, msg2 = doPass(firstLen, {dropDown=true}) if not ok2 then print("Pass "..p.." failed: "..tostring(msg2 or "")) return end end print("Completed "..fixedPasses.." passes of length "..firstLen..".") else -- Variable passes until blocked in increment direction (intended for "up" case). -- After each pass, try to increment; if increment fails (blocked), then do ONE FINAL -- opposite-direction pass with "dropBehind=true" on each step, then stop. if inc ~= "up" and inc ~= "down" then print("When numPasses is omitted, use 'up' or 'down'.") return end while true do -- Try to increment (move up/down and turn around) local incOK = false if inc == "up" then incOK = incrementUpTurnback() else incOK = incrementDownTurnback() end if not incOK then -- Final pass with blocks behind on each step, then finish local okFinal, msgFinal = doPass(firstLen, {dropDown=true, dropBehind=true}) if not okFinal then print("Final behind-pass failed: "..tostring(msgFinal or "")) else print("Reached increment obstacle; final behind-pass completed.") end return end -- Normal opposite-direction pass, same length local ok2, msg2 = doPass(firstLen, {dropDown=true}) if not ok2 then print("Pass failed after increment: "..tostring(msg2 or "")) return end -- Loop continues: attempt another increment until blocked end end