AdvancedMiningTurtle.lua

601 lines · 19.4 KB

Open raw

{program="AdvancedMiningTurtle",version="2.0",date="2024-12-19"}

Copy & run

wget https://perlytiara.github.io/turtles.tips/raw/programs/perlytiara/tClear/AdvancedMiningTurtle.lua
1--{program="AdvancedMiningTurtle",version="2.0",date="2024-12-19"}
2---------------------------------------
3-- Advanced Mining Turtle by AI Assistant
4-- 2024-12-19, v2.0 Enhanced wireless mining turtle
5---------------------------------------
6
7---------------------------------------
8---- DESCRIPTION ----------------------
9---------------------------------------
10-- Enhanced mining turtle with advanced wireless communication
11-- Supports remote control from AdvancedMiningController
12-- Features real-time status reporting, pause/resume, and chunky pairing
13-- Based on original tClear.lua with wireless enhancements
14
15---------------------------------------
16---- ASSUMPTIONS ----------------------
17---------------------------------------
18-- Requires a mining turtle with wireless modem
19-- Should be placed at left corner of mining area
20-- Chunky turtle should be placed one block to the right
21
22---------------------------------------
23---- VARIABLES ------------------------
24---------------------------------------
25local cVersion = "v2.0"
26local cPrgName = "AdvancedMiningTurtle"
27local blnDebugPrint = true
28
29-- Communication settings
30local protocol = "advanced-mining"
31local controllerId = nil
32local chunkyTurtleId = nil
33local isRemoteControlled = false
34
35-- Operation state
36local isOperationActive = false
37local isPaused = false
38local operationCommand = ""
39local operationParams = {}
40
41-- Position tracking
42local tPos = {x = 1, y = 0, z = 1, facing = 0}
43local startPosition = {x = 1, y = 0, z = 1, facing = 0}
44
45-- Mining parameters
46local digDeep = 0
47local digWide = 0
48local digHeight = 0
49local blnLayerByLayer = false
50local blnStartWithin = false
51local blnStripMine = false
52
53-- Status reporting
54local lastStatusReport = 0
55local statusReportInterval = 5 -- seconds
56
57---------------------------------------
58---- Utility Functions ----------------
59---------------------------------------
60local function debugPrint(str)
61 if blnDebugPrint then
62 print("[MiningTurtle] " .. str)
63 end
64end
65
66local function findModem()
67 for _, p in pairs(rs.getSides()) do
68 if peripheral.isPresent(p) and peripheral.getType(p) == "modem" then
69 return p
70 end
71 end
72 error("No modem attached to this turtle.")
73end
74
75local function sendMessage(targetId, message, customProtocol)
76 local protocolToUse = customProtocol or protocol
77 rednet.send(targetId, message, protocolToUse)
78 debugPrint("Sent to " .. targetId .. ": " .. textutils.serialize(message))
79end
80
81local function sendStatusUpdate()
82 if controllerId and isOperationActive then
83 local status = {
84 type = "status_update",
85 position = "(" .. tPos.x .. "," .. tPos.y .. "," .. tPos.z .. ")",
86 progress = "Mining in progress",
87 fuel = turtle.getFuelLevel(),
88 inventory = math.floor((turtle.getItemCount() / (16 * 64)) * 100) .. "%",
89 timestamp = os.time()
90 }
91
92 if chunkyTurtleId then
93 status.chunkyStatus = "Paired with chunky turtle"
94 end
95
96 sendMessage(controllerId, status)
97 lastStatusReport = os.time()
98 end
99end
100
101---------------------------------------
102---- Movement Functions (from tClear) -
103---------------------------------------
104local function gf(n) if n==nil then n=1 end for i=1,n,1 do while not turtle.forward() do end end end
105local function gb(n) if n==nil then n=1 end for i=1,n,1 do while not turtle.back() do end end end
106local function gu(n) if n==nil then n=1 end for i=1,n,1 do while not turtle.up() do end end end
107local function gd(n) if n==nil then n=1 end for i=1,n,1 do while not turtle.down() do end end end
108local function gl(n) if n==nil then n=1 end for i=1,n,1 do while not turtle.turnLeft() do end end end
109local function gr(n) if n==nil then n=1 end for i=1,n,1 do while not turtle.turnRight() do end end end
110
111local function df() turtle.dig() end
112local function du() turtle.digUp() end
113local function dd() turtle.digDown() end
114
115local function dfs() while turtle.dig() do end end
116local function dus() while turtle.digUp() do end end
117local function dds() while turtle.digDown() do end end
118
119local function ss(s) turtle.select(s) end
120local function gic(s) return turtle.getItemCount(s) end
121
122local function gfs(n) if n==nil then n=1 end for i=1,n,1 do while not turtle.forward() do df() end end end
123local function gbs(n) if n==nil then n=1 end for i=1,n,1 do while not turtle.back() do gl() gl() df() gr() gr() end end end
124local function gus(n) if n==nil then n=1 end for i=1,n,1 do while not turtle.up() do du() end end end
125local function gds(n) if n==nil then n=1 end for i=1,n,1 do while not turtle.down() do dd() end end end
126
127-- Position-aware movement functions
128local function glPos(n) if n==nil then n=1 end for i=1,n,1 do while not turtle.turnLeft() do end end end
129local function grPos(n) if n==nil then n=1 end for i=1,n,1 do while not turtle.turnRight() do end end end
130local function gfPos(n) if n==nil then n=1 end for i=1,n,1 do while not turtle.forward() do df() end end end
131local function gbPos(n) if n==nil then n=1 end for i=1,n,1 do while not turtle.back() do gl() gl() df() gr() gr() end end end
132local function guPos(n) if n==nil then n=1 end for i=1,n,1 do while not turtle.up() do du() end tPos[3]=tPos[3]+1 end end
133local function gdPos(n) if n==nil then n=1 end for i=1,n,1 do while not turtle.down() do dd() end tPos[3]=tPos[3]-1 end end
134
135---------------------------------------
136---- Chunky Turtle Communication ------
137---------------------------------------
138local function moveChunkyTurtle(mainX, mainY, mainZ, mainFacing)
139 if chunkyTurtleId then
140 -- Calculate chunky turtle position relative to main turtle (to the right)
141 local chunkyX = mainX -- Same X position (depth)
142 local chunkyY = mainY -- Same height
143 local chunkyZ = mainZ + 1 -- One block to the right (positive Z)
144 local chunkyFacing = mainFacing -- Same facing direction
145
146 sendMessage(chunkyTurtleId, {
147 type = "move",
148 target = {x = chunkyX, y = chunkyY, z = chunkyZ, facing = chunkyFacing},
149 timestamp = os.time()
150 }, "tclear-chunky")
151
152 debugPrint("Sent chunky turtle to position: (" .. chunkyX .. "," .. chunkyY .. "," .. chunkyZ .. ") facing=" .. chunkyFacing)
153 end
154end
155
156local function stopChunkyTurtle()
157 if chunkyTurtleId then
158 sendMessage(chunkyTurtleId, {
159 type = "stop",
160 timestamp = os.time()
161 }, "tclear-chunky")
162 end
163end
164
165---------------------------------------
166---- Mining Functions (from tClear) ---
167---------------------------------------
168local blnDigUp = false
169local blnDigDown = false
170
171local function digUpDown()
172 if blnDigUp then dus() end
173 if blnDigDown then dds() end
174end
175
176local function gfPosDig(n)
177 if n==nil then n=1 end
178 for i=1,n,1 do
179 gfPos()
180 digUpDown()
181 end
182end
183
184local function checkFuel()
185 return turtle.getFuelLevel()
186end
187
188local function refuelFromSlot(s, n)
189 if s==nil then s=16 end
190 if n==nil then n=64 end
191 local currentSlot = turtle.getSelectedSlot()
192 local fuelItems = turtle.getItemCount(s)
193 local returnValue = false
194
195 if fuelItems>0 then
196 ss(s)
197 returnValue=turtle.refuel(n)
198 ss(currentSlot)
199 end
200 return returnValue
201end
202
203local function refuelManager(setMinFuel, setSlotFuel, waitTime)
204 local currentSlotSelected = turtle.getSelectedSlot()
205 ss(setSlotFuel)
206 while turtle.getFuelLevel() < setMinFuel do
207 print("Need more fuel (" .. turtle.getFuelLevel() .. "/" .. setMinFuel .. ").")
208 if not refuelFromSlot(setSlotFuel) then
209 print(" Please, put fuel items in slot " .. setSlotFuel .. "!")
210 print(" Sleeping " .. waitTime .. " seconds")
211 sleep(waitTime)
212 else
213 print("Refueled...")
214 end
215 end
216 ss(currentSlotSelected)
217end
218
219---------------------------------------
220---- Operation Control Functions ------
221---------------------------------------
222local function parseOperationCommand(command)
223 local args = {}
224 for arg in string.gmatch(command, "%S+") do
225 table.insert(args, arg)
226 end
227
228 if #args < 3 then
229 error("Invalid command format. Expected: depth width height [options]")
230 end
231
232 digDeep = tonumber(args[1])
233 digWide = tonumber(args[2])
234 digHeight = tonumber(args[3])
235
236 if not digDeep or digDeep <= 0 then
237 error("Invalid depth. Must be >= 1")
238 end
239 if not digWide or digWide == -1 or digWide == 0 or digWide == 1 then
240 error("Invalid width. Cannot be -1, 0, or 1")
241 end
242 if not digHeight or digHeight == 0 then
243 error("Invalid height. Cannot be 0")
244 end
245
246 -- Parse options
247 blnLayerByLayer = false
248 blnStartWithin = false
249 blnStripMine = false
250
251 for i = 4, #args do
252 local option = string.lower(args[i])
253 if option == "layerbylayer" or option == "layer" or option == "singlelayer" then
254 blnLayerByLayer = true
255 elseif option == "startwithin" or option == "within" or option == "in" then
256 blnStartWithin = true
257 elseif option == "stripmine" or option == "strip" or option == "mine" then
258 blnStripMine = true
259 end
260 end
261
262 debugPrint("Parsed command: depth=" .. digDeep .. " width=" .. digWide .. " height=" .. digHeight)
263 debugPrint("Options: layerbylayer=" .. tostring(blnLayerByLayer) .. " startwithin=" .. tostring(blnStartWithin) .. " stripmine=" .. tostring(blnStripMine))
264end
265
266local function performMiningOperation()
267 print("Starting mining operation...")
268 print("Parameters: " .. digDeep .. " x " .. digWide .. " x " .. digHeight)
269
270 -- Initialize position
271 tPos[1] = 1
272 tPos[2] = 0
273 tPos[3] = 1
274 tPos[4] = 0
275 startPosition = {x = tPos[1], y = tPos[2], z = tPos[3], facing = tPos[4]}
276
277 -- Check fuel
278 local cMinFuel = 110
279 local slotFuel = 16
280
281 if not blnLayerByLayer then
282 cMinFuel = math.floor(digHeight/3)
283 else
284 cMinFuel = math.floor(digHeight)
285 end
286 cMinFuel = cMinFuel * (math.abs(digDeep) + 1) * (math.abs(digWide) + 1) + (digHeight * 2)
287 cMinFuel = math.floor(cMinFuel * 1.1) + 20
288
289 refuelManager(cMinFuel, slotFuel, 10)
290
291 -- Handle negative values
292 local digWideOrg = digWide
293 local digDeepOrg = digDeep
294 local blnNegativeWidth = false
295
296 if digWide < 0 then
297 blnNegativeWidth = true
298 digWide = digDeepOrg
299 digDeep = -digWideOrg
300 end
301
302 local blnNegativeHeight = false
303 local remainingDigHeight = digHeight
304 if digHeight < 0 then
305 blnNegativeHeight = true
306 remainingDigHeight = -digHeight
307 end
308
309 -- Enter and go up
310 if not blnStartWithin then
311 gfPosDig()
312 moveChunkyTurtle(tPos[1], tPos[2], tPos[3], tPos[4])
313 else
314 tPos[2] = 1
315 moveChunkyTurtle(tPos[1], tPos[2], tPos[3], tPos[4])
316 end
317
318 if not blnNegativeWidth then
319 grPos()
320 end
321
322 -- Starting height
323 if not blnLayerByLayer then
324 if digHeight > 2 then
325 guPos(digHeight-2)
326 moveChunkyTurtle(tPos[1], tPos[2], tPos[3], tPos[4])
327 elseif digHeight < -1 then
328 gdPos(1)
329 moveChunkyTurtle(tPos[1], tPos[2], tPos[3], tPos[4])
330 end
331 else
332 if digHeight > 1 then
333 guPos(digHeight-1)
334 moveChunkyTurtle(tPos[1], tPos[2], tPos[3], tPos[4])
335 end
336 end
337
338 -- Main mining loop
339 while remainingDigHeight > 0 and isOperationActive and not isPaused do
340 -- Set dig up/down
341 if not blnLayerByLayer then
342 if not blnNegativeHeight then
343 if tPos[3] > 1 then
344 blnDigUp = true
345 blnDigDown = true
346 elseif remainingDigHeight == 2 then
347 blnDigUp = true
348 blnDigDown = false
349 else
350 blnDigUp = false
351 blnDigDown = false
352 end
353 else
354 if tPos[3] >= digHeight + 3 then
355 blnDigUp = true
356 blnDigDown = true
357 elseif remainingDigHeight == 2 then
358 blnDigUp = true
359 blnDigDown = false
360 else
361 blnDigUp = false
362 blnDigDown = false
363 end
364 end
365 else
366 blnDigUp = false
367 blnDigDown = false
368 end
369
370 -- Dig one level
371 for iy = 1, digDeep, 1 do
372 if not isOperationActive or isPaused then break end
373
374 if iy == 1 then
375 gfPosDig()
376 moveChunkyTurtle(tPos[1], tPos[2], tPos[3], tPos[4])
377 elseif iy % 2 == 0 then
378 glPos()
379 gfPosDig()
380 glPos()
381 moveChunkyTurtle(tPos[1], tPos[2], tPos[3], tPos[4])
382 else
383 grPos()
384 gfPosDig()
385 grPos()
386 moveChunkyTurtle(tPos[1], tPos[2], tPos[3], tPos[4])
387 end
388
389 gfPosDig(digWide-2)
390 moveChunkyTurtle(tPos[1], tPos[2], tPos[3], tPos[4])
391
392 if iy == digDeep then
393 if iy % 2 == 1 then
394 glPos(2)
395 gfPosDig(digWide-2)
396 end
397 gfPosDig()
398 glPos()
399 gfPosDig(digDeep-1)
400 glPos()
401 moveChunkyTurtle(tPos[1], tPos[2], tPos[3], tPos[4])
402 end
403 end
404
405 -- Change level
406 remainingDigHeight = remainingDigHeight - 1
407 if blnDigUp then remainingDigHeight = remainingDigHeight - 1 end
408 if blnDigDown then remainingDigHeight = remainingDigHeight - 1 end
409
410 if remainingDigHeight > 0 then
411 if not blnLayerByLayer then
412 if not blnNegativeHeight then
413 if remainingDigHeight >= 2 then
414 gdPos(3)
415 moveChunkyTurtle(tPos[1], tPos[2], tPos[3], tPos[4])
416 else
417 gdPos(tPos[3]-1)
418 moveChunkyTurtle(tPos[1], tPos[2], tPos[3], tPos[4])
419 end
420 else
421 if remainingDigHeight >= 2 then
422 gdPos(3)
423 moveChunkyTurtle(tPos[1], tPos[2], tPos[3], tPos[4])
424 else
425 gdPos(-digHeight + tPos[3] - 2)
426 moveChunkyTurtle(tPos[1], tPos[2], tPos[3], tPos[4])
427 end
428 end
429 else
430 gdPos(1)
431 moveChunkyTurtle(tPos[1], tPos[2], tPos[3], tPos[4])
432 end
433 end
434
435 -- Send periodic status updates
436 if os.time() - lastStatusReport >= statusReportInterval then
437 sendStatusUpdate()
438 end
439 end
440
441 -- Return to floor
442 if not blnNegativeHeight then
443 gdPos(tPos[3]-1)
444 else
445 guPos(-tPos[3]+1)
446 end
447 moveChunkyTurtle(tPos[1], tPos[2], tPos[3], tPos[4])
448
449 if not blnNegativeWidth then
450 glPos()
451 end
452
453 if not blnStartWithin then
454 gbPos()
455 moveChunkyTurtle(tPos[1], tPos[2], tPos[3], tPos[4])
456 end
457
458 -- Stop chunky turtle
459 stopChunkyTurtle()
460
461 print("Mining operation completed!")
462
463 -- Send completion status
464 if controllerId then
465 sendMessage(controllerId, {
466 type = "operation_complete",
467 timestamp = os.time()
468 })
469 end
470end
471
472---------------------------------------
473---- Message Processing ---------------
474---------------------------------------
475local function processMessage(senderId, message)
476 if message.type == "discover" then
477 -- Respond to discovery request
478 sendMessage(senderId, {
479 type = "mining_turtle_available",
480 name = "Advanced Mining Turtle",
481 fuel = turtle.getFuelLevel(),
482 inventory = math.floor((turtle.getItemCount() / (16 * 64)) * 100),
483 timestamp = os.time()
484 })
485 return true
486
487 elseif message.type == "start_mining" then
488 -- Start mining operation
489 controllerId = senderId
490 chunkyTurtleId = message.chunkyId
491 operationCommand = message.command
492 isOperationActive = true
493 isPaused = false
494
495 print("Received mining command: " .. operationCommand)
496 print("Controller ID: " .. controllerId)
497 if chunkyTurtleId then
498 print("Chunky Turtle ID: " .. chunkyTurtleId)
499 end
500
501 -- Parse and start operation
502 parseOperationCommand(operationCommand)
503
504 -- Send confirmation
505 sendMessage(controllerId, {
506 type = "mining_started",
507 command = operationCommand,
508 timestamp = os.time()
509 })
510
511 -- Start mining in a separate thread
512 local function miningThread()
513 local ok, err = pcall(performMiningOperation)
514 if not ok then
515 print("Mining operation failed: " .. tostring(err))
516 if controllerId then
517 sendMessage(controllerId, {
518 type = "operation_error",
519 error = tostring(err),
520 timestamp = os.time()
521 })
522 end
523 end
524 end
525
526 -- Start mining thread
527 local thread = coroutine.create(miningThread)
528 coroutine.resume(thread)
529
530 return true
531
532 elseif message.type == "status_request" then
533 -- Send status update
534 sendStatusUpdate()
535 return true
536
537 elseif message.type == "pause_operation" then
538 -- Pause operation
539 isPaused = true
540 print("Operation paused by controller")
541 return true
542
543 elseif message.type == "resume_operation" then
544 -- Resume operation
545 isPaused = false
546 print("Operation resumed by controller")
547 return true
548
549 elseif message.type == "stop_operation" then
550 -- Stop operation
551 isOperationActive = false
552 isPaused = false
553 print("Operation stopped by controller")
554 return true
555 end
556
557 return false
558end
559
560---------------------------------------
561---- Main Program ----------------------
562---------------------------------------
563local function main()
564 term.clear()
565 term.setCursorPos(1, 1)
566
567 print("==========================================")
568 print(" Advanced Mining Turtle " .. cVersion)
569 print("==========================================")
570 print()
571
572 -- Initialize rednet
573 local modemSide = findModem()
574 rednet.open(modemSide)
575 print("Rednet initialized on " .. modemSide)
576 print("Turtle ID: " .. os.getComputerID())
577 print()
578 print("Waiting for controller commands...")
579 print("Press Ctrl+T to exit")
580
581 -- Main message loop
582 while true do
583 local senderId, message, msgProtocol = rednet.receive()
584
585 if senderId and msgProtocol == protocol then
586 local handled = processMessage(senderId, message)
587 if handled then
588 debugPrint("Processed message from " .. senderId)
589 end
590 end
591 end
592end
593
594-- Run main program
595local ok, err = pcall(main)
596if not ok then
597 print("Error: " .. tostring(err))
598 print("Press any key to exit...")
599 os.pullEvent("key")
600end
601