Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- Minecraft Turtle Delivery Script
- --]]
- -- ========= CONFIGURATION =========
- local ENABLE_FILE_LOGGING = true
- local LOG_FILE_NAME = "turtle_delivery.log"
- local BUILDER_CHEST_CLEAR_TRIPS = 4 -- How many trips to make to try and clear builder's chest
- -- ===============================
- local AUTOMATA_TYPE = "endAutomata"
- local ME_BRIDGE_TYPE = "meBridge"
- local COLONY_INTEGRATOR_TYPE = "colonyIntegrator"
- local ME_BRIDGE_BLOCK_ID = "advancedperipherals:me_bridge"
- local SLOT_NUMBER_FILE = "builder_slot.txt"
- local HOME_POINT_NAME = "home"
- local DELIVERY_POINT_NAME = "deliveryPoint"
- local BUILDER_HUT_TYPE_PATTERN = "builder"
- local automata
- local meBridge, colonyIntegrator
- local function getTimestamp() return os.date("%Y-%m-%d %H:%M:%S") end
- local function log(message)
- print(message)
- if ENABLE_FILE_LOGGING then
- local fileMessage = "[" .. getTimestamp() .. "] " .. message
- local file, err = fs.open(LOG_FILE_NAME, "a")
- if file then
- file.writeLine(fileMessage)
- file.close()
- else
- print("ERROR: Could not write to log file '" .. LOG_FILE_NAME .. "': " .. tostring(err))
- end
- end
- end
- if ENABLE_FILE_LOGGING then
- local initialFileMessage = "[" .. getTimestamp() .. "] --- Turtle script started. Logging enabled. ---"
- local file, err = fs.open(LOG_FILE_NAME, "a")
- if file then
- file.writeLine(initialFileMessage)
- file.close()
- else
- print("ERROR: Could not write initial message to log file '" .. LOG_FILE_NAME .. "': " .. tostring(err))
- end
- end
- local function setupEssentialPeripherals()
- log("Setting up essential peripherals...")
- automata = peripheral.find(AUTOMATA_TYPE)
- if not automata then log("CRITICAL ERROR: End Automata ('" .. AUTOMATA_TYPE .. "') not found!"); return false end
- log("End Automata found.")
- if not rs then log("CRITICAL ERROR: Redstone API (rs) not available!"); return false end
- log("Redstone API found.")
- log("Essential peripherals setup complete.")
- return true
- end
- local function setupOperationalPeripherals()
- log("Setting up operational peripherals (at home base)...")
- local meBridgeFound = false
- meBridge = peripheral.find(ME_BRIDGE_TYPE)
- if not meBridge then log("ERROR: ME Bridge ('" .. ME_BRIDGE_TYPE .. "') not found at home base!")
- else log("ME Bridge found."); meBridgeFound = true end
- colonyIntegrator = peripheral.find(COLONY_INTEGRATOR_TYPE)
- if not colonyIntegrator then log("WARN: Colony Integrator ('" .. COLONY_INTEGRATOR_TYPE .. "') not found.")
- else log("Colony Integrator found.") end
- return meBridgeFound
- end
- local function warpTo(pointName)
- if not automata then log("Automata not available for warp."); return false end
- log("Attempting warp to " .. pointName .. "...")
- local currentFuel = turtle.getFuelLevel()
- if type(currentFuel) == "number" and currentFuel < 50 and pointName ~= HOME_POINT_NAME then
- log("WARN: Low fuel ("..currentFuel..") before warp to "..pointName..".")
- elseif currentFuel == 0 and pointName ~= HOME_POINT_NAME then
- log("ERROR: No fuel to attempt warp to "..pointName..".")
- return false
- end
- local success, reasonOrResult = pcall(automata.warpToPoint, pointName)
- if success then
- if reasonOrResult == true or (type(reasonOrResult) == "string" and string.match(string.lower(reasonOrResult), "success")) then
- log("Warp to " .. pointName .. " successful.")
- return true
- elseif reasonOrResult == nil then
- log("Warp to " .. pointName .. " successful (returned true, nil).")
- return true
- else
- log("ERROR: Warp to " .. pointName .. " call succeeded but peripheral reported failure: " .. tostring(reasonOrResult))
- return false
- end
- else
- log("ERROR: Warp to " .. pointName .. " pcall failed: " .. tostring(reasonOrResult))
- return false
- end
- end
- local function orientToMEBridge()
- log("Orienting to ME Bridge block ('" .. ME_BRIDGE_BLOCK_ID .. "')...")
- for i = 1, 4 do
- local s, data = turtle.inspect()
- if s and data and data.name == ME_BRIDGE_BLOCK_ID then log("ME Bridge block found in front."); return true end
- log("Not found in front. Turning right...")
- turtle.turnRight(); os.sleep(0.5)
- end
- log("ERROR: ME Bridge block not found in front after 4 turns.")
- return false
- end
- -- findEmptySlot is no longer strictly needed for item collection but might be useful for other things like refueling.
- local function findEmptySlot()
- for i = 1, 16 do if turtle.getItemCount(i) == 0 then return i end end
- return nil
- end
- local function clearTurtleInventoryToME()
- if not meBridge then log("ME Bridge not found for inv clear."); return false end
- log("Clearing turtle inventory to ME...")
- local anyFailed = false
- for slot = 1, 16 do
- local itemDetail = turtle.getItemDetail(slot)
- if itemDetail then
- turtle.select(slot)
- if turtle.dropUp(itemDetail.count) then
- local itemToImport = {name=itemDetail.name, count=itemDetail.count, nbt=itemDetail.nbt}
- local importedCount, err = meBridge.importItem(itemToImport, "up")
- if importedCount and importedCount > 0 then
- if importedCount < itemDetail.count then log("WARN: Not all "..itemDetail.name.." imported from chest. ".. (itemDetail.count - importedCount) .. " left?"); anyFailed = true end
- elseif importedCount == 0 then log("WARN: Imported 0 of " .. itemDetail.name .. " from chest. ME full/not accepted? Stuck in chest."); anyFailed = true
- else log("ERROR importing " .. itemDetail.name .. " from chest: " .. (err or "unknown")); anyFailed = true end
- else log("WARN: Failed to dropUp item from slot " .. slot .. " ("..itemDetail.name..")"); anyFailed = true end
- end
- end
- if anyFailed then log("Turtle inv clear had issues.") else log("Turtle inv clear done.") end
- return not anyFailed
- end
- local function clearChestAboveToME()
- if not meBridge then log("ME Bridge not found for chest clear."); return false end
- log("Clearing chest above to ME...")
- local tempSlot = findEmptySlot()
- if not tempSlot then log("No empty turtle slot for chest clear. Skipping."); return end
- local originalSelectedSlot = turtle.getSelectedSlot()
- turtle.select(tempSlot)
- local emptySuckCycles = 0
- while emptySuckCycles < 3 do
- local itemsFoundThisCycle = false
- while turtle.suckUp(1) do
- itemsFoundThisCycle = true; emptySuckCycles = 0
- local itemDetail = turtle.getItemDetail(tempSlot)
- if not itemDetail then log("ERROR: Sucked item, no detail. Breaking."); turtle.select(originalSelectedSlot); return end
- if turtle.dropUp(1) then
- local itemToImport = {name=itemDetail.name, nbt=itemDetail.nbt}
- local totalImportedThisType = 0
- for _=1,10 do
- local imported, err = meBridge.importItem(itemToImport, "up")
- if imported and imported > 0 then totalImportedThisType = totalImportedThisType + imported
- else if err then log("Error importing "..itemDetail.name.." from chest: " .. err) end; break end
- if imported < 64 then break end; os.sleep(0.1)
- end
- if totalImportedThisType > 0 then log("Imported total " .. totalImportedThisType .. " of " .. itemDetail.name .. " from chest.") end
- else
- log("ERROR: Sucked item, failed dropUp. Importing from turtle slot " ..tempSlot)
- meBridge.importItem({name=itemDetail.name, count=itemDetail.count, nbt=itemDetail.nbt}, "up")
- end
- if turtle.getItemCount(tempSlot) > 0 then
- log("WARN: Temp slot " ..tempSlot.. " not empty: " .. turtle.getItemDetail(tempSlot).name .. ". Clearing.")
- local leftover = turtle.getItemDetail(tempSlot)
- if leftover then turtle.dropUp(leftover.count); meBridge.importItem({name=leftover.name, count=leftover.count, nbt=leftover.nbt}, "up") end
- end; os.sleep(0.1)
- end
- if not itemsFoundThisCycle then emptySuckCycles = emptySuckCycles + 1; if emptySuckCycles == 3 then log("Chest above appears empty (checked 3x).") end end
- os.sleep(0.2)
- end
- turtle.select(originalSelectedSlot)
- end
- local function ensureFuel()
- if not meBridge then log("ME Bridge not found for refueling."); return false end
- local fuelLevelStr = turtle.getFuelLevel()
- if fuelLevelStr == "unlimited" then log("Fuel is unlimited."); return true end
- local currentFuelNum = tonumber(fuelLevelStr) or 0
- local maxFuelNum = tonumber(turtle.getFuelLimit()) or 0
- if maxFuelNum == 0 then log("Max fuel is 0. Cannot refuel."); return true end
- if currentFuelNum >= maxFuelNum * 0.8 then return true end
- log("Refueling needed. Current: " .. tostring(currentFuelNum) .. "/" .. tostring(maxFuelNum))
- local fuelItems = {
- {name="minecraft:coal_block", count=16}, {name="minecraft:charcoal_block", count=16},
- {name="minecraft:coal", count=64}, {name="minecraft:charcoal", count=64}
- }
- local refueledOverall = false
- for _, fuelItemSpec in ipairs(fuelItems) do
- log("Attempting to get " .. fuelItemSpec.name .. " (max " .. fuelItemSpec.count .. ").")
- local numExported, err_export = meBridge.exportItem(fuelItemSpec, "up")
- if numExported and numExported > 0 then
- log("Exported " .. numExported .. " " .. fuelItemSpec.name .. " to chest.")
- local originalSlot = turtle.getSelectedSlot()
- local tempSlot = findEmptySlot()
- if not tempSlot then
- log("No empty slot for fuel. Returning to ME.")
- meBridge.importItem({name=fuelItemSpec.name, count=numExported}, "up"); turtle.select(originalSlot)
- goto continue_fuel_loop
- end
- turtle.select(tempSlot)
- local suckedCount = 0
- for _=1, numExported do if turtle.suckUp(1) then suckedCount = suckedCount + 1 else break end end
- if suckedCount > 0 then
- log("Sucked " .. suckedCount .. " of " .. fuelItemSpec.name .. ".")
- local fuelBefore = tonumber(turtle.getFuelLevel()) or 0
- local refuelOpRes = turtle.refuel()
- local fuelAfter = tonumber(turtle.getFuelLevel()) or 0
- local gained = 0
- if type(refuelOpRes) == "number" then gained = refuelOpRes elseif refuelOpRes == true then gained = fuelAfter - fuelBefore; if gained < 0 then gained = 0 end end
- log("Refuel op. Gained: " .. tostring(gained) .. " points.")
- if gained > 0 then refueledOverall = true end
- else log("Failed to suck any " .. fuelItemSpec.name .. " from chest (" .. numExported .. " exported).") end
- if suckedCount < numExported then
- log("Returning " .. (numExported - suckedCount) .. " unused " .. fuelItemSpec.name .. " (chest) to ME.")
- meBridge.importItem({name=fuelItemSpec.name, count=(numExported - suckedCount)}, "up")
- end
- if turtle.getItemCount(tempSlot) > 0 then
- log("Returning unused " .. fuelItemSpec.name .. " (turtle slot " ..tempSlot.. ") to ME.")
- local remaining = turtle.getItemDetail(tempSlot)
- if remaining then turtle.dropUp(remaining.count); meBridge.importItem({name=remaining.name, count=remaining.count, nbt=remaining.nbt}, "up")
- else log("WARN: Could not get item detail for remaining fuel in slot " .. tempSlot) end
- end
- turtle.select(originalSlot)
- local currentFuelCheck = tonumber(turtle.getFuelLevel()) or 0
- if currentFuelCheck >= maxFuelNum * 0.8 then log("Fuel target reached."); break end
- else
- if err_export then log("Error exporting " .. fuelItemSpec.name .. ": " .. tostring(err_export))
- else log("ME system has no " .. fuelItemSpec.name .. " or export failed (0 exported).") end
- end
- ::continue_fuel_loop::
- end
- local finalFuel = tonumber(turtle.getFuelLevel()) or 0
- if not refueledOverall and finalFuel < maxFuelNum * 0.8 then log("WARN: Refueling done, fuel might still be low: " .. tostring(finalFuel) .. "/" .. tostring(maxFuelNum)) end
- log("Fuel check finished. Current fuel: " .. tostring(finalFuel))
- return true
- end
- local function waitForLever()
- log("Waiting for lever (back=true)...")
- while not rs.getInput("back") do log("Lever off. Waiting 60s..."); os.sleep(60) end
- log("Lever ON.")
- end
- local function getActualBuilderHuts()
- if not colonyIntegrator then log("Colony Integrator not found for huts list."); return {} end
- log("Fetching builder huts list...")
- local ok, buildings = pcall(colonyIntegrator.getBuildings)
- if not ok then log("Could not get buildings (pcall error): " .. tostring(buildings)); return {} end
- if type(buildings) ~= "table" then log("Could not get buildings (not table): " .. tostring(buildings)); return {} end
- local huts = {}
- for _, b in ipairs(buildings) do if b and b.type and string.match(string.lower(b.type), string.lower(BUILDER_HUT_TYPE_PATTERN)) then table.insert(huts, b) end end
- log("Found " .. #huts .. " builder huts (pattern: '" .. BUILDER_HUT_TYPE_PATTERN .. "').")
- return huts
- end
- local function performInfoRetrievalMode()
- log("--- Info Retrieval Mode ---")
- if not colonyIntegrator then log("Colony Integrator not found for info mode."); return end
- local huts = getActualBuilderHuts()
- if #huts == 0 then log("No Builder's Huts found.")
- else
- log("Available Builder's Huts:")
- for i, h in ipairs(huts) do
- if h and h.location then log(string.format("[%d] %s (L%d) @ %.0f,%.0f,%.0f (%s)", i, h.name or "Unnamed", h.level or 0, h.location.x, h.location.y, h.location.z, h.type or "N/A"))
- else log("["..i.."] Invalid hut data.") end
- end
- log("To assign, create '" .. SLOT_NUMBER_FILE .. "' with hut number.")
- end
- log("---------------------------")
- end
- local function getAssignedBuilderSlot()
- if fs.exists(SLOT_NUMBER_FILE) then
- local file, err = fs.open(SLOT_NUMBER_FILE, "r")
- if file then
- local line = file.readLine(); file.close()
- if line then
- local num = tonumber(line)
- if num then return num end; log("WARN: Content of " .. SLOT_NUMBER_FILE .. " not number: '" .. line .. "'")
- else log("WARN: " .. SLOT_NUMBER_FILE .. " is empty.") end
- else log("ERROR: Could not open " .. SLOT_NUMBER_FILE .. ": " .. tostring(err)) end
- end
- return nil
- end
- local function requestAndCollectItems(resources)
- if not meBridge then log("ME Bridge not found for item request."); return false end
- if not resources then log("WARN: Resources table is nil."); return false end
- if #resources == 0 then log("No resources requested by builder."); return true end
- log("Requesting & collecting items... Found " .. #resources .. " resource entries.")
- local overallSuccess = true
- local anyValidResourceFound = false
- for i, res_entry in ipairs(resources) do
- log("Processing resource entry #" .. i .. ": " .. textutils.serialize(res_entry, {compact=true}))
- local currentItemName = nil
- if res_entry.item and type(res_entry.item) == "table" and res_entry.item.name then
- currentItemName = res_entry.item.name
- elseif type(res_entry.item) == "string" then -- Fallback based on documentation
- currentItemName = res_entry.item
- end
- local initialTotalNeededRaw = res_entry.needs
- local initialTotalNeeded = tonumber(initialTotalNeededRaw)
- local currentItemNBT = nil
- if res_entry.item and type(res_entry.item) == "table" and res_entry.item.nbt then
- currentItemNBT = res_entry.item.nbt
- end
- if currentItemName == nil then
- log("WARN: Entry #" .. i .. " is missing valid 'item' name. Skipping.")
- elseif initialTotalNeeded == nil then
- log("WARN: Entry #" .. i .. " 'needs' ('" .. tostring(initialTotalNeededRaw) .. "') not num. Item: " .. tostring(currentItemName) .. ". Skipping.")
- elseif initialTotalNeeded <= 0 then
- log("Skipping " .. currentItemName .. ": needed amount is zero or invalid (" .. tostring(initialTotalNeededRaw) .. ")")
- else
- anyValidResourceFound = true
- log(string.format("Need %d of %s", initialTotalNeeded, currentItemName))
- local collectedForItem = 0
- local loopIteration = 0
- while true do
- loopIteration = loopIteration + 1
- local loopTotalNeededForThisIteration = tonumber(res_entry.needs) or 0
- log(string.format("PRE-COMPARE (Item: %s, Pass: %d): collectedForItem=%s (type: %s), res_entry.needs=%s (type: %s), loopTotalNeededForThisIteration=%s (type: %s)",
- currentItemName, loopIteration,
- tostring(collectedForItem), type(collectedForItem),
- tostring(res_entry.needs), type(res_entry.needs),
- tostring(loopTotalNeededForThisIteration), type(loopTotalNeededForThisIteration)
- ))
- if collectedForItem == nil or loopTotalNeededForThisIteration == nil then
- log("CRITICAL DEBUG: A value IS NIL right before comparison! collectedForItem type: "..type(collectedForItem)..", loopTotalNeededForThisIteration type: "..type(loopTotalNeededForThisIteration))
- end
- if collectedForItem >= loopTotalNeededForThisIteration then
- log("DEBUG: Condition met (collected >= needed). Breaking while loop for " .. currentItemName)
- break
- end
- if loopTotalNeededForThisIteration == 0 then
- log("WARN: total needed for " .. currentItemName .. " became 0 or invalid mid-collection. Breaking loop.")
- break
- end
- -- Simplified slot finding: just try to suck. Turtle will place it.
- -- We need to know the currently selected slot before sucking to check if it's full *for that item type*
- -- However, the main constraint will be turtle.suckUp() failing if inventory is truly full.
- local amountToRequestThisPass = math.min(loopTotalNeededForThisIteration - collectedForItem, 64) -- Request up to a stack or remaining
- if amountToRequestThisPass <= 0 then
- log("Cannot request "..currentItemName..": amountToRequestThisPass is "..amountToRequestThisPass .. ". Breaking loop.")
- break
- end
- log(string.format("Requesting %d %s", amountToRequestThisPass, currentItemName))
- local itemFilter = {name=currentItemName, count=amountToRequestThisPass, nbt=currentItemNBT}
- local exportedCount, err_export = meBridge.exportItem(itemFilter, "up")
- if not exportedCount or exportedCount == 0 then
- log("ME has no "..currentItemName.." or export failed. (Err: "..tostring(err_export).."). Breaking loop.")
- break
- end
- log("ME exported "..exportedCount.." "..currentItemName.." to chest.")
- local suckedThisPass=0
- local canStillSuck = true
- for _=1,exportedCount do
- local emptySlotBeforeSuck = findEmptySlot() -- Check if there's any empty slot at all
- if not emptySlotBeforeSuck and turtle.getItemCount(turtle.getSelectedSlot()) > 0 and turtle.getItemSpace(turtle.getSelectedSlot()) == 0 then
- -- If no absolutely empty slot, and current slot is full (or can't stack more of this type)
- local isFullForAllTypes = true
- for s_check = 1, 16 do
- if turtle.getItemCount(s_check) == 0 then isFullForAllTypes = false; break end
- local detail = turtle.getItemDetail(s_check)
- if detail and detail.name == currentItemName and detail.count < (detail.maxStackSize or 64) then
- isFullForAllTypes = false; break
- end
- end
- if isFullForAllTypes then
- log("Turtle inventory appears completely full for new items or this type. Breaking suck loop.")
- canStillSuck = false
- break
- end
- end
- if turtle.suckUp(1) then
- suckedThisPass=suckedThisPass+1
- else
- log("turtle.suckUp(1) failed. Chest empty or inv full for this item.")
- canStillSuck = false
- break
- end
- end
- log("Sucked "..suckedThisPass.." "..currentItemName..".")
- collectedForItem = collectedForItem + suckedThisPass
- if suckedThisPass < exportedCount then
- log((exportedCount-suckedThisPass).." "..currentItemName.." left in chest. Returning.")
- meBridge.importItem({name=currentItemName, count=(exportedCount-suckedThisPass), nbt=currentItemNBT},"up")
- end
- if not canStillSuck or (suckedThisPass==0 and exportedCount>0) then
- log("WARN: Could not suck items or inventory became full. Breaking loop for "..currentItemName)
- break
- end
- os.sleep(0.2)
- end
- log(string.format("Collected %d / %d of %s", collectedForItem, initialTotalNeeded, currentItemName))
- if collectedForItem < initialTotalNeeded then overallSuccess = false end
- end
- end
- if not anyValidResourceFound and #resources > 0 then
- log("ERROR: Processed " .. #resources .. " resource entries, but none were valid for processing.")
- return false
- end
- return overallSuccess
- end
- local function attemptClearBuilderChest()
- log("Attempting to clear builder's chest at delivery point...")
- local itemsMovedFromBuilderChest = 0
- for trip = 1, BUILDER_CHEST_CLEAR_TRIPS do
- log("Builder chest clear: Trip " .. trip .. "/" .. BUILDER_CHEST_CLEAR_TRIPS)
- if not warpTo(DELIVERY_POINT_NAME) then
- log("Builder chest clear: Failed to warp to delivery point for trip " .. trip .. ". Aborting clear.")
- return itemsMovedFromBuilderChest > 0
- end
- -- Move down to ensure we are above the chest
- local movesDown = 0
- while not turtle.detectDown() and movesDown < 10 do
- if not turtle.down() then log("Builder chest clear: Failed to move down. Blocked?"); break end
- movesDown = movesDown + 1; os.sleep(0.2)
- end
- if not turtle.detectDown() and movesDown > 0 then
- log("Builder chest clear: Could not find surface below after moving down. Aborting clear for this trip.")
- goto next_clear_trip -- Continue to next trip, maybe issue resolves
- end
- local suckedThisTrip = 0
- local anySuckedThisPass
- repeat
- anySuckedThisPass = false
- for slot = 1, 16 do -- Try to fill turtle inventory
- if turtle.getItemCount(slot) == 0 then -- Found an empty slot in turtle
- if turtle.suckDown(1) then
- suckedThisTrip = suckedThisTrip + 1
- anySuckedThisPass = true
- itemsMovedFromBuilderChest = itemsMovedFromBuilderChest + 1
- local suckedItem = turtle.getItemDetail(slot)
- if suckedItem then log("Builder chest clear: Sucked 1x " .. suckedItem.name)
- else log("Builder chest clear: Sucked an item, but no details.") end
- os.sleep(0.1)
- else
- -- suckDown failed, slot might be full for this item type or chest empty for this pull
- goto end_suck_loop_for_trip -- Break inner, then outer if needed
- end
- end
- end
- until not anySuckedThisPass
- ::end_suck_loop_for_trip::
- if suckedThisTrip > 0 then
- log("Builder chest clear: Sucked " .. suckedThisTrip .. " items this trip. Returning to home to deposit.")
- if not warpTo(HOME_POINT_NAME) then
- log("Builder chest clear: CRITICAL - Failed to warp home with items from builder. Items might be lost. Aborting.")
- return itemsMovedFromBuilderChest > 0 -- Return status so far
- end
- if not orientToMEBridge() then
- log("Builder chest clear: CRITICAL - Failed to orient at home. Cannot deposit items. Aborting.")
- return itemsMovedFromBuilderChest > 0
- end
- if not meBridge then
- if not setupOperationalPeripherals() or not meBridge then
- log("Builder chest clear: CRITICAL - ME Bridge lost and cannot be reacquired. Items stuck in turtle. Aborting.")
- return itemsMovedFromBuilderChest > 0
- end
- end
- clearTurtleInventoryToME() -- Deposit everything sucked
- else
- log("Builder chest clear: Sucked no items this trip. Assuming builder chest is empty or inaccessible.")
- break -- Exit the trip loop
- end
- ::next_clear_trip::
- end
- log("Builder chest clearing attempt finished. Total items moved: " .. itemsMovedFromBuilderChest)
- return itemsMovedFromBuilderChest > 0
- end
- local function performAssignedBuilderDelivery()
- log("--- Assigned Builder Delivery Mode ---")
- if not (colonyIntegrator and meBridge) then log("Integrator or ME Bridge missing. Cannot perform delivery."); return end
- local slotNum = getAssignedBuilderSlot()
- if not slotNum then log("Builder slot file missing/invalid."); return end
- log("Assigned to builder slot: " .. slotNum)
- local allHuts = getActualBuilderHuts()
- if #allHuts == 0 then log("No builder huts in colony."); return end
- if slotNum <= 0 or slotNum > #allHuts then log("ERROR: Slot " .. slotNum .. " out of range (1-" .. #allHuts .. ")."); return end
- local targetHut = allHuts[slotNum]
- if not (targetHut and targetHut.location) then log("ERROR: Target hut data invalid for slot " .. slotNum); return end
- log(string.format("Targeting: %s @ %.0f,%.0f,%.0f", targetHut.name or "Unnamed", targetHut.location.x, targetHut.location.y, targetHut.location.z))
- local resources, err_res = colonyIntegrator.getBuilderResources(targetHut.location)
- if not resources then
- log("Could not get resources for builder: " .. tostring(err_res)); return
- end
- local collectionSuccessfulOrNotNeeded = true
- if #resources > 0 then
- collectionSuccessfulOrNotNeeded = requestAndCollectItems(resources)
- if not collectionSuccessfulOrNotNeeded then log("WARN: Item collection phase reported issues.")
- else log("Item collection process reported success.") end
- else
- log("Builder needs no resources according to getBuilderResources().")
- end
- local anyItemsInInventory = false
- for s=1,16 do if turtle.getItemCount(s) > 0 then anyItemsInInventory = true; break end end
- if not anyItemsInInventory then
- log("No items in inventory to deliver. Skipping warp to delivery.")
- return
- end
- log("Proceeding to delivery point: " .. DELIVERY_POINT_NAME)
- if warpTo(DELIVERY_POINT_NAME) then
- log("Arrived at delivery. Moving down for drop...")
- local movesDown = 0
- while not turtle.detectDown() and movesDown < 10 do if not turtle.down() then log("Move down failed."); break end; movesDown=movesDown+1; os.sleep(0.2) end
- if turtle.detectDown() or movesDown == 0 then
- log("Surface detected/assumed. Dumping inventory down.")
- local deliveryFailedDueToFullChest = false
- for s=1,16 do
- if turtle.getItemCount(s)>0 then
- turtle.select(s);
- local d=turtle.getItemDetail(s);
- if d then
- log("Dumping "..d.count.."x "..d.name.." down.");
- if not turtle.dropDown() then
- log("WARN: dropDown() failed for "..d.name..". Builder's chest might be full.")
- deliveryFailedDueToFullChest = true
- break -- Stop trying to drop more if one fails
- end;
- os.sleep(0.1)
- else log("WARN: Slot "..s.." has items but getItemDetail returned nil. Skipping.") end
- end
- end
- if deliveryFailedDueToFullChest then
- log("Delivery failed, builder's chest likely full. Initiating reverse and clear process.")
- if warpTo(HOME_POINT_NAME) then
- if orientToMEBridge() and meBridge then
- clearTurtleInventoryToME() -- Return what couldn't be delivered
- attemptClearBuilderChest() -- This will try to empty builder's chest
- -- After this, the main loop will continue, effectively retrying the whole process.
- else
- log("CRITICAL: Could not return to home base ME setup after failed delivery. Items stuck.")
- end
- else
- log("CRITICAL: Could not warp home after failed delivery. Items stuck at builder.")
- end
- else
- log("Inventory dump (down) complete.")
- end
- else log("No surface below after " .. movesDown .. " moves. Items remain.") end
- else log("Failed warp to delivery. Items remain.") end
- end
- local function main()
- term.clear(); term.setCursorPos(1,1)
- log("Main script execution started.")
- if not setupEssentialPeripherals() then log("Critical essential peripheral setup failed. Exiting."); return end
- while true do
- log("=== New Cycle Started ===")
- if not warpTo(HOME_POINT_NAME) then log("CRITICAL: Failed warp to home. Cycle cannot continue. Waiting 60s."); os.sleep(60); goto continue_loop end
- if not orientToMEBridge() then log("Failed orient to ME Bridge at home. Waiting 60s."); os.sleep(60); goto continue_loop end
- local opReady = setupOperationalPeripherals()
- if opReady then clearTurtleInventoryToME(); os.sleep(0.5); clearChestAboveToME(); os.sleep(0.5); ensureFuel(); os.sleep(0.5)
- else log("ME Bridge not found at home. Skipping ME tasks."); os.sleep(10) end
- waitForLever(); os.sleep(0.5)
- local slotFileExists = fs.exists(SLOT_NUMBER_FILE)
- if slotFileExists then
- if opReady and colonyIntegrator then performAssignedBuilderDelivery()
- else
- log("Slot file exists, but ME Bridge or Integrator missing.")
- if colonyIntegrator then log("Integrator found, attempting info mode."); performInfoRetrievalMode()
- else log("Integrator also missing, cannot run info mode.") end
- log("Delivery prereqs not met. Wait 60s.")
- os.sleep(60)
- end
- else
- log("Slot file '"..SLOT_NUMBER_FILE.."' not found.")
- log("Proceeding to info mode (if Integrator available).")
- if colonyIntegrator then performInfoRetrievalMode() else log("Integrator missing, cannot run info mode.") end
- log("Info mode done. Wait 60s."); os.sleep(60)
- end
- log("Cycle complete. Returning home..."); os.sleep(2)
- ::continue_loop::
- end
- end
- main()
- log("Script main function has unexpectedly exited the main loop.")
Add Comment
Please, Sign In to add comment