Myros27

ColonySupplier V3.2

May 16th, 2025 (edited)
57
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 25.35 KB | None | 0 0
  1. --[[
  2. MineColonies Builder Request Fulfillment Bot
  3. Version 3.2
  4.  
  5. Changelog v3.2:
  6. - Random Work Order Selection: If multiple suitable work orders are found,
  7.   one is chosen at random to prevent one problematic order from blocking others.
  8. - Reinforces delivering partial shipments (already mostly in place by design).
  9. - Previous fixes from v3.1 remain.
  10.  
  11. Setup: (Same as v2.0)
  12. ]]
  13.  
  14. -- Configuration (same as v3.1)
  15. local ME_BRIDGE_NAME = "meBridge"
  16. local END_AUTOMATA_NAME = "endAutomata"
  17. local COLONY_INTEGRATOR_NAME = "colonyIntegrator"
  18. local HOME_WARP_POINT = "home"
  19. local COLONY_WARP_POINT = "colony"
  20. local NAMED_BUILDING_STORAGE_SUFFIX = "_storage"
  21. local COAL_SLOT = 16
  22. local COAL_RESERVE_AMOUNT = 64
  23. local LOW_FUEL_THRESHOLD = 200
  24. local DETAILED_RESOURCE_LOG_FILE = "builder_bot_resource_details.log"
  25. local MAIN_LOG_FILE = "builder_bot_main.log"
  26.  
  27. local automata = nil
  28.  
  29. -- [[ Logging Function (same as v3.0) ]]
  30. local function log(message)
  31.     local timestamp = textutils.formatTime(os.time(), false)
  32.     local logMessage = "[" .. timestamp .. "] " .. tostring(message)
  33.     print(logMessage)
  34.     local file = fs.open(MAIN_LOG_FILE, "a")
  35.     if file then file.writeLine(logMessage) file.close()
  36.     else print("ERROR: Could not write to main log file: " .. MAIN_LOG_FILE) end
  37. end
  38.  
  39. -- [[ HELPER FUNCTIONS (initialPeripheralCheck, ensureFuel, warpTo, findEmptySlot, consolidateInventory, returnUnusedItemsToME, getItemsFromME, deliverItems, prepareAtHomeBase - same as v3.1) ]]
  40. -- These functions are assumed to be identical to v3.1 and are omitted for brevity.
  41. local function initialPeripheralCheck()
  42.     automata = peripheral.find(END_AUTOMATA_NAME)
  43.     if not automata then log("CRITICAL ERROR: End Automata ('" .. END_AUTOMATA_NAME .. "') not found!") return false end
  44.     log("End Automata found.")
  45.     return true
  46. end
  47.  
  48. local function ensureFuel(atHome)
  49.     log("Ensuring fuel. Turtle is " .. (atHome and "at home." or "not at home."))
  50.     if turtle.getFuelLevel() < LOW_FUEL_THRESHOLD then
  51.         turtle.select(COAL_SLOT)
  52.         if turtle.getItemCount(COAL_SLOT) > 0 then log("Fuel is low (" .. turtle.getFuelLevel() .. "). Refueling from coal slot...") turtle.refuel() log("Fuel level after attempting refuel: " .. turtle.getFuelLevel())
  53.         else log("Fuel is low, but no coal in slot " .. COAL_SLOT .. " to use.") end
  54.     end
  55.     if atHome then
  56.         log("At home: Attempting to stock coal and maximize fuel.")
  57.         turtle.select(COAL_SLOT)
  58.         local currentCoal = turtle.getItemCount(COAL_SLOT)
  59.         if currentCoal < COAL_RESERVE_AMOUNT then
  60.             local amountToSuck = COAL_RESERVE_AMOUNT - currentCoal
  61.             log("Coal slot " .. COAL_SLOT .. " has " .. currentCoal .. "/" .. COAL_RESERVE_AMOUNT .. ". Sucking up to " .. amountToSuck .. " from chest below...")
  62.             local suckResult = turtle.suckDown(amountToSuck)
  63.             if type(suckResult) == "number" then
  64.                 if suckResult > 0 then log("Sucked " .. suckResult .. " additional coal (numeric return).")
  65.                 else log("Sucked 0 items (numeric return; chest empty or other issue).") end
  66.             elseif suckResult == true then log("suckDown returned true. Assuming " .. amountToSuck .. " (or available) coal sucked.")
  67.             elseif suckResult == false then log("Failed to suck coal (suckDown returned false).")
  68.             else log("WARN: turtle.suckDown returned unexpected type: " .. type(suckResult) .. ", value: " .. tostring(suckResult)) end
  69.         else log("Coal slot " .. COAL_SLOT .. " is already full or has sufficient reserve.") end
  70.         turtle.select(COAL_SLOT)
  71.         if turtle.getItemCount(COAL_SLOT) > 0 then log("Refueling turtle at home base from slot " .. COAL_SLOT .. "...") turtle.refuel() log("Fuel level after home refueling: " .. turtle.getFuelLevel())
  72.         else log("No coal in slot " .. COAL_SLOT .. " to perform home refueling.") end
  73.     end
  74.     if turtle.getFuelLevel() == 0 then log("CRITICAL: Turtle has zero fuel!") return false end
  75.     log("Fuel check complete. Current level: " .. turtle.getFuelLevel())
  76.     return true
  77. end
  78.  
  79. local function warpTo(pointName)
  80.     log("Attempting to warp to '" .. pointName .. "'...")
  81.     if turtle.getFuelLevel() == 0 then log("  ERROR: Zero fuel. Cannot warp.") return false end
  82.     local success, reason = automata.warpToPoint(pointName)
  83.     if success then log("Warp successful to " .. pointName) os.sleep(2) return true
  84.     else log("ERROR: Failed to warp to " .. pointName .. ": " .. (reason or "unknown error")) return false end
  85. end
  86.  
  87. local function findEmptySlot() for i = 1, 15 do if turtle.getItemCount(i) == 0 then return i end end return nil end
  88. local function consolidateInventory() log("Consolidating inventory...") for i = 1, 15 do turtle.select(i) if turtle.getItemCount(i) > 0 then for j = i + 1, 15 do if turtle.compareTo(j) then local space = turtle.getItemSpace(i) if space > 0 then turtle.select(j) turtle.transferTo(i, math.min(space, turtle.getItemCount(j))) end end end end end turtle.select(1) end
  89.  
  90. local function returnUnusedItemsToME(bridge)
  91.     if not bridge then log("ERROR (returnUnused): ME Bridge not provided!") return end
  92.     log("Returning unused items to ME system (at home)...")
  93.     turtle.up()
  94.     local itemsDroppedDetails = {}
  95.     for i = 1, 15 do
  96.         turtle.select(i)
  97.         local itemDetail = turtle.getItemDetail(i)
  98.         if itemDetail and itemDetail.count > 0 then
  99.             local displayNameToPrint = itemDetail.displayName or itemDetail.name or "UnknownItemInTurtle"
  100.             log("  Attempting to drop " .. itemDetail.count .. " of " .. displayNameToPrint .. " (Registry: " .. itemDetail.name .. ", Slot " .. i .. ") into IO chest.")
  101.             if turtle.drop() then
  102.                 log("    Dropped successfully.")
  103.                 table.insert(itemsDroppedDetails, itemDetail)
  104.             else
  105.                 log("    WARN: Failed to drop " .. displayNameToPrint .. " into IO chest from slot " .. i)
  106.             end
  107.         end
  108.     end
  109.     turtle.down()
  110.     if #itemsDroppedDetails == 0 then log("  No items were in turtle (slots 1-15) to return, or all drops failed.") return end
  111.     log("  Importing items from IO chest into ME system:")
  112.     for _, itemToImport in ipairs(itemsDroppedDetails) do
  113.         local displayNameToImport = itemToImport.displayName or itemToImport.name or "UnknownItemToImport"
  114.         local importFilter = {name=itemToImport.name, count=itemToImport.count}
  115.         if itemToImport.nbt then importFilter.nbt = itemToImport.nbt end
  116.         log("    Attempting to import " .. itemToImport.count .. " of " .. displayNameToImport)
  117.         local importedAmount, importError = bridge.importItem(importFilter, "up")
  118.         if importError then log("    ERROR importing " .. displayNameToImport .. ": " .. importError)
  119.         elseif importedAmount > 0 then log("    Successfully imported " .. importedAmount .. " of " .. displayNameToImport)
  120.             if importedAmount < itemToImport.count then log("    WARN: Imported " .. importedAmount .. "/" .. itemToImport.count) end
  121.         else log("    Imported 0 of " .. displayNameToImport .. ". (No error, 0 moved)") end
  122.         os.sleep(0.2)
  123.     end
  124.     log("Finished returning items.")
  125. end
  126.  
  127. local function getItemsFromME(bridge, itemsToGet)
  128.     if not bridge then log("ERROR (getItems): ME Bridge not provided!") return {} end
  129.     log("Requesting items from ME system (at home):") local successfullyFetched = {}
  130.     for _, itemReq in ipairs(itemsToGet) do
  131.         local itemName = "" ; local itemDisplayName = ""
  132.         if type(itemReq.item) == "table" then itemName = itemReq.item.name or "UnknownItemRegistry"
  133.         elseif type(itemReq.item) == "string" then itemName = itemReq.item else itemName = "InvalidItemRegistry" end
  134.         if type(itemReq.displayName) == "table" then itemDisplayName = itemReq.displayName.name or itemReq.displayName.displayName or itemName
  135.         elseif type(itemReq.displayName) == "string" then itemDisplayName = itemReq.displayName else itemDisplayName = itemName end
  136.         local neededCount = itemReq.needs
  137.         if neededCount == nil or type(neededCount) ~= "number" or neededCount <= 0 then
  138.             log("  Skipping item " .. itemDisplayName .. " for ME fetch (invalid neededCount: " .. tostring(neededCount) .. ")")
  139.             goto continue_me_req_v32
  140.         end
  141.         local emptySlot = findEmptySlot() if not emptySlot then log("  No empty slot. Skipping ME requests.") break end
  142.         turtle.select(emptySlot)
  143.         local exportFilter = {name=itemName, count=neededCount}
  144.         if itemReq.nbt then exportFilter.nbt = itemReq.nbt end
  145.         local exportedAmount, exportReason = bridge.exportItem(exportFilter, "up")
  146.         if not exportedAmount or exportedAmount == 0 then log("  Export failed for " .. itemDisplayName .. ": " .. (exportReason or "0 items")) goto continue_me_req_v32 end
  147.         turtle.up() local itemActuallySucked = 0 turtle.select(emptySlot)
  148.         for _ = 1, exportedAmount do if turtle.suck(1) then itemActuallySucked = itemActuallySucked + 1 else break end end
  149.         turtle.down()
  150.         if itemActuallySucked > 0 then
  151.             local fetchedDetail = turtle.getItemDetail(emptySlot)
  152.             table.insert(successfullyFetched, { slot = emptySlot, name = fetchedDetail.name, displayName = fetchedDetail.displayName, count = itemActuallySucked, nbt = fetchedDetail.nbt })
  153.             local fetchedDisplayName = fetchedDetail.displayName or fetchedDetail.name or "UnknownFetchedItem"
  154.             if itemActuallySucked < neededCount then log("  WARN: Sucked " ..itemActuallySucked.."/"..neededCount .. " of " .. fetchedDisplayName)
  155.             else log("  Sucked " ..itemActuallySucked .. " of " .. fetchedDisplayName) end
  156.         elseif exportedAmount > 0 then log("  Exported " .. exportedAmount .. " but failed to suck " .. itemDisplayName) end
  157.         ::continue_me_req_v32::
  158.     end
  159.     consolidateInventory() return successfullyFetched
  160. end
  161.  
  162. local function deliverItems(deliveryWarpPointName, itemsExpectedToDeliver)
  163.     log("Attempting delivery to " .. deliveryWarpPointName)
  164.     log("Delivering items by dropping down:")
  165.     local allItemsFullyDelivered = true
  166.     local remainingToDeliver = {}
  167.     for _, itemDetail in ipairs(itemsExpectedToDeliver) do
  168.         table.insert(remainingToDeliver, { name = itemDetail.name, displayName = itemDetail.displayName or itemDetail.name or "UnknownItem", nbt = itemDetail.nbt, count = itemDetail.count })
  169.     end
  170.     local deliveryAttempted = false
  171.     for deliveryPass = 1, 2 do
  172.         if deliveryAttempted and deliveryPass == 2 then
  173.             local anyLeft = false; for _, item in ipairs(remainingToDeliver) do if item.count > 0 then anyLeft = true break end end
  174.             if not anyLeft then break end -- All delivered, no need for 2nd pass
  175.             log("    Some items remain. Trying alternative drop spot...")
  176.             turtle.turnLeft() turtle.forward()
  177.         elseif deliveryPass == 2 then break end
  178.         deliveryAttempted = true
  179.         for i = 1, #remainingToDeliver do
  180.             local wantedItem = remainingToDeliver[i]
  181.             if wantedItem.count > 0 then
  182.                 local wantedItemDisplayName = wantedItem.displayName
  183.                 log("  Seeking to deliver " .. wantedItem.count .. " of " .. wantedItemDisplayName)
  184.                 for slot = 1, 15 do
  185.                     turtle.select(slot)
  186.                     local itemInSlot = turtle.getItemDetail(slot)
  187.                     if itemInSlot and itemInSlot.name == wantedItem.name and (itemInSlot.nbt == wantedItem.nbt) then
  188.                         local amountToDrop = math.min(itemInSlot.count, wantedItem.count)
  189.                         if amountToDrop > 0 then
  190.                             log("    Found " .. itemInSlot.count .. " of " .. wantedItemDisplayName .. " in slot " .. slot .. ". Attempting to drop " .. amountToDrop)
  191.                             if turtle.dropDown(amountToDrop) then
  192.                                 log("      Dropped " .. amountToDrop .. " successfully.")
  193.                                 wantedItem.count = wantedItem.count - amountToDrop
  194.                                 if wantedItem.count == 0 then log("      Requirement for " .. wantedItemDisplayName .. " met.") break end
  195.                             else
  196.                                 log("      DropDown failed for " .. amountToDrop .. " of " .. wantedItemDisplayName .. " from slot " .. slot .. ".")
  197.                                 allItemsFullyDelivered = false
  198.                             end
  199.                         end
  200.                     end
  201.                 end
  202.             end
  203.         end
  204.         local allMetThisPass = true
  205.         for _, item in ipairs(remainingToDeliver) do if item.count > 0 then allMetThisPass = false break end end
  206.         if allMetThisPass then log("    All item requirements met in this delivery pass.") break end
  207.         if deliveryPass == 2 then turtle.back() turtle.turnRight() end
  208.     end
  209.     for _, item in ipairs(remainingToDeliver) do
  210.         if item.count > 0 then log("  WARN: Could not deliver " .. item.count .. " of " .. item.displayName .. ".") allItemsFullyDelivered = false end
  211.     end
  212.     if allItemsFullyDelivered then log("All requested items appear fully delivered to " .. deliveryWarpPointName)
  213.     else log("Some items were not fully delivered to " .. deliveryWarpPointName) end
  214.     log("Waiting 10 seconds at builder's hut: " .. deliveryWarpPointName)
  215.     os.sleep(10)
  216.     return allItemsFullyDelivered
  217. end
  218.  
  219. function prepareAtHomeBase()
  220.     log("Ensuring turtle is prepared at home base...")
  221.     if not warpTo(HOME_WARP_POINT) then log("CRITICAL: Cannot reach " .. HOME_WARP_POINT) return false, nil end
  222.     local bridge = peripheral.find(ME_BRIDGE_NAME)
  223.     if not bridge then log("ERROR: ME Bridge ('"..ME_BRIDGE_NAME.."') not found at " .. HOME_WARP_POINT .. "!") return false, nil end
  224.     log("ME Bridge found at home base.")
  225.     if not ensureFuel(true) then log("CRITICAL: Failed to ensure fuel at " .. HOME_WARP_POINT .. ".") return false, bridge end
  226.     returnUnusedItemsToME(bridge)
  227.     log("Turtle is at home and prepared.")
  228.     return true, bridge
  229. end
  230.  
  231. -- MAIN SCRIPT EXECUTION
  232. log("Builder Bot v3.2 Initializing...")
  233. if not initialPeripheralCheck() then log("Essential End Automata not found. Exiting.") return end
  234. local resLogClearFile = fs.open(DETAILED_RESOURCE_LOG_FILE, "w")
  235. if resLogClearFile then resLogClearFile.close() log("Cleared " .. DETAILED_RESOURCE_LOG_FILE) end
  236. local homePrepared, currentBridge = prepareAtHomeBase()
  237. if not homePrepared then
  238.     log("Initial home preparation failed. Waiting 5 minutes...") os.sleep(300)
  239.     homePrepared, currentBridge = prepareAtHomeBase()
  240.     if not homePrepared then log("Second home prep failed. Exiting.") return end
  241. end
  242. log("Successfully initialized. Starting main loop.")
  243.  
  244. while true do
  245.     log("\n--- Starting New Cycle ---")
  246.     local workOrderFoundAndTargeted = false ; local actualDeliveryWarpPoint = nil
  247.     local originalTargetBuildingName = nil ; local currentWorkOrderItems = nil
  248.     local detailedResFile = nil
  249.  
  250.     log("Going to colony for work orders...")
  251.     if not ensureFuel(false) then log("Warn: Low fuel before leaving home.") end
  252.     if not warpTo(COLONY_WARP_POINT) then
  253.         log("Failed to reach colony.") ; homePrepared, currentBridge = prepareAtHomeBase()
  254.         if not homePrepared then log("CRIT: No recovery. Wait 5m...") os.sleep(300) end
  255.         goto continue_main_loop_v32
  256.     end
  257.     local colony = peripheral.find(COLONY_INTEGRATOR_NAME)
  258.     if not colony then
  259.         log("ERROR: CI not found at "..COLONY_WARP_POINT) ; homePrepared, currentBridge = prepareAtHomeBase()
  260.         if not homePrepared then os.sleep(300) end
  261.         goto continue_main_loop_v32
  262.     end
  263.     log("CI found. Checking work orders...")
  264.     local workOrders = colony.getWorkOrders()
  265.    
  266.     -- ***** V3.2 MODIFICATION: Collect suitable WOs and pick one randomly *****
  267.     local suitableWorkOrders = {}
  268.  
  269.     if not workOrders or #workOrders == 0 then log("No active work orders.")
  270.     else
  271.         log("Found " .. #workOrders .. " WOs. Evaluating...")
  272.         for _, wo in ipairs(workOrders) do
  273.             if not wo or wo.id == nil then log("  WARN: Invalid WO entry.") goto continue_eval_wo_loop_v32 end
  274.             log("\n  Evaluating WO ID: " .. wo.id .. " for: " .. (wo.buildingName or "N/A"))
  275.             detailedResFile = fs.open(DETAILED_RESOURCE_LOG_FILE, "a")
  276.             if detailedResFile then detailedResFile.write("\n--- Eval WO ID: " .. wo.id .. " for: " .. (wo.buildingName or "N/A") .. ", Type: " .. (wo.workOrderType or "N/A") .. " ---\n") end
  277.             local itemsNeededForThisOrder = {} ; local needsSomething = false
  278.             local resources = colony.getWorkOrderResources(wo.id)
  279.             if resources then
  280.                 if #resources > 0 then
  281.                     local headerMsg = "    Found " .. #resources .. " resource entries:"
  282.                     if detailedResFile then detailedResFile.write(headerMsg .. "\n") else log(headerMsg) end
  283.                     for resIdx, res in ipairs(resources) do
  284.                         local sResItem = "UnknownItemRegistry"
  285.                         if type(res.item) == "table" then sResItem = res.item.name or (res.item.displayName or "UnknownInTable") elseif type(res.item) == "string" then sResItem = res.item end
  286.                         local sResDisplayName = sResItem
  287.                         if type(res.displayName) == "table" then sResDisplayName = res.displayName.name or (res.displayName.displayName or sResItem) elseif type(res.displayName) == "string" then sResDisplayName = res.displayName end
  288.                         local res_needs_val = res.needs ; local resAvailable = res.available
  289.                         local resStatus = res.status ; local resDelivering = res.delivering
  290.                         local logEntry = ("      Res #" .. resIdx .. ": '" .. sResDisplayName .. "' (Reg: " .. sResItem .. ")\n") ..
  291.                                        ("        Raw needs: " .. tostring(res_needs_val) .. " (Type: " .. type(res_needs_val) .. ")\n") ..
  292.                                        ("        Raw Avail: " .. tostring(resAvailable) .. " (Type: " .. type(resAvailable) .. ")\n") ..
  293.                                        ("        Raw Status: " .. tostring(resStatus) .. " (Type: " .. type(resStatus) .. ")\n") ..
  294.                                        ("        Raw Deliver: " .. tostring(resDelivering) .. " (Type: " .. type(resDelivering) .. ")\n")
  295.                         if detailedResFile then detailedResFile.write(logEntry) else log(logEntry) end
  296.                         if res_needs_val == nil then
  297.                             local skipMsg = "        SKIP: 'needs' is nil."
  298.                             if detailedResFile then detailedResFile.write(skipMsg .. "\n") else log(skipMsg) end
  299.                             goto continue_res_loop_v32
  300.                         end
  301.                         local isStillNeeded = false ; local evalMsg = ""
  302.                         if type(res_needs_val) == "number" and res_needs_val > 0 then
  303.                             if resAvailable == false then isStillNeeded = true evalMsg = "        EVAL: Need (avail false).\n"
  304.                             elseif resStatus and string.lower(resStatus) ~= "met" and string.lower(resStatus) ~= "fulfilled" and string.lower(resStatus) ~= "not_needed" then
  305.                                 isStillNeeded = true evalMsg = "        EVAL: Need (status '"..tostring(resStatus).."').\n"
  306.                             else evalMsg = "        EVAL: Not Need (avail true or status met/fulfilled/not_needed). Needs: "..tostring(res_needs_val)..", Avail: "..tostring(resAvailable)..", Status: "..tostring(resStatus).."\n" end
  307.                         else evalMsg = "        EVAL: Not Need (needs not >0 or not num). Needs: "..tostring(res_needs_val).."\n" end
  308.                         if detailedResFile then detailedResFile.write(evalMsg) else log(evalMsg) end
  309.                         if isStillNeeded then
  310.                             local actionMsg = "        ACTION: Add " .. res_needs_val .. " of " .. sResDisplayName .. " to list.\n"
  311.                             if detailedResFile then detailedResFile.write(actionMsg) else log(actionMsg) end
  312.                             table.insert(itemsNeededForThisOrder, {item = sResItem, displayName = sResDisplayName, needs = res_needs_val, nbt = res.nbt})
  313.                             needsSomething = true
  314.                         end
  315.                         ::continue_res_loop_v32::
  316.                     end
  317.                 else
  318.                     local noResMsg = "    WO " .. wo.id .. " no resource entries."
  319.                     if detailedResFile then detailedResFile.write(noResMsg .. "\n") else log(noResMsg) end
  320.                 end
  321.             else
  322.                 local failGetResMsg = "  WARN: Failed to get resources for WO " .. wo.id
  323.                 if detailedResFile then detailedResFile.write(failGetResMsg .. "\n") else log(failGetResMsg) end
  324.             end
  325.             if detailedResFile then detailedResFile.close() detailedResFile = nil end
  326.            
  327.             if needsSomething then
  328.                 -- Determine warp point for this suitable WO
  329.                 local tempDeliveryWarpPoint = nil
  330.                 if wo.buildingName and not string.match(string.lower(wo.buildingName), "com.minecolonies.building.") and not string.match(string.lower(wo.buildingName), "minecolonies:") then
  331.                     tempDeliveryWarpPoint = wo.buildingName .. NAMED_BUILDING_STORAGE_SUFFIX
  332.                 elseif wo.builder and wo.builder.x ~= nil then tempDeliveryWarpPoint = wo.builder.x .. "," .. wo.builder.y .. "," .. wo.builder.z
  333.                 end
  334.  
  335.                 if tempDeliveryWarpPoint then
  336.                     log("  WO ID " .. wo.id .. " for " .. (wo.buildingName or "N/A") .. " is suitable and has a valid warp point.")
  337.                     table.insert(suitableWorkOrders, {
  338.                         woData = wo,
  339.                         items = itemsNeededForThisOrder,
  340.                         warpPoint = tempDeliveryWarpPoint
  341.                     })
  342.                 else
  343.                     log("  WO ID " .. wo.id .. " for " .. (wo.buildingName or "N/A") .. " needs items, but no valid warp point determined. Skipping as suitable.")
  344.                 end
  345.             else log("  WO " .. wo.id .. " no items needed based on eval.") end
  346.             ::continue_eval_wo_loop_v32::
  347.         end
  348.     end
  349.     colony = nil
  350.  
  351.     if #suitableWorkOrders > 0 then
  352.         local randomIndex = math.random(1, #suitableWorkOrders)
  353.         local chosenTask = suitableWorkOrders[randomIndex]
  354.        
  355.         log("Found " .. #suitableWorkOrders .. " suitable work order(s). Randomly selected task for WO ID: " .. chosenTask.woData.id)
  356.         originalTargetBuildingName = chosenTask.woData.buildingName or "Unknown Target"
  357.         currentWorkOrderItems = chosenTask.items
  358.         actualDeliveryWarpPoint = chosenTask.warpPoint
  359.         workOrderFoundAndTargeted = true
  360.     else
  361.         log("No suitable work orders found this cycle that require items and have valid warp points.")
  362.     end
  363.    
  364.     if not workOrderFoundAndTargeted then log("No suitable WOs at colony.") log("Wait 10s at colony...") os.sleep(10) end
  365.     -- ***** END V3.2 MODIFICATION *****
  366.  
  367.     if workOrderFoundAndTargeted and actualDeliveryWarpPoint and currentWorkOrderItems then
  368.         log("WO targeted. Home for items: " .. originalTargetBuildingName)
  369.         if not warpTo(HOME_WARP_POINT) then log("Failed warp home.") goto continue_main_loop_v32 end
  370.         currentBridge = peripheral.find(ME_BRIDGE_NAME)
  371.         if not currentBridge then log("ERROR: ME Bridge missing at home!") goto continue_main_loop_v32 end
  372.         if not ensureFuel(true) then log("Fuel fail home.") goto continue_main_loop_v32 end
  373.         local fetchedItems = getItemsFromME(currentBridge, currentWorkOrderItems)
  374.         -- Even if fetchedItems is empty or partial, we proceed to deliver what we got (if anything)
  375.         if not fetchedItems then fetchedItems = {} end -- Ensure it's a table for deliverItems
  376.  
  377.         log("ME fetch attempt complete. Fetched " .. #fetchedItems .. " types of items. Delivering to " .. originalTargetBuildingName .. " via " .. actualDeliveryWarpPoint)
  378.         if not ensureFuel(false) then log("Warn: Low fuel pre-delivery.") end
  379.         if warpTo(actualDeliveryWarpPoint) then
  380.             if #fetchedItems > 0 then -- Only deliver if we actually got something
  381.                 deliverItems(actualDeliveryWarpPoint, fetchedItems)
  382.             else
  383.                 log("No items were successfully fetched from ME. Nothing to deliver for this WO.")
  384.                 log("Waiting 10 seconds at builder's hut (even with no items, to prevent immediate re-check of same empty WO): " .. actualDeliveryWarpPoint)
  385.                 os.sleep(10)
  386.             end
  387.         else log("Failed warp to " .. actualDeliveryWarpPoint .. ". Items (if any) remain.") end
  388.         log("Delivery attempt for " .. originalTargetBuildingName .. " done.")
  389.     else log("No WO targeted this cycle. Home if not there.") end
  390.     log("Cycle end. Prep for next.")
  391.     homePrepared, currentBridge = prepareAtHomeBase()
  392.     if not homePrepared then log("Home prep fail. Wait 5m...") os.sleep(300) homePrepared, currentBridge = prepareAtHomeBase()
  393.         if not homePrepared then log("2nd home prep fail. Exit.") return end
  394.     end
  395.     log("Wait 10s before next cycle...") os.sleep(10)
  396.     ::continue_main_loop_v32::
  397. end
Add Comment
Please, Sign In to add comment