edig.lua
737 lines · 18.8 KB
Advanced tunnel digger with dome shapes and multi-turtle coordination
Usage: edig [command] [args...]
Copy & run
wget https://perlytiara.github.io/turtles.tips/raw/programs/perlytiara/eDig/edig.lua
| 1 | -- edig.lua - Advanced tunnel digger with dome shapes and multi-turtle coordination |
| 2 | -- Usage: edig [command] [args...] |
| 3 | -- Commands: dig, multi, install, client, help |
| 4 | |
| 5 | local args = {...} |
| 6 | |
| 7 | -- Check if we're on a turtle |
| 8 | local function hasTurtle() |
| 9 | return pcall(function() return turtle.getFuelLevel() end) |
| 10 | end |
| 11 | |
| 12 | -- Movement helpers |
| 13 | local function df() while turtle.detect() do turtle.dig() end end |
| 14 | local function du() while turtle.detectUp() do turtle.digUp() end end |
| 15 | local function dd() while turtle.detectDown() do turtle.digDown() end end |
| 16 | local function gf() |
| 17 | while not turtle.forward() do |
| 18 | if turtle.detect() then turtle.dig() end |
| 19 | turtle.attack() |
| 20 | end |
| 21 | end |
| 22 | local function gu() |
| 23 | while not turtle.up() do |
| 24 | if turtle.detectUp() then turtle.digUp() end |
| 25 | turtle.attackUp() |
| 26 | end |
| 27 | end |
| 28 | local function gd() |
| 29 | while not turtle.down() do |
| 30 | if turtle.detectDown() then turtle.digDown() end |
| 31 | turtle.attackDown() |
| 32 | end |
| 33 | end |
| 34 | |
| 35 | -- Resource scanning |
| 36 | local function scanInventory() |
| 37 | local fuel = 0 |
| 38 | local blocks = 0 |
| 39 | local fuelSlots = {} |
| 40 | local blockSlots = {} |
| 41 | |
| 42 | for i = 1, 16 do |
| 43 | local count = turtle.getItemCount(i) |
| 44 | if count > 0 then |
| 45 | turtle.select(i) |
| 46 | local isFuel = turtle.refuel(0) |
| 47 | if isFuel then |
| 48 | fuel = fuel + count |
| 49 | table.insert(fuelSlots, i) |
| 50 | else |
| 51 | blocks = blocks + count |
| 52 | table.insert(blockSlots, i) |
| 53 | end |
| 54 | end |
| 55 | end |
| 56 | |
| 57 | return { |
| 58 | fuel = fuel, |
| 59 | blocks = blocks, |
| 60 | fuelSlots = fuelSlots, |
| 61 | blockSlots = blockSlots |
| 62 | } |
| 63 | end |
| 64 | |
| 65 | -- Fuel management |
| 66 | local function refuel(target) |
| 67 | if turtle.getFuelLevel() == "unlimited" then return true end |
| 68 | |
| 69 | local current = turtle.getSelectedSlot() |
| 70 | for i = 1, 16 do |
| 71 | if turtle.getItemCount(i) > 0 then |
| 72 | turtle.select(i) |
| 73 | while turtle.getItemCount(i) > 0 and turtle.getFuelLevel() < target do |
| 74 | if not turtle.refuel(1) then break end |
| 75 | end |
| 76 | if turtle.getFuelLevel() >= target then break end |
| 77 | end |
| 78 | end |
| 79 | turtle.select(current) |
| 80 | |
| 81 | if turtle.getFuelLevel() < target then |
| 82 | print("Need fuel! Current: " .. turtle.getFuelLevel()) |
| 83 | print("Add coal/charcoal to any slot") |
| 84 | while turtle.getFuelLevel() < target do |
| 85 | sleep(1) |
| 86 | for i = 1, 16 do |
| 87 | if turtle.getItemCount(i) > 0 then |
| 88 | turtle.select(i) |
| 89 | if turtle.refuel(1) then break end |
| 90 | end |
| 91 | end |
| 92 | end |
| 93 | end |
| 94 | return true |
| 95 | end |
| 96 | |
| 97 | -- Find block slot for placement |
| 98 | local function findBlockSlot() |
| 99 | for i = 1, 16 do |
| 100 | local count = turtle.getItemCount(i) |
| 101 | if count > 0 then |
| 102 | turtle.select(i) |
| 103 | local isFuel = turtle.refuel(0) |
| 104 | if not isFuel then return i end |
| 105 | end |
| 106 | end |
| 107 | return nil |
| 108 | end |
| 109 | |
| 110 | -- Place floor |
| 111 | local function placeFloor() |
| 112 | if not turtle.detectDown() then |
| 113 | local slot = findBlockSlot() |
| 114 | if slot then |
| 115 | turtle.select(slot) |
| 116 | local success = turtle.placeDown() |
| 117 | if not success then |
| 118 | print("Warning: Could not place floor block (no blocks available)") |
| 119 | return false |
| 120 | end |
| 121 | return true |
| 122 | else |
| 123 | print("Warning: No blocks available for floor placement") |
| 124 | return false |
| 125 | end |
| 126 | end |
| 127 | return true |
| 128 | end |
| 129 | |
| 130 | -- Dome tunnel shapes |
| 131 | local DOME_SHAPES = { |
| 132 | ["size2"] = { |
| 133 | width = 7, |
| 134 | heights = {3,3,4,4,4,3,3}, |
| 135 | maxTurtles = 7 |
| 136 | }, |
| 137 | ["custom"] = { |
| 138 | width = 5, |
| 139 | heights = {3,4,4,4,3}, |
| 140 | maxTurtles = 5 |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | -- Calculate dome shape heights |
| 145 | local function getDomeHeights(shape, width, sideHeight, centerHeight, radius) |
| 146 | if shape == "size2" then |
| 147 | return DOME_SHAPES.size2.heights |
| 148 | elseif shape == "custom" then |
| 149 | local heights = {} |
| 150 | for x = 0, width - 1 do |
| 151 | if radius <= 0 then |
| 152 | if x == 0 or x == width - 1 then |
| 153 | heights[x+1] = sideHeight |
| 154 | else |
| 155 | heights[x+1] = centerHeight |
| 156 | end |
| 157 | else |
| 158 | local u = 1 - (math.abs(2*x - (width - 1)) / (width - 1)) |
| 159 | local exponent = 1 / (1 + radius) |
| 160 | local u2 = u ^ exponent |
| 161 | local f = (1 - math.cos(math.pi * u2)) / 2 |
| 162 | local h = math.floor(0.5 + (sideHeight + (centerHeight - sideHeight) * f)) |
| 163 | if h < sideHeight then h = sideHeight end |
| 164 | if h > centerHeight then h = centerHeight end |
| 165 | heights[x+1] = h |
| 166 | end |
| 167 | end |
| 168 | return heights |
| 169 | end |
| 170 | return {3,3,3} -- default |
| 171 | end |
| 172 | |
| 173 | -- Check if we have blocks for floor placement |
| 174 | local function checkBlocksForFloor(shouldPlaceFloor) |
| 175 | if shouldPlaceFloor then |
| 176 | local slot = findBlockSlot() |
| 177 | if not slot then |
| 178 | print("No blocks available for floor placement!") |
| 179 | print("Options:") |
| 180 | print("1. Add blocks to inventory and press Enter") |
| 181 | print("2. Type 'skip' to continue without floor placement") |
| 182 | print("3. Type 'stop' to abort") |
| 183 | |
| 184 | while true do |
| 185 | write("Choice: ") |
| 186 | local choice = string.lower(read()) |
| 187 | if choice == "skip" then |
| 188 | return false |
| 189 | elseif choice == "stop" then |
| 190 | error("Operation aborted by user") |
| 191 | elseif choice == "" then |
| 192 | slot = findBlockSlot() |
| 193 | if slot then |
| 194 | print("Blocks found! Continuing...") |
| 195 | return true |
| 196 | else |
| 197 | print("Still no blocks. Please add blocks or type 'skip' or 'stop'") |
| 198 | end |
| 199 | end |
| 200 | end |
| 201 | end |
| 202 | end |
| 203 | return shouldPlaceFloor |
| 204 | end |
| 205 | |
| 206 | -- Straight tunnel digging |
| 207 | local function digStraightTunnel(height, width, length, shouldPlaceFloor) |
| 208 | local slice = 0 |
| 209 | |
| 210 | print("Starting straight tunnel dig...") |
| 211 | print("Dimensions: " .. length .. "x" .. width .. "x" .. height) |
| 212 | |
| 213 | while slice < length do |
| 214 | slice = slice + 1 |
| 215 | |
| 216 | -- Refuel check every 8 slices |
| 217 | if slice % 8 == 0 then |
| 218 | refuel(turtle.getFuelLevel() + 16) |
| 219 | end |
| 220 | |
| 221 | -- Dig tunnel slice |
| 222 | digTunnelSlice(height, width, shouldPlaceFloor) |
| 223 | |
| 224 | -- Move forward for next slice |
| 225 | gf() |
| 226 | |
| 227 | if slice >= 1000 then |
| 228 | print("Safety stop at 1000 slices") |
| 229 | break |
| 230 | end |
| 231 | end |
| 232 | |
| 233 | print("Done! Dug " .. slice .. " slices") |
| 234 | end |
| 235 | |
| 236 | -- Dig dome slice |
| 237 | local function digDomeSlice(heights, width, shouldPlaceFloor) |
| 238 | shouldPlaceFloor = checkBlocksForFloor(shouldPlaceFloor) |
| 239 | |
| 240 | -- Enter slice |
| 241 | df() |
| 242 | gf() |
| 243 | |
| 244 | -- Move to level 2 for dome shape |
| 245 | if heights[1] >= 2 then |
| 246 | gu() |
| 247 | end |
| 248 | |
| 249 | -- Dig left to right |
| 250 | for x = 1, width do |
| 251 | local h = heights[x] or 0 |
| 252 | |
| 253 | -- Adjust height |
| 254 | if h >= 1 then turtle.digDown() end |
| 255 | if h >= 3 then du() end |
| 256 | |
| 257 | -- Move right if not last column |
| 258 | if x < width then |
| 259 | turtle.turnLeft() |
| 260 | df() |
| 261 | gf() |
| 262 | turtle.turnRight() |
| 263 | end |
| 264 | end |
| 265 | |
| 266 | -- Upper pass for height 4 columns |
| 267 | local needUpper = false |
| 268 | for i = 1, #heights do |
| 269 | if heights[i] >= 4 then needUpper = true break end |
| 270 | end |
| 271 | |
| 272 | if needUpper then |
| 273 | gu() -- Move to level 3 |
| 274 | for x = 1, width do |
| 275 | if (heights[x] or 0) >= 4 then du() end |
| 276 | if x < width then |
| 277 | turtle.turnLeft() |
| 278 | gf() |
| 279 | turtle.turnRight() |
| 280 | end |
| 281 | end |
| 282 | gd() -- Return to level 2 |
| 283 | end |
| 284 | |
| 285 | -- Return to base level |
| 286 | gd() |
| 287 | |
| 288 | -- Return to starting position |
| 289 | for w = 1, width - 1 do |
| 290 | turtle.turnLeft() |
| 291 | gf() |
| 292 | turtle.turnRight() |
| 293 | end |
| 294 | end |
| 295 | |
| 296 | -- Dome tunnel digging |
| 297 | local function digDomeTunnel(shape, length, shouldPlaceFloor) |
| 298 | local heights = getDomeHeights(shape, DOME_SHAPES[shape].width, 3, 4, 0) |
| 299 | local width = DOME_SHAPES[shape].width |
| 300 | local slice = 0 |
| 301 | |
| 302 | print("Starting dome tunnel dig...") |
| 303 | print("Shape: " .. shape .. " (" .. width .. " wide)") |
| 304 | print("Length: " .. length) |
| 305 | |
| 306 | while slice < length do |
| 307 | slice = slice + 1 |
| 308 | |
| 309 | -- Refuel check every 8 slices |
| 310 | if slice % 8 == 0 then |
| 311 | refuel(turtle.getFuelLevel() + 16) |
| 312 | end |
| 313 | |
| 314 | -- Dig dome slice |
| 315 | digDomeSlice(heights, width, shouldPlaceFloor) |
| 316 | |
| 317 | -- Move forward for next slice |
| 318 | gf() |
| 319 | |
| 320 | if slice >= 1000 then |
| 321 | print("Safety stop at 1000 slices") |
| 322 | break |
| 323 | end |
| 324 | end |
| 325 | |
| 326 | print("Done! Dug " .. slice .. " dome slices") |
| 327 | end |
| 328 | |
| 329 | -- Dig tunnel slice (straight) |
| 330 | local function digTunnelSlice(height, width, shouldPlaceFloor) |
| 331 | shouldPlaceFloor = checkBlocksForFloor(shouldPlaceFloor) |
| 332 | |
| 333 | -- Dig the slice in front of turtle |
| 334 | for h = 1, height - 1 do |
| 335 | du() |
| 336 | if h < height - 1 then gu() end |
| 337 | end |
| 338 | |
| 339 | -- Dig forward |
| 340 | df() |
| 341 | gf() |
| 342 | if shouldPlaceFloor then placeFloor() end |
| 343 | |
| 344 | -- Return to base level |
| 345 | for h = 1, height - 1 do gd() end |
| 346 | |
| 347 | -- Dig the width (side to side) |
| 348 | for w = 1, width - 1 do |
| 349 | turtle.turnLeft() |
| 350 | df() |
| 351 | gf() |
| 352 | if shouldPlaceFloor then placeFloor() end |
| 353 | |
| 354 | -- Dig up for height |
| 355 | for h = 1, height - 1 do |
| 356 | du() |
| 357 | if h < height - 1 then gu() end |
| 358 | end |
| 359 | |
| 360 | -- Return to base |
| 361 | for h = 1, height - 1 do gd() end |
| 362 | |
| 363 | turtle.turnRight() |
| 364 | end |
| 365 | |
| 366 | -- Return to starting position |
| 367 | for w = 1, width - 1 do |
| 368 | turtle.turnLeft() |
| 369 | gf() |
| 370 | turtle.turnRight() |
| 371 | end |
| 372 | end |
| 373 | |
| 374 | |
| 375 | -- Dig command |
| 376 | local function digCommand() |
| 377 | if not hasTurtle() then |
| 378 | print("Turtle required for digging!") |
| 379 | return |
| 380 | end |
| 381 | |
| 382 | local height = 3 |
| 383 | local length = 32 |
| 384 | local width = 3 |
| 385 | local autoPlace = false |
| 386 | local segment = nil |
| 387 | local shape = "straight" |
| 388 | |
| 389 | -- Parse arguments |
| 390 | if #args >= 2 then |
| 391 | height = math.max(1, tonumber(args[2]) or 3) |
| 392 | for i = 3, #args do |
| 393 | local arg = string.lower(args[i]) |
| 394 | local num = tonumber(args[i]) |
| 395 | if num then |
| 396 | if i == 3 then |
| 397 | length = math.max(1, num) |
| 398 | elseif i == 4 then |
| 399 | width = math.max(1, num) |
| 400 | elseif i == 5 then |
| 401 | segment = num |
| 402 | end |
| 403 | elseif arg == "place" then |
| 404 | autoPlace = true |
| 405 | elseif arg == "dome" or arg == "size2" then |
| 406 | shape = "size2" |
| 407 | elseif arg == "custom" then |
| 408 | shape = "custom" |
| 409 | end |
| 410 | end |
| 411 | else |
| 412 | -- Interactive prompts |
| 413 | term.clear() |
| 414 | term.setCursorPos(1, 1) |
| 415 | print("eDig - Advanced Tunnel Digger") |
| 416 | |
| 417 | local resources = scanInventory() |
| 418 | print("Resources: " .. resources.fuel .. " fuel, " .. resources.blocks .. " blocks") |
| 419 | |
| 420 | write("Tunnel type (straight/dome/size2) [straight]: ") |
| 421 | local t = string.lower(read()) |
| 422 | if t == "dome" or t == "size2" then |
| 423 | shape = "size2" |
| 424 | elseif t == "custom" then |
| 425 | shape = "custom" |
| 426 | end |
| 427 | |
| 428 | if shape == "straight" then |
| 429 | write("Tunnel height (blocks) [3]: ") |
| 430 | local h = read() |
| 431 | if h ~= "" then height = math.max(1, tonumber(h) or 3) end |
| 432 | |
| 433 | write("Tunnel length (blocks) [32]: ") |
| 434 | local l = read() |
| 435 | if l ~= "" then length = math.max(1, tonumber(l) or 32) end |
| 436 | |
| 437 | write("Tunnel width (blocks) [3]: ") |
| 438 | local w = read() |
| 439 | if w ~= "" then width = math.max(1, tonumber(w) or 3) end |
| 440 | else |
| 441 | write("Tunnel length (blocks) [32]: ") |
| 442 | local l = read() |
| 443 | if l ~= "" then length = math.max(1, tonumber(l) or 32) end |
| 444 | end |
| 445 | |
| 446 | write("Place floor blocks? (y/n) [n]: ") |
| 447 | local place = string.lower(read()) |
| 448 | autoPlace = (place == "y" or place == "yes") |
| 449 | |
| 450 | write("Segment number (for multi-turtle) [none]: ") |
| 451 | local seg = read() |
| 452 | if seg ~= "" then segment = tonumber(seg) end |
| 453 | end |
| 454 | |
| 455 | -- Resource check and planning |
| 456 | local resources = scanInventory() |
| 457 | print("Digging " .. shape .. " tunnel") |
| 458 | |
| 459 | if shape == "straight" then |
| 460 | print("Dimensions: " .. length .. "x" .. width .. "x" .. height) |
| 461 | else |
| 462 | print("Shape: " .. shape .. " (" .. DOME_SHAPES[shape].width .. " wide)") |
| 463 | print("Length: " .. length) |
| 464 | end |
| 465 | |
| 466 | if segment then |
| 467 | print("Segment: " .. segment) |
| 468 | end |
| 469 | |
| 470 | print("Resources: " .. resources.fuel .. " fuel, " .. resources.blocks .. " blocks") |
| 471 | |
| 472 | -- Initial fuel check |
| 473 | local fuelNeeded = length * (width + height) * 2 |
| 474 | if resources.fuel * 80 < fuelNeeded then |
| 475 | print("Warning: May need more fuel") |
| 476 | end |
| 477 | refuel(math.min(fuelNeeded, turtle.getFuelLevel() + 100)) |
| 478 | |
| 479 | print("Starting tunnel dig...") |
| 480 | if segment then |
| 481 | print("Segment " .. segment .. " starting...") |
| 482 | end |
| 483 | |
| 484 | -- Dig based on shape |
| 485 | if shape == "straight" then |
| 486 | digStraightTunnel(height, width, length, autoPlace) |
| 487 | else |
| 488 | digDomeTunnel(shape, length, autoPlace) |
| 489 | end |
| 490 | |
| 491 | if segment then |
| 492 | print("Segment " .. segment .. " complete") |
| 493 | end |
| 494 | end |
| 495 | |
| 496 | -- Multi-turtle command |
| 497 | local function multiCommand() |
| 498 | local function findModem() |
| 499 | for _, side in pairs(rs.getSides()) do |
| 500 | if peripheral.isPresent(side) and peripheral.getType(side) == "modem" then |
| 501 | return side |
| 502 | end |
| 503 | end |
| 504 | error("No modem found!") |
| 505 | end |
| 506 | |
| 507 | rednet.open(findModem()) |
| 508 | |
| 509 | print("Multi-Turtle eDig") |
| 510 | write("Tunnel type (straight/dome/size2) [straight]: ") |
| 511 | local shape = string.lower(read()) |
| 512 | if shape ~= "dome" and shape ~= "size2" then |
| 513 | shape = "straight" |
| 514 | end |
| 515 | |
| 516 | local height, width, length |
| 517 | if shape == "straight" then |
| 518 | write("Tunnel height (blocks) [3]: ") |
| 519 | height = tonumber(read()) or 3 |
| 520 | |
| 521 | write("Tunnel width (blocks) [3]: ") |
| 522 | width = tonumber(read()) or 3 |
| 523 | else |
| 524 | height = DOME_SHAPES[shape].heights[1] |
| 525 | width = DOME_SHAPES[shape].width |
| 526 | print("Dome shape: " .. shape .. " (" .. width .. " wide, max " .. DOME_SHAPES[shape].maxTurtles .. " turtles)") |
| 527 | end |
| 528 | |
| 529 | write("Tunnel length (blocks) [32]: ") |
| 530 | length = tonumber(read()) or 32 |
| 531 | |
| 532 | write("Place floor blocks? (y/n) [n]: ") |
| 533 | local place = string.lower(read()) == "y" and "place" or "" |
| 534 | |
| 535 | write("Turtle IDs (space-separated): ") |
| 536 | local idStr = read() |
| 537 | local ids = {} |
| 538 | for id in idStr:gmatch("%S+") do |
| 539 | local num = tonumber(id) |
| 540 | if num then table.insert(ids, num) end |
| 541 | end |
| 542 | |
| 543 | if #ids == 0 then |
| 544 | print("No valid turtle IDs") |
| 545 | return |
| 546 | end |
| 547 | |
| 548 | -- Limit turtles based on shape |
| 549 | local maxTurtles = shape == "straight" and width or DOME_SHAPES[shape].maxTurtles |
| 550 | if #ids > maxTurtles then |
| 551 | print("Warning: " .. shape .. " shape supports max " .. maxTurtles .. " turtles") |
| 552 | print("Using first " .. maxTurtles .. " turtles") |
| 553 | while #ids > maxTurtles do |
| 554 | table.remove(ids) |
| 555 | end |
| 556 | end |
| 557 | |
| 558 | write("Segment mode? (y/n) [n]: ") |
| 559 | local segmentMode = string.lower(read()) == "y" |
| 560 | |
| 561 | local segmentLength = 0 |
| 562 | if segmentMode then |
| 563 | write("Segment length (blocks per turtle) [8]: ") |
| 564 | segmentLength = tonumber(read()) or 8 |
| 565 | end |
| 566 | |
| 567 | -- Build command |
| 568 | local cmd = tostring(height) .. " " .. tostring(length) .. " " .. tostring(width) |
| 569 | if place ~= "" then cmd = cmd .. " " .. place end |
| 570 | if shape ~= "straight" then cmd = cmd .. " " .. shape end |
| 571 | |
| 572 | -- Send to turtles with coordination |
| 573 | print("Sending coordinated jobs to " .. #ids .. " turtles...") |
| 574 | print("All turtles will start simultaneously") |
| 575 | |
| 576 | if segmentMode then |
| 577 | local totalLength = length |
| 578 | local segments = math.ceil(totalLength / segmentLength) |
| 579 | |
| 580 | for i = 1, #ids do |
| 581 | local turtleId = ids[i] |
| 582 | local segmentStart = (i - 1) * segmentLength |
| 583 | local segmentEnd = math.min(segmentStart + segmentLength, totalLength) |
| 584 | local segmentLengthActual = segmentEnd - segmentStart |
| 585 | |
| 586 | if segmentLengthActual > 0 then |
| 587 | local segmentCmd = cmd .. " " .. tostring(i) |
| 588 | print("Turtle " .. turtleId .. " (Segment " .. i .. "): " .. segmentLengthActual .. " blocks") |
| 589 | rednet.send(turtleId, {command = "RUN", args = segmentCmd}) |
| 590 | end |
| 591 | end |
| 592 | else |
| 593 | -- Simultaneous row-based coordination |
| 594 | for i = 1, #ids do |
| 595 | local turtleId = ids[i] |
| 596 | local rowCmd = cmd .. " " .. tostring(i) .. " " .. tostring(width) |
| 597 | print("Turtle " .. turtleId .. " (Row " .. i .. "): " .. width .. " blocks wide") |
| 598 | rednet.send(turtleId, {command = "RUN", args = rowCmd}) |
| 599 | end |
| 600 | end |
| 601 | |
| 602 | print("Jobs sent! All turtles starting simultaneously...") |
| 603 | end |
| 604 | |
| 605 | -- Client command |
| 606 | local function clientCommand() |
| 607 | local function findModem() |
| 608 | for _, side in pairs(rs.getSides()) do |
| 609 | if peripheral.isPresent(side) and peripheral.getType(side) == "modem" then |
| 610 | return side |
| 611 | end |
| 612 | end |
| 613 | error("No modem found!") |
| 614 | end |
| 615 | |
| 616 | rednet.open(findModem()) |
| 617 | local id = os.getComputerID() |
| 618 | |
| 619 | print("eDig client ready (ID: " .. id .. ")") |
| 620 | print("Waiting for jobs...") |
| 621 | |
| 622 | while true do |
| 623 | local sender, msg, protocol = rednet.receive() |
| 624 | |
| 625 | local cmd = "" |
| 626 | if type(msg) == "table" and msg.command == "RUN" then |
| 627 | cmd = msg.args or "" |
| 628 | elseif type(msg) == "string" then |
| 629 | cmd = msg |
| 630 | end |
| 631 | |
| 632 | if cmd ~= "" then |
| 633 | print("Running: edig dig " .. cmd) |
| 634 | local ok, err = pcall(function() |
| 635 | shell.run("edig dig " .. cmd) |
| 636 | end) |
| 637 | |
| 638 | if ok then |
| 639 | rednet.send(sender, {status = "done", id = id}) |
| 640 | print("Job completed") |
| 641 | else |
| 642 | rednet.send(sender, {status = "error", id = id, error = err}) |
| 643 | print("Job failed: " .. tostring(err)) |
| 644 | end |
| 645 | end |
| 646 | end |
| 647 | end |
| 648 | |
| 649 | -- Install command |
| 650 | local function installCommand() |
| 651 | print("Installing eDig system...") |
| 652 | |
| 653 | local files = { |
| 654 | "https://raw.githubusercontent.com/perlytiara/CC-Tweaked-TurtsAndComputers/refs/heads/main/programs/perlytiara/eDig/edig.lua" |
| 655 | } |
| 656 | |
| 657 | local function downloadFile(url, filename) |
| 658 | print("Downloading " .. filename .. "...") |
| 659 | local result = shell.run("wget", url, filename) |
| 660 | if result then |
| 661 | print("✓ " .. filename) |
| 662 | return true |
| 663 | else |
| 664 | print("✗ Failed to download " .. filename) |
| 665 | return false |
| 666 | end |
| 667 | end |
| 668 | |
| 669 | local success = 0 |
| 670 | |
| 671 | if downloadFile(files[1], "edig") then |
| 672 | success = success + 1 |
| 673 | end |
| 674 | |
| 675 | print("Installed " .. success .. " files") |
| 676 | |
| 677 | if turtle then |
| 678 | print("Turtle setup complete!") |
| 679 | print("Run 'edig client' to start listening for jobs") |
| 680 | print("Or run 'edig dig <height> <length> <width> [place] [segment]' directly") |
| 681 | else |
| 682 | print("Computer setup complete!") |
| 683 | print("Run 'edig multi' to send jobs to turtles") |
| 684 | end |
| 685 | end |
| 686 | |
| 687 | -- Help command |
| 688 | local function helpCommand() |
| 689 | print("eDig Advanced Tunnel System") |
| 690 | print("Usage: edig [command] [args...]") |
| 691 | print() |
| 692 | print("Commands:") |
| 693 | print(" dig [height] [length] [width] [place] [segment] [shape]") |
| 694 | print(" - Dig tunnels (straight or dome shapes)") |
| 695 | print(" - Shapes: straight, dome, size2") |
| 696 | print(" - Interactive mode if no args provided") |
| 697 | print() |
| 698 | print(" multi") |
| 699 | print(" - Send coordinated jobs to multiple turtles") |
| 700 | print(" - Supports simultaneous row-based coordination") |
| 701 | print(" - Dome shapes: max 7 turtles (size2), max 5 turtles (custom)") |
| 702 | print() |
| 703 | print(" client") |
| 704 | print(" - Start remote listener for jobs") |
| 705 | print(" - Use on turtle clients") |
| 706 | print() |
| 707 | print(" install") |
| 708 | print(" - Download and install the system") |
| 709 | print() |
| 710 | print(" help") |
| 711 | print(" - Show this help message") |
| 712 | print() |
| 713 | print("Examples:") |
| 714 | print(" edig dig 3 32 3 -- 3x3x32 straight tunnel") |
| 715 | print(" edig dig 4 50 5 place -- 4x5x50 tunnel with floors") |
| 716 | print(" edig dig 0 100 0 dome -- 7-wide dome tunnel (size2)") |
| 717 | print(" edig multi -- Multi-turtle coordinator") |
| 718 | print(" edig client -- Start turtle client") |
| 719 | end |
| 720 | |
| 721 | -- Main command router |
| 722 | local command = args[1] or "help" |
| 723 | |
| 724 | if command == "dig" then |
| 725 | digCommand() |
| 726 | elseif command == "multi" then |
| 727 | multiCommand() |
| 728 | elseif command == "client" then |
| 729 | clientCommand() |
| 730 | elseif command == "install" then |
| 731 | installCommand() |
| 732 | elseif command == "help" then |
| 733 | helpCommand() |
| 734 | else |
| 735 | print("Unknown command: " .. command) |
| 736 | print("Use 'edig help' for available commands") |
| 737 | end |