stairs.lua

305 lines · 7.3 KB

Open raw

Fast stair builder

Usage: stairs [headroom] [up/down] [length] [place]

Copy & run

wget https://perlytiara.github.io/turtles.tips/raw/programs/perlytiara/stairs/stairs.lua
1-- stairs.lua - Fast stair builder
2-- Usage: stairs [headroom] [up/down] [length] [place]
3-- headroom = blocks above each step, length = total steps to build
4
5local args = {...}
6
7local function hasTurtle()
8 return pcall(function() return turtle.getFuelLevel() end)
9end
10
11if not hasTurtle() then
12 print("Turtle required!")
13 return
14end
15
16-- Movement helpers
17local function df() while turtle.detect() do turtle.dig() end end
18local function du() while turtle.detectUp() do turtle.digUp() end end
19local function dd() while turtle.detectDown() do turtle.digDown() end end
20local function gf()
21 while not turtle.forward() do
22 if turtle.detect() then turtle.dig() end
23 turtle.attack()
24 end
25end
26local function gu()
27 while not turtle.up() do
28 if turtle.detectUp() then turtle.digUp() end
29 turtle.attackUp()
30 end
31end
32local function gd()
33 while not turtle.down() do
34 if turtle.detectDown() then turtle.digDown() end
35 turtle.attackDown()
36 end
37end
38
39-- Resource scanning and management
40local function scanInventory()
41 local fuel = 0
42 local blocks = 0
43 local fuelSlots = {}
44 local blockSlots = {}
45
46 for i = 1, 16 do
47 local count = turtle.getItemCount(i)
48 if count > 0 then
49 turtle.select(i)
50 local isFuel = turtle.refuel(0)
51 if isFuel then
52 fuel = fuel + count
53 table.insert(fuelSlots, i)
54 else
55 blocks = blocks + count
56 table.insert(blockSlots, i)
57 end
58 end
59 end
60
61 return {
62 fuel = fuel,
63 blocks = blocks,
64 fuelSlots = fuelSlots,
65 blockSlots = blockSlots
66 }
67end
68
69local function findBlockSlot()
70 for i = 1, 16 do
71 local count = turtle.getItemCount(i)
72 if count > 0 then
73 turtle.select(i)
74 local isFuel = turtle.refuel(0)
75 if not isFuel then return i end
76 end
77 end
78 return nil
79end
80
81local function placeFloor()
82 if not turtle.detectDown() then
83 local slot = findBlockSlot()
84 if slot then
85 turtle.select(slot)
86 turtle.placeDown()
87 end
88 end
89end
90
91-- Fuel management
92local function refuel(target)
93 if turtle.getFuelLevel() == "unlimited" then return true end
94
95 local current = turtle.getSelectedSlot()
96 for i = 1, 16 do
97 if turtle.getItemCount(i) > 0 then
98 turtle.select(i)
99 while turtle.getItemCount(i) > 0 and turtle.getFuelLevel() < target do
100 if not turtle.refuel(1) then break end
101 end
102 if turtle.getFuelLevel() >= target then break end
103 end
104 end
105 turtle.select(current)
106
107 if turtle.getFuelLevel() < target then
108 print("Need fuel! Current: " .. turtle.getFuelLevel())
109 print("Add coal/charcoal to any slot")
110 while turtle.getFuelLevel() < target do
111 sleep(1)
112 for i = 1, 16 do
113 if turtle.getItemCount(i) > 0 then
114 turtle.select(i)
115 if turtle.refuel(1) then break end
116 end
117 end
118 end
119 end
120 return true
121end
122
123-- Clear headroom
124local function clearUp(h)
125 du(); gu()
126 for i = 1, h - 1 do
127 du()
128 if i < h - 1 then gu() end
129 end
130 for i = 1, math.max(h - 2, 0) do gd() end
131end
132
133local function clearDown(h)
134 for i = 1, h - 1 do gu() end
135 du()
136 for i = 1, h - 1 do gd() end
137end
138
139-- Parse arguments
140local headroom = 3 -- blocks above each step
141local goUp = true
142local length = nil -- number of steps to build
143local autoPlace = false
144local autoLength = false -- use surface detection for up, or blocks available
145
146if #args >= 1 then
147 headroom = math.max(1, tonumber(args[1]) or 3)
148 for i = 2, #args do
149 local arg = string.lower(args[i])
150 local num = tonumber(args[i])
151 if num then
152 length = math.max(1, num)
153 autoLength = false
154 elseif arg == "down" then
155 goUp = false
156 elseif arg == "up" then
157 goUp = true
158 elseif arg == "place" then
159 autoPlace = true
160 elseif arg == "auto" then
161 autoLength = true
162 end
163 end
164else
165 -- Interactive prompts
166 term.clear()
167 term.setCursorPos(1, 1)
168 print("Stair Builder")
169
170 -- Scan resources first
171 local resources = scanInventory()
172 print("Resources: " .. resources.fuel .. " fuel, " .. resources.blocks .. " blocks")
173
174 write("Headroom (blocks above steps) [3]: ")
175 local h = read()
176 if h ~= "" then headroom = math.max(1, tonumber(h) or 3) end
177
178 write("Direction (u/d) [u]: ")
179 local dir = string.lower(read())
180 goUp = not (dir == "d" or dir == "down")
181
182 -- Length options
183 local maxSteps = math.floor(resources.blocks / (autoPlace and 1 or 0.1)) -- rough estimate
184 if goUp then
185 write("Length - steps/surface/auto [surface]: ")
186 local lengthInput = string.lower(read())
187 if lengthInput == "surface" or lengthInput == "" then
188 autoLength = true
189 length = nil
190 elseif lengthInput == "auto" then
191 autoLength = true
192 length = maxSteps
193 else
194 local num = tonumber(lengthInput)
195 if num then
196 length = math.max(1, num)
197 autoLength = false
198 else
199 autoLength = true
200 end
201 end
202 else
203 write("Depth (steps down) [32]: ")
204 local s = read()
205 length = math.max(1, tonumber(s) or 32)
206 autoLength = false
207 end
208
209 write("Place floor blocks? (y/n) [n]: ")
210 local place = string.lower(read())
211 autoPlace = (place == "y" or place == "yes")
212end
213
214-- Set defaults if not specified
215if not length and not autoLength then
216 if goUp then
217 autoLength = true -- surface detection for up
218 else
219 length = 32 -- default depth for down
220 end
221end
222
223-- Resource check and planning
224local resources = scanInventory()
225print("Building " .. (goUp and "up" or "down") .. " stairs")
226print("Headroom: " .. headroom .. " blocks above each step")
227
228if autoLength and goUp then
229 print("Mode: to surface (auto-detect)")
230elseif autoLength then
231 print("Length: auto (max " .. math.floor(resources.blocks / (autoPlace and 1 or 0.1)) .. " steps)")
232else
233 print("Length: " .. (length or "unknown") .. " steps")
234end
235
236print("Resources: " .. resources.fuel .. " fuel, " .. resources.blocks .. " blocks")
237
238-- Estimate what we can build
239local blocksPerStep = autoPlace and 1 or 0
240local maxPossibleSteps = blocksPerStep > 0 and math.floor(resources.blocks / blocksPerStep) or 999
241if autoPlace and maxPossibleSteps < (length or 32) then
242 print("Warning: Only enough blocks for " .. maxPossibleSteps .. " steps with floor placement")
243end
244
245-- Initial fuel check
246local fuelNeeded = (length or 64) * 3
247if resources.fuel * 80 < fuelNeeded then -- rough fuel value estimate
248 print("Warning: May need more fuel")
249end
250refuel(math.min(fuelNeeded, turtle.getFuelLevel() + 100))
251
252local step = 0
253local openStreak = 0
254
255while true do
256 step = step + 1
257
258 -- Refuel check every 8 steps
259 if step % 8 == 0 then
260 refuel(turtle.getFuelLevel() + 16)
261 end
262
263 -- Build step
264 if goUp then
265 df(); gf()
266 if autoPlace then placeFloor() end
267 clearUp(headroom)
268 else
269 df(); gf(); dd(); gd()
270 if autoPlace then placeFloor() end
271 clearDown(headroom)
272 end
273
274 -- Exit conditions
275 if not autoLength and step >= (length or 32) then
276 break
277 end
278
279 -- Surface detection for up stairs
280 if autoLength and goUp then
281 if not turtle.detect() and not turtle.detectUp() then
282 openStreak = openStreak + 1
283 else
284 openStreak = 0
285 end
286 if openStreak >= 5 then break end
287 end
288
289 -- Block limit check
290 if autoPlace then
291 local currentResources = scanInventory()
292 if currentResources.blocks <= 0 then
293 print("Out of blocks!")
294 break
295 end
296 end
297
298 if step >= 1000 then
299 print("Safety stop at 1000 steps")
300 break
301 end
302end
303
304print("Done! Built " .. step .. " steps")
305