robathome icon

MC drop_line

robathome | PRO | 11/09/25 07:21:44 PM UTC | 0 ⭐ | 436 👁️ | Never ⏰ | []
text |

9.76 KB

|

None

|

0 👍

/

0 👎

-- 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