-- drop_line.lua (CC:Tweaked)
-- Usage:
-- drop_line <incrementDir> [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 <right|left|up|down> [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
Comments