robathome

MC drop_line

Nov 9th, 2025
255
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.76 KB | None | 0 0
  1. -- drop_line.lua (CC:Tweaked)
  2. -- Usage:
  3. -- drop_line <incrementDir> [numPasses]
  4. -- Examples:
  5. -- drop_line right 4
  6. -- drop_line up
  7. --
  8. -- Behavior:
  9. -- 1) right 4 -> Measure first pass length until front obstacle; then do 4 passes,
  10. -- shifting 1 block to the right between passes in zig-zag (R,R then L,L ...).
  11. -- 2) up -> After each pass, move up 1 and turn around; repeat until "up" is blocked.
  12. -- When "up" is blocked, do ONE FINAL opposite-direction pass that also places
  13. -- a block behind on each step, then stop.
  14.  
  15. local args = {...}
  16. if #args < 1 then
  17. print("Usage: drop_line <right|left|up|down> [numPasses]")
  18. return
  19. end
  20.  
  21. local incDir = string.lower(args[1])
  22. local fixedPasses = nil
  23. if args[2] ~= nil then
  24. fixedPasses = tonumber(args[2])
  25. if not fixedPasses or fixedPasses < 1 then
  26. print("Invalid numPasses: "..tostring(args[2]))
  27. return
  28. end
  29. end
  30.  
  31. local function isUnlimitedFuel()
  32. return turtle.getFuelLevel() == "unlimited"
  33. end
  34.  
  35. local function tryRefuelAll()
  36. if isUnlimitedFuel() then return true end
  37. for slot=1,16 do
  38. local detail = turtle.getItemDetail(slot)
  39. if detail then
  40. turtle.select(slot)
  41. -- One big gulp; if not fuel, refuel() returns false and nothing is consumed
  42. turtle.refuel(64)
  43. if isUnlimitedFuel() then return true end
  44. end
  45. end
  46. return turtle.getFuelLevel() > 0 or isUnlimitedFuel()
  47. end
  48.  
  49. local function ensureFuel()
  50. if not tryRefuelAll() then
  51. print("Warning: out of fuel and no refuel items found.")
  52. end
  53. end
  54.  
  55. local function attackClear(moveFn, detectFn, digFn, attackFn)
  56. -- Keep trying to clear entities; return true if space is clear after attempts
  57. local tries = 0
  58. while detectFn() do
  59. digFn()
  60. attackFn()
  61. tries = tries + 1
  62. if tries > 8 then break end
  63. end
  64. return not detectFn()
  65. end
  66.  
  67. local function forward()
  68. local tries = 0
  69. while not turtle.forward() do
  70. -- If blocked, try to dig/attack
  71. attackClear(turtle.forward, turtle.detect, turtle.dig, turtle.attack)
  72. if turtle.forward() then return true end
  73. tries = tries + 1
  74. if tries > 8 then return false end
  75. sleep(0.1)
  76. end
  77. return true
  78. end
  79.  
  80. local function up()
  81. local tries = 0
  82. while not turtle.up() do
  83. attackClear(turtle.up, turtle.detectUp, turtle.digUp, turtle.attackUp)
  84. if turtle.up() then return true end
  85. tries = tries + 1
  86. if tries > 6 then return false end
  87. sleep(0.1)
  88. end
  89. return true
  90. end
  91.  
  92. local function down()
  93. local tries = 0
  94. while not turtle.down() do
  95. attackClear(turtle.down, turtle.detectDown, turtle.digDown, turtle.attackDown)
  96. if turtle.down() then return true end
  97. tries = tries + 1
  98. if tries > 6 then return false end
  99. sleep(0.1)
  100. end
  101. return true
  102. end
  103.  
  104. local function turnRight() turtle.turnRight() end
  105. local function turnLeft() turtle.turnLeft() end
  106. local function turnAround() turnRight(); turnRight() end
  107.  
  108. local function selectPlaceableSlot()
  109. -- Pick any slot with an item; prefer non-fuel if possible by trying all slots
  110. -- We just cycle from 1..16 each time; quickest working heuristic.
  111. for slot=1,16 do
  112. local data = turtle.getItemDetail(slot)
  113. if data and data.count > 0 then
  114. turtle.select(slot)
  115. return true
  116. end
  117. end
  118. return false
  119. end
  120.  
  121. local function placeDownEnsured()
  122. if turtle.detectDown() then return true end
  123. if not selectPlaceableSlot() then return false end
  124. return turtle.placeDown()
  125. end
  126.  
  127. local function placeFrontEnsured()
  128. if turtle.detect() then return true end
  129. if not selectPlaceableSlot() then return false end
  130. return turtle.place()
  131. end
  132.  
  133. local function placeBehindEnsured()
  134. -- Turn around, place forward, turn back
  135. turnAround()
  136. local ok = placeFrontEnsured()
  137. turnAround()
  138. return ok
  139. end
  140.  
  141. local function stepForwardWithPlacement(opts)
  142. -- opts: { dropDown=true/false, dropBehind=false }
  143. local dropDown = opts and opts.dropDown ~= false -- default true
  144. local dropBehind = opts and opts.dropBehind == true
  145.  
  146. if dropDown then
  147. if not placeDownEnsured() then
  148. print("No placeable blocks for placeDown()")
  149. return false
  150. end
  151. end
  152.  
  153. if not forward() then
  154. print("Blocked: cannot move forward.")
  155. return false
  156. end
  157.  
  158. if dropBehind then
  159. if not placeBehindEnsured() then
  160. print("No placeable blocks for placeBehind()")
  161. -- Not fatal; keep going
  162. end
  163. end
  164.  
  165. return true
  166. end
  167.  
  168. local function measureFirstPassLength()
  169. -- Perform the measuring pass WITHOUT consuming its endpoint turn logic.
  170. -- We drop down each step, move forward until front is blocked.
  171. local steps = 0
  172. while not turtle.detect() do
  173. if not stepForwardWithPlacement({dropDown=true}) then
  174. return nil, "Failed during first-pass forward movement."
  175. end
  176. steps = steps + 1
  177. end
  178. return steps
  179. end
  180.  
  181. local function doPass(steps, opts)
  182. -- Walk exactly 'steps' forward-steps, dropping blocks each step.
  183. -- opts: { dropDown=true/false, dropBehind=false }
  184. for i=1,steps do
  185. if not stepForwardWithPlacement(opts) then
  186. return false, "Pass interrupted by obstacle."
  187. end
  188. end
  189. return true
  190. end
  191.  
  192. local function incrementRightTurnback(passIndex)
  193. -- Zig-zag lateral shift "right": odd passes end -> R, forward 1, R; even -> L, forward 1, L
  194. if passIndex % 2 == 1 then
  195. turnRight()
  196. if not forward() then return false, "Cannot shift right between passes." end
  197. turnRight()
  198. else
  199. turnLeft()
  200. if not forward() then return false, "Cannot shift right between passes." end
  201. turnLeft()
  202. end
  203. return true
  204. end
  205.  
  206. local function incrementLeftTurnback(passIndex)
  207. -- Mirror of "right"
  208. if passIndex % 2 == 1 then
  209. turnLeft()
  210. if not forward() then return false, "Cannot shift left between passes." end
  211. turnLeft()
  212. else
  213. turnRight()
  214. if not forward() then return false, "Cannot shift left between passes." end
  215. turnRight()
  216. end
  217. return true
  218. end
  219.  
  220. local function incrementUpTurnback()
  221. if not up() then return false end
  222. turnAround()
  223. return true
  224. end
  225.  
  226. local function incrementDownTurnback()
  227. if not down() then return false end
  228. turnAround()
  229. return true
  230. end
  231.  
  232. local function doRightFixedPasses(totalPasses, passLen)
  233. for p=1,totalPasses-1 do
  234. -- After each pass except the last, increment lateral + turnback
  235. local ok, msg = nil, nil
  236. if p % 2 == 1 then
  237. ok, msg = incrementRightTurnback(p)
  238. else
  239. ok, msg = incrementRightTurnback(p)
  240. end
  241. if not ok then return false, msg end
  242. -- next pass runs opposite direction but same length
  243. end
  244. return true
  245. end
  246.  
  247. local function doLeftFixedPasses(totalPasses, passLen)
  248. for p=1,totalPasses-1 do
  249. local ok, msg = incrementLeftTurnback(p)
  250. if not ok then return false, msg end
  251. end
  252. return true
  253. end
  254.  
  255. -- MAIN FLOW
  256. ensureFuel()
  257.  
  258. -- Validate increment direction
  259. local inc = incDir
  260. if inc ~= "right" and inc ~= "left" and inc ~= "up" and inc ~= "down" then
  261. print("incrementDir must be one of: right, left, up, down")
  262. return
  263. end
  264.  
  265. -- 1) First pass: go forward, drop-down each step, stop when front obstacle encountered
  266. local firstLen, err = measureFirstPassLength()
  267. if not firstLen then
  268. print("First pass failed: "..tostring(err))
  269. return
  270. end
  271. -- If zero-length (immediately blocked), just stop
  272. if firstLen == 0 then
  273. print("First pass length 0; nothing to do.")
  274. return
  275. end
  276.  
  277. -- 2) Execute the remaining passes per mode:
  278. if fixedPasses ~= nil then
  279. -- Fixed number of passes (e.g., "right 4")
  280. -- We already completed pass #1 (at current position, facing the obstacle).
  281. -- Now we must do (fixedPasses-1) further passes of the same length,
  282. -- shifting in the requested lateral direction between passes.
  283. for p=2,fixedPasses do
  284. -- Increment step+turnback before each new pass (except pass #1 which we already did)
  285. local ok, msg
  286. if inc == "right" then
  287. ok, msg = incrementRightTurnback(p-1)
  288. elseif inc == "left" then
  289. ok, msg = incrementLeftTurnback(p-1)
  290. elseif inc == "up" then
  291. ok, msg = incrementUpTurnback()
  292. elseif inc == "down" then
  293. ok, msg = incrementDownTurnback()
  294. end
  295. if not ok then
  296. print("Increment failed between passes: "..tostring(msg or ""))
  297. return
  298. end
  299. local ok2, msg2 = doPass(firstLen, {dropDown=true})
  300. if not ok2 then
  301. print("Pass "..p.." failed: "..tostring(msg2 or ""))
  302. return
  303. end
  304. end
  305. print("Completed "..fixedPasses.." passes of length "..firstLen..".")
  306. else
  307. -- Variable passes until blocked in increment direction (intended for "up" case).
  308. -- After each pass, try to increment; if increment fails (blocked), then do ONE FINAL
  309. -- opposite-direction pass with "dropBehind=true" on each step, then stop.
  310. if inc ~= "up" and inc ~= "down" then
  311. print("When numPasses is omitted, use 'up' or 'down'.")
  312. return
  313. end
  314.  
  315. while true do
  316. -- Try to increment (move up/down and turn around)
  317. local incOK = false
  318. if inc == "up" then incOK = incrementUpTurnback()
  319. else incOK = incrementDownTurnback()
  320. end
  321.  
  322. if not incOK then
  323. -- Final pass with blocks behind on each step, then finish
  324. local okFinal, msgFinal = doPass(firstLen, {dropDown=true, dropBehind=true})
  325. if not okFinal then
  326. print("Final behind-pass failed: "..tostring(msgFinal or ""))
  327. else
  328. print("Reached increment obstacle; final behind-pass completed.")
  329. end
  330. return
  331. end
  332.  
  333. -- Normal opposite-direction pass, same length
  334. local ok2, msg2 = doPass(firstLen, {dropDown=true})
  335. if not ok2 then
  336. print("Pass failed after increment: "..tostring(msg2 or ""))
  337. return
  338. end
  339. -- Loop continues: attempt another increment until blocked
  340. end
  341. end
  342.  
Add Comment
Please, Sign In to add comment