general_husbandry.lua

382 lines · 10.6 KB

Open raw

General Husbandry Utility

Copy & run

wget https://perlytiara.github.io/turtles.tips/raw/programs/perlytiara/husbandry/general_husbandry.lua
1-- Husbandry Turtle - General Husbandry Utility
2-- Requirements: CC:Tweaked turtle with Advanced Peripherals Husbandry Automata upgrade
3-- Provides a guided text UI for common actions: search, inspect, feed/use item, capture/release, breeding
4
5local function supportsColor()
6 return term.isColor and term.isColor()
7end
8
9local function clearScreen()
10 term.clear()
11 term.setCursorPos(1, 1)
12end
13
14local function writeCentered(text)
15 local w, _ = term.getSize()
16 local x = math.max(1, math.floor((w - #text) / 2) + 1)
17 term.setCursorPos(x, select(2, term.getCursorPos()))
18 print(text)
19end
20
21local function banner()
22 if supportsColor() then term.setTextColor(colors.cyan) end
23 writeCentered("==============================")
24 writeCentered(" Husbandry Turtle - Assistant ")
25 writeCentered("==============================")
26 if supportsColor() then term.setTextColor(colors.white) end
27 print("")
28end
29
30local function prompt(promptText)
31 io.write(promptText .. " ")
32 return read()
33end
34
35local function waitForEnter(msg)
36 msg = msg or "Press Enter to continue"
37 io.write(msg)
38 read()
39end
40
41local function confirm(question, defaultYes)
42 local def = defaultYes and "Y/n" or "y/N"
43 while true do
44 local ans = string.lower((prompt(string.format("%s [%s]", question, def)) or ""):gsub("%s+", ""))
45 if ans == "" then return defaultYes end
46 if ans == "y" or ans == "yes" then return true end
47 if ans == "n" or ans == "no" then return false end
48 print("Please answer y or n.")
49 end
50end
51
52-- Peripheral detection (try multiple known names)
53local function findHusbandryPeripheral()
54 local candidates = {
55 "husbandry_automata", -- snake_case variant
56 "husbandryAutomata", -- camelCase variant from docs
57 "weak_automata", -- fallback (older core)
58 "automata" -- very old/other name
59 }
60 for _, name in ipairs(candidates) do
61 local p = peripheral.find(name)
62 if p then return p, name end
63 end
64 return nil, nil
65end
66
67-- Inventory helpers
68local function getInventorySnapshot()
69 local snapshot = {}
70 for slot = 1, 16 do
71 local detail = turtle.getItemDetail(slot)
72 if detail then
73 snapshot[#snapshot + 1] = {
74 slot = slot,
75 name = detail.name,
76 count = detail.count or turtle.getItemCount(slot),
77 displayName = detail.displayName or detail.name,
78 }
79 end
80 end
81 return snapshot
82end
83
84local function printInventory(snapshot)
85 print("Inventory:")
86 if #snapshot == 0 then
87 print(" (empty)")
88 return
89 end
90 for _, item in ipairs(snapshot) do
91 print(string.format(" [%2d] x%-3d %s (%s)", item.slot, item.count, item.displayName, item.name))
92 end
93end
94
95local function findPreferredItemSlot(preferredNames)
96 if not preferredNames or #preferredNames == 0 then return nil end
97 local snapshot = getInventorySnapshot()
98 local lowered = {}
99 for _, n in ipairs(preferredNames) do lowered[#lowered + 1] = string.lower(n) end
100 for _, item in ipairs(snapshot) do
101 local lname = string.lower(item.name .. " " .. item.displayName)
102 for _, key in ipairs(lowered) do
103 if string.find(lname, key, 1, true) then
104 return item.slot, item
105 end
106 end
107 end
108 return nil
109end
110
111local function promptSelectSlot(preferredNames)
112 local autoSlot, autoItem = findPreferredItemSlot(preferredNames or {})
113 local snapshot = getInventorySnapshot()
114 printInventory(snapshot)
115 if autoSlot then
116 print(string.format("Suggested slot [%d]: %s x%d", autoSlot, autoItem.displayName, autoItem.count))
117 end
118 while true do
119 local ans = prompt("Enter slot number (1-16) or leave empty to use suggestion")
120 ans = (ans or ""):gsub("%s+", "")
121 if ans == "" and autoSlot then return autoSlot end
122 local n = tonumber(ans)
123 if n and n >= 1 and n <= 16 then return n end
124 print("Invalid slot. Please enter a number 1-16.")
125 end
126end
127
128-- Action handlers
129local function actionSearch(automata)
130 print("Scanning for nearby animals...")
131 local result, err = automata.searchAnimals()
132 if not result then
133 print("Error: " .. tostring(err))
134 return
135 end
136 if #result == 0 then
137 print("No animals detected nearby.")
138 return
139 end
140 print(string.format("Found %d animals:", #result))
141 for i, animal in ipairs(result) do
142 -- animal fields can vary; show common ones defensively
143 local species = tostring(animal.species or animal.name or animal.id or "unknown")
144 local pos = animal.position or {}
145 local dx = tonumber(pos.x or 0)
146 local dy = tonumber(pos.y or 0)
147 local dz = tonumber(pos.z or 0)
148 print(string.format(" %2d) %s at (%d,%d,%d)", i, species, dx, dy, dz))
149 end
150end
151
152local function actionInspect(automata)
153 print("Inspecting animal in front...")
154 local info, err = automata.inspectAnimal()
155 if not info then
156 print("Error: " .. tostring(err))
157 return
158 end
159 print("Info:")
160 for k, v in pairs(info) do
161 local vt = type(v)
162 if vt == "table" then
163 local parts = {}
164 for k2, v2 in pairs(v) do parts[#parts + 1] = tostring(k2) .. ":" .. tostring(v2) end
165 print(" " .. tostring(k) .. ": { " .. table.concat(parts, ", ") .. " }")
166 else
167 print(" " .. tostring(k) .. ": " .. tostring(v))
168 end
169 end
170end
171
172local function actionUseOnAnimal(automata, preferredNames)
173 print("Use selected item on animal in front")
174 local slot = promptSelectSlot(preferredNames)
175 turtle.select(slot)
176 local ok, resultOrErr = automata.useOnAnimal()
177 if ok then
178 print("Interaction success: " .. tostring(resultOrErr))
179 else
180 print("Interaction failed: " .. tostring(resultOrErr))
181 end
182end
183
184local function actionCapture(automata)
185 print("Capturing animal in front...")
186 local ok, err = automata.captureAnimal()
187 if ok then
188 print("Captured.")
189 else
190 print("Failed to capture: " .. tostring(err))
191 end
192end
193
194local function actionRelease(automata)
195 print("Releasing captured animal...")
196 local ok, err = automata.releaseAnimal()
197 if ok then
198 print("Released.")
199 else
200 print("Failed to release: " .. tostring(err))
201 end
202end
203
204local function actionGetCapturedInfo(automata)
205 local info, err = automata.getCapturedAnimal()
206 if not info then
207 print("No captured animal or error: " .. tostring(err))
208 return
209 end
210 print("Captured Animal:")
211 for k, v in pairs(info) do
212 print(" " .. tostring(k) .. ": " .. tostring(v))
213 end
214end
215
216-- Breeding workflow
217local BREEDING_MAPPINGS = {
218 Cow = {"wheat"},
219 Sheep = {"wheat"},
220 Pig = {"carrot", "potato", "beetroot"},
221 Chicken = {"seed"},
222 Wolf = {"meat", "beef", "porkchop", "mutton", "chicken"},
223 Cat = {"fish", "cod", "salmon"},
224 Fox = {"sweet_berries"},
225 Rabbit = {"dandelion", "carrot"},
226}
227
228local function actionBreedingWorkflow(automata)
229 print("Guided breeding workflow")
230 print("Note: Position the turtle directly in front of the animal before feeding.")
231 print("")
232 print("Known species presets:")
233 local speciesList = {}
234 for species, _ in pairs(BREEDING_MAPPINGS) do speciesList[#speciesList + 1] = species end
235 table.sort(speciesList)
236 for i, s in ipairs(speciesList) do
237 print(string.format(" %2d) %s", i, s))
238 end
239 print(" 0) Other/Unknown")
240
241 local choice = tonumber(prompt("Choose species preset number")) or 0
242 local chosenSpecies = speciesList[choice] or "Other"
243 local preferred = BREEDING_MAPPINGS[chosenSpecies] or {}
244 if #preferred > 0 then
245 print("Preferred breeding items: " .. table.concat(preferred, ", "))
246 else
247 print("No preset. You will choose an item slot manually.")
248 end
249
250 local pairsToBreed = tonumber(prompt("How many pairs to breed? (each pair makes one baby)")) or 1
251 if pairsToBreed < 1 then pairsToBreed = 1 end
252
253 for i = 1, pairsToBreed do
254 print("")
255 print(string.format("Pair %d/%d", i, pairsToBreed))
256 -- First mate
257 print("Bring first adult in front of the turtle.")
258 waitForEnter("Press Enter when ready...")
259 local slotA = promptSelectSlot(preferred)
260 turtle.select(slotA)
261 local okA, msgA = automata.useOnAnimal()
262 if not okA then
263 print("Feeding first animal failed: " .. tostring(msgA))
264 if not confirm("Continue to next pair?", true) then return end
265 else
266 print("First animal fed: " .. tostring(msgA))
267 end
268
269 -- Second mate
270 print("Bring second adult in front of the turtle.")
271 waitForEnter("Press Enter when ready...")
272 local slotB = slotA -- reuse same item by default
273 -- Allow change if desired
274 if confirm("Use same slot for second mate?", true) then
275 turtle.select(slotB)
276 else
277 slotB = promptSelectSlot(preferred)
278 turtle.select(slotB)
279 end
280 local okB, msgB = automata.useOnAnimal()
281 if not okB then
282 print("Feeding second animal failed: " .. tostring(msgB))
283 if not confirm("Continue to next pair?", true) then return end
284 else
285 print("Second animal fed: " .. tostring(msgB))
286 end
287
288 print("If both were adults and valid mates, a baby should be created shortly.")
289 end
290
291 print("Breeding workflow complete.")
292end
293
294-- Main menu
295local function main()
296 clearScreen()
297 banner()
298 if not turtle then
299 print("This program must run on a turtle.")
300 return
301 end
302 local automata, pname = findHusbandryPeripheral()
303 if not automata then
304 print("Could not find Husbandry Automata peripheral. Make sure the upgrade is installed.")
305 print("Tried names: husbandry_automata, husbandryAutomata, weak_automata, automata")
306 return
307 end
308 print("Detected peripheral: " .. tostring(pname))
309 print("")
310
311 while true do
312 banner()
313 print("Choose an action:")
314 print(" 1) Search nearby animals")
315 print(" 2) Inspect animal in front")
316 print(" 3) Use selected item on animal in front")
317 print(" 4) Capture animal in front")
318 print(" 5) Release captured animal")
319 print(" 6) Show captured animal info")
320 print(" 7) Guided breeding workflow")
321 print(" 8) Show inventory and select slot")
322 print(" 9) Exit")
323 local choice = tonumber(prompt("Enter choice number")) or -1
324 clearScreen()
325 banner()
326 if choice == 1 then
327 actionSearch(automata)
328 waitForEnter()
329 elseif choice == 2 then
330 actionInspect(automata)
331 waitForEnter()
332 elseif choice == 3 then
333 -- Ask for quick presets for common species
334 print("Quick presets: 1) Wheat 2) Seeds 3) Carrot 4) Potato 5) None")
335 local p = tonumber(prompt("Choose preset")) or 5
336 local pref = ({
337 [1] = {"wheat"},
338 [2] = {"seed"},
339 [3] = {"carrot"},
340 [4] = {"potato"},
341 [5] = {},
342 })[p] or {}
343 actionUseOnAnimal(automata, pref)
344 waitForEnter()
345 elseif choice == 4 then
346 actionCapture(automata)
347 waitForEnter()
348 elseif choice == 5 then
349 actionRelease(automata)
350 waitForEnter()
351 elseif choice == 6 then
352 actionGetCapturedInfo(automata)
353 waitForEnter()
354 elseif choice == 7 then
355 actionBreedingWorkflow(automata)
356 waitForEnter()
357 elseif choice == 8 then
358 local snapshot = getInventorySnapshot()
359 printInventory(snapshot)
360 local _ = promptSelectSlot({})
361 print("Slot selected. (No action performed)")
362 waitForEnter()
363 elseif choice == 9 then
364 print("Goodbye!")
365 return
366 else
367 print("Invalid choice.")
368 waitForEnter()
369 end
370 clearScreen()
371 end
372end
373
374-- Entry
375local ok, err = pcall(main)
376if not ok then
377 print("Unexpected error: " .. tostring(err))
378end
379
380
381
382