entrance_carver.lua

240 lines · 12.9 KB

Open raw

Entrance Carver by Silvamord Carves a rectangular entrance corridor with configurable width, height (above/below floor), and length. Start modes: - center: turtle stands at center column of doorway - bottom-left: turtle stands at doorway's bottom-left corner Features: torches (left/right/both, spacing), chest dump, throw items by sample, favorite config, auto-return for fuel along corridor. ]]-- local version = "1.0" -- UI helpers local function ask_number_default(prompt, default_value, min_val, max_val) while true do term.clear(); term.setCursorPos(1,1) write("Entrance Carver v"..version.."\n\n") write(string.format("%s [default: %s] ", prompt, tostring(default_value))) local s = read(); if s == nil or s == "" then return default_value end local n = tonumber(s) if n and (not min_val or n >= min_val) and (not max_val or n <= max_val) then return n end write("\nInvalid input. Press Enter to try again."); read() end end local function ask_yes_no(prompt, default_yes) while true do term.clear(); term.setCursorPos(1,1) write("Entrance Carver v"..version.."\n\n") local def = default_yes and "Y" or "N"

Copy & run

wget https://perlytiara.github.io/turtles.tips/raw/programs/perlytiara/entrance_carver.lua
1--[[
2 Entrance Carver by Silvamord
3 Carves a rectangular entrance corridor with configurable width, height (above/below floor), and length.
4 Start modes:
5 - center: turtle stands at center column of doorway
6 - bottom-left: turtle stands at doorway's bottom-left corner
7
8 Features: torches (left/right/both, spacing), chest dump, throw items by sample, favorite config, auto-return for fuel along corridor.
9]]--
10
11local version = "1.0"
12
13-- UI helpers
14local function ask_number_default(prompt, default_value, min_val, max_val)
15 while true do
16 term.clear(); term.setCursorPos(1,1)
17 write("Entrance Carver v"..version.."\n\n")
18 write(string.format("%s [default: %s] ", prompt, tostring(default_value)))
19 local s = read(); if s == nil or s == "" then return default_value end
20 local n = tonumber(s)
21 if n and (not min_val or n >= min_val) and (not max_val or n <= max_val) then return n end
22 write("\nInvalid input. Press Enter to try again."); read()
23 end
24end
25
26local function ask_yes_no(prompt, default_yes)
27 while true do
28 term.clear(); term.setCursorPos(1,1)
29 write("Entrance Carver v"..version.."\n\n")
30 local def = default_yes and "Y" or "N"
31 write(string.format("%s (y/n) [default: %s] ", prompt, def))
32 local s = read(); s = s and string.lower(s) or ""
33 if s == "" then return default_yes end
34 if s == "y" or s == "yes" then return true end
35 if s == "n" or s == "no" then return false end
36 write("\nInvalid input. Press Enter to try again."); read()
37 end
38end
39
40local function ask_choice(prompt, default_value, choices)
41 while true do
42 term.clear(); term.setCursorPos(1,1)
43 write("Entrance Carver v"..version.."\n\n")
44 write(string.format("%s %s [default: %s] ", prompt, table.concat(choices, "/"), tostring(default_value)))
45 local s = read(); if s == nil or s == "" then return default_value end
46 s = string.lower(s)
47 for _, c in ipairs(choices) do if s == c then return s end end
48 write("\nInvalid input. Press Enter to try again."); read()
49 end
50end
51
52-- Movement helpers
53local function ensure_fuel(threshold)
54 if turtle.getFuelLevel() == "unlimited" then return end
55 if turtle.getFuelLevel() >= threshold then return end
56 for i=1,16 do
57 turtle.select(i)
58 if turtle.refuel(0) then while turtle.getFuelLevel()<threshold and turtle.refuel(1) do end; if turtle.getFuelLevel()>=threshold then return end end
59 end
60 term.clear(); term.setCursorPos(1,1); print("Out of fuel. Add fuel and press Enter."); read();
61 return ensure_fuel(threshold)
62end
63
64local function dig_forward() while turtle.detect() do if not turtle.dig() then turtle.attack(); sleep(0.1) end end end
65local function dig_upwards() while turtle.detectUp() do if not turtle.digUp() then turtle.attackUp(); sleep(0.1) end end end
66local function dig_downwards() while turtle.detectDown() do if not turtle.digDown() then turtle.attackDown(); sleep(0.1) end end end
67
68local function safe_forward() ensure_fuel(100); while not turtle.forward() do dig_forward(); sleep(0.05) end end
69local function safe_up() ensure_fuel(100); while not turtle.up() do dig_upwards(); sleep(0.05) end end
70local function safe_down() ensure_fuel(100); while not turtle.down() do dig_downwards(); sleep(0.05) end end
71
72local function turn_left() turtle.turnLeft() end
73local function turn_right() turtle.turnRight() end
74local function step_right() turn_right(); dig_forward(); safe_forward(); turn_left() end
75local function step_left() turn_left(); dig_forward(); safe_forward(); turn_right() end
76
77-- Favorites
78local function favorite_path()
79 local dir = ".entrance_carver"; if not fs.exists(dir) then fs.makeDir(dir) end
80 return fs.combine(dir, "favorite")
81end
82local function load_favorite()
83 local p = favorite_path(); if not fs.exists(p) then return nil end
84 local h = fs.open(p, "r"); if not h then return nil end; local d=h.readAll(); h.close()
85 local ok,t = pcall(textutils.unserialize,d); if ok and type(t)=="table" then return t end; return nil
86end
87local function save_favorite(tbl)
88 local p = favorite_path(); local h = fs.open(p,"w"); if not h then return end; h.write(textutils.serialize(tbl)); h.close()
89end
90
91-- Inventory & IO
92local function count_empty_slots() local e=0; for i=1,16 do if turtle.getItemCount(i)==0 then e=e+1 end end; return e end
93local function any_item_matches_slot(slot_idx)
94 if turtle.getItemCount(slot_idx)==0 then return false end
95 for i=1,16 do if i~=slot_idx and turtle.getItemCount(i)>0 then turtle.select(i); if turtle.compareTo(slot_idx) then return true end end end
96 return false
97end
98local function drop_matching_front(slot_idx)
99 for i=1,16 do if i~=slot_idx and turtle.getItemCount(i)>0 then turtle.select(i); if turtle.compareTo(slot_idx) then turtle.drop() end end end
100end
101local function turn_to_side(side) if side=="left" then turn_left() else turn_right() end end
102local function place_chest_in_wall(chest_slot, side)
103 if turtle.getItemCount(chest_slot)==0 then return false end
104 turn_to_side(side); dig_forward(); turtle.select(chest_slot)
105 local ok = turtle.place(); if not ok then dig_forward(); ok = turtle.place() end; if not ok then ok = turtle.placeDown() end
106 turn_to_side(side=="left" and "right" or "left"); return ok
107end
108local function deposit_into_front(chest_slot, torch_slot, throw_slot)
109 for i=1,16 do if i~=chest_slot and i~=torch_slot and i~=throw_slot and turtle.getItemCount(i)>0 then turtle.select(i); if not turtle.refuel(0) then turtle.drop() end end end
110 if throw_slot then local cnt=turtle.getItemCount(throw_slot); if cnt>1 then turtle.select(throw_slot); turtle.drop(cnt-1) end end
111end
112local function ensure_inventory_capacity(cfg, at_left)
113 if count_empty_slots()>0 then return end
114 if cfg.use_throw and turtle.getItemCount(cfg.throw_slot)>0 and any_item_matches_slot(cfg.throw_slot) then
115 drop_matching_front(cfg.throw_slot); if count_empty_slots()>0 then return end
116 end
117 if cfg.use_chests then local side = at_left and "left" or "right"; if place_chest_in_wall(cfg.chest_slot, side) then deposit_into_front(cfg.chest_slot, cfg.torch_slot, cfg.throw_slot) end end
118end
119
120-- Torches
121local function place_torch_if_needed(step_idx, cfg, width, at_left)
122 if not cfg.use_torches or cfg.torch_spacing<=0 then return end
123 if step_idx % cfg.torch_spacing ~= 0 then return end
124 if turtle.getItemCount(cfg.torch_slot)==0 then return end
125 local function place_on(side)
126 local climbed = 0; if width>=3 then safe_up(); climbed=1 end
127 turn_to_side(side); turtle.select(cfg.torch_slot)
128 local ok = turtle.place(); if not ok then turn_to_side(side=="left" and "right" or "left"); for i=1,climbed do safe_down() end; turtle.select(cfg.torch_slot); turtle.placeDown(); return end
129 turn_to_side(side=="left" and "right" or "left"); for i=1,climbed do safe_down() end
130 end
131 if cfg.torch_side=="both" then if at_left then place_on("left"); place_on("right") else place_on("right"); place_on("left") end else place_on(cfg.torch_side) end
132end
133
134-- Carve one corridor slice at current face, optimized using level-2 reach
135local function carve_slice(width, above, below, start_at_left, current_level)
136 local work_level = (above>=2) and 2 or 1
137 if (current_level or 1) < work_level then while (current_level or 1) < work_level do safe_up(); current_level=(current_level or 1)+1 end end
138 if (current_level or 1) > work_level then while (current_level or 1) > work_level do safe_down(); current_level=(current_level or 1)-1 end end
139 local end_at_left
140 if start_at_left then
141 for x=1,width do
142 if work_level==1 then dig_forward() else turtle.digDown(); if above>=2 then dig_upwards() end end
143 if x<width then step_right() end
144 end
145 end_at_left=false
146 else
147 for x=width,1,-1 do
148 if work_level==1 then dig_forward() else turtle.digDown(); if above>=2 then dig_upwards() end end
149 if x>1 then step_left() end
150 end
151 end_at_left=true
152 end
153 if above>=3 then safe_up(); if start_at_left then for x=1,width do dig_upwards(); if x<width then step_right() end end else for x=width,1,-1 do dig_upwards(); if x>1 then step_left() end end end; safe_down() end
154 if below>=1 then if work_level==2 then safe_down() end; if start_at_left then for x=1,width do turtle.digDown(); if x<width then step_right() end end else for x=width,1,-1 do turtle.digDown(); if x>1 then step_left() end end end; if work_level==2 then safe_up() end end
155 return end_at_left, work_level
156end
157
158local function estimate_moves_per_slice(width, above, below)
159 local vertical = (above>=2) and 1 or 0; if above>=3 then vertical=vertical+2 end; if below>=1 and above>=2 then vertical=vertical+2 end
160 local lateral = (width-1)
161 local advance = 1
162 return vertical + lateral + advance
163end
164
165local function attempt_return_for_refuel(depth, reserve_needed)
166 local minimal = depth*2 + 4
167 if turtle.getFuelLevel() ~= "unlimited" and turtle.getFuelLevel() < minimal then ensure_fuel(minimal) end
168 turn_right(); turn_right(); for i=1,depth do safe_forward() end
169 term.clear(); term.setCursorPos(1,1); print("At start. Add fuel/torches, press Enter."); read()
170 ensure_fuel(reserve_needed)
171 turn_right(); turn_right(); for i=1,depth do safe_forward() end
172end
173
174local function main()
175 term.clear(); term.setCursorPos(1,1); print("Entrance Carver v"..version); print("Place turtle at doorway, facing wall.")
176 local fav = load_favorite(); local use_fav = fav and ask_yes_no("Use favorite saved config?", true) or false
177
178 local start_mode, width, length, above, below
179 local use_torches, torch_spacing, torch_side, torch_slot
180 local use_chests, chest_slot
181 local use_throw, throw_slot
182 local auto_return
183
184 if use_fav then
185 start_mode = fav.start_mode or "center"
186 width = fav.width or 5; length = fav.length or 16; above = fav.above or 3; below = fav.below or 0
187 auto_return = fav.auto_return or true
188 use_torches = fav.use_torches or true; torch_spacing = fav.torch_spacing or 9; torch_side = fav.torch_side or "both"; torch_slot = fav.torch_slot or 1
189 use_chests = fav.use_chests or true; chest_slot = fav.chest_slot or 2
190 use_throw = fav.use_throw or false; throw_slot = fav.throw_slot or 4
191 else
192 start_mode = ask_choice("Start mode:", "center", {"center","bottom-left"})
193 width = ask_number_default("Doorway width:", 5, 1, 64)
194 length = ask_number_default("Entrance length:", 16, 1, 100000)
195 above = ask_number_default("Height above floor:", 3, 1, 16)
196 below = ask_number_default("Height below floor:", 0, 0, 8)
197 auto_return = ask_yes_no("Auto-return for fuel/torches?", true)
198 use_torches = ask_yes_no("Place torches?", true)
199 if use_torches then torch_spacing = ask_number_default("Torch spacing (blocks):", 9, 1, 64); torch_side = ask_choice("Torch side:", "both", {"left","right","both"}); torch_slot = ask_number_default("Torch slot (1-16):", 1, 1, 16) else torch_spacing=0; torch_side="right"; torch_slot=1 end
200 use_chests = ask_yes_no("Place chests to dump when full?", true); if use_chests then chest_slot = ask_number_default("Chest slot (1-16):", 2, 1, 16) else chest_slot = 2 end
201 use_throw = ask_yes_no("Throw items matching a sample when full?", false); if use_throw then throw_slot = ask_number_default("Sample slot (1-16):", 4, 1, 16) else throw_slot = 4 end
202 if ask_yes_no("Save as favorite?", true) then save_favorite({start_mode=start_mode,width=width,length=length,above=above,below=below,auto_return=auto_return,use_torches=use_torches,torch_spacing=torch_spacing,torch_side=torch_side,torch_slot=torch_slot,use_chests=use_chests,chest_slot=chest_slot,use_throw=use_throw,throw_slot=throw_slot}) end
203 end
204
205 local cfg = {use_torches=use_torches, torch_spacing=torch_spacing, torch_side=torch_side, torch_slot=torch_slot, use_chests=use_chests, chest_slot=chest_slot, use_throw=use_throw, throw_slot=throw_slot, auto_return=auto_return}
206
207 term.clear(); term.setCursorPos(1,1)
208 print("Entrance Carver v"..version)
209 print("Width:", width, " Length:", length, " Above:", above, " Below:", below)
210 print("Torches:", use_torches and ("every "..torch_spacing.." blocks on "..torch_side) or "No")
211 print("Chests:", use_chests and ("slot "..chest_slot) or "No", " Throw:", use_throw and ("slot "..throw_slot) or "No")
212 print("")
213 print("Place torches in slot "..torch_slot..", chests in slot "..chest_slot..", sample in slot "..throw_slot.." if throwing.")
214 print("")
215 print("Press Enter to start..."); read()
216
217 -- Align to left edge if starting at center
218 if start_mode=="center" then local left_offset = math.floor((width-1)/2); turn_left(); for i=1,left_offset do dig_forward(); safe_forward() end; turn_right() end
219
220 local per_slice = estimate_moves_per_slice(width, above, below)
221 local depth=0; local at_left=true; local current_level=1
222
223 for step=1,length do
224 ensure_inventory_capacity(cfg, at_left)
225 local reserve = per_slice + depth + 10
226 if turtle.getFuelLevel()~="unlimited" and turtle.getFuelLevel()<reserve then ensure_fuel(reserve); if turtle.getFuelLevel()<reserve and cfg.auto_return then attempt_return_for_refuel(depth, reserve) end end
227 at_left, current_level = carve_slice(width, above, below, at_left, current_level)
228 place_torch_if_needed(step, cfg, width, at_left)
229 ensure_inventory_capacity(cfg, at_left)
230 -- advance to next face
231 dig_forward(); safe_forward(); depth = depth + 1
232 end
233
234 term.clear(); term.setCursorPos(1,1); print("Done. Entrance completed.")
235end
236
237main()
238
239
240