Myros27

villageBot v1.5

May 25th, 2025 (edited)
31
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 70.60 KB | None | 0 0
  1. -- VillageBot v1.7
  2.  
  3. --#region STRICT TOP-LEVEL CONFIGURATION AND LOGGER GLOBALS
  4. local LOG_LEVELS = { DEBUG = 1, INFO = 2, WARN = 3, ERROR = 4, FATAL = 5 }
  5. local DEBUG_LOGGING_ENABLED = true
  6. local LOG_FILE_NAME_CONST = "villagebot.log"
  7.  
  8. local current_log_level_val
  9. if DEBUG_LOGGING_ENABLED then
  10.     current_log_level_val = (LOG_LEVELS and LOG_LEVELS.DEBUG) or 1
  11. else
  12.     current_log_level_val = (LOG_LEVELS and LOG_LEVELS.INFO) or 2
  13. end
  14.  
  15. local BOT_DATA_FILE = "villagebot_data.json"
  16. local ME_BRIDGE_NAME = "advancedperipherals:me_bridge"
  17. local REDSTONE_BLOCK_NAME = "minecraft:redstone_block"
  18.  
  19. local AUTOMATA_PERIPHERAL_NAME = "endAutomata"
  20. local ME_BRIDGE_PERIPHERAL_NAME = "meBridge"
  21. local COLONY_INTEGRATOR_PERIPHERAL_NAME = "colonyIntegrator"
  22.  
  23. local FUEL_SLOT = 16
  24. local COAL_BLOCK_NAME = "minecraft:coal_block"
  25. local REFUEL_BELOW_PERCENTAGE = 0.90
  26. local MAX_REDSTONE_BLOCK_RETRIES = 10
  27. local REDSTONE_BLOCK_RETRY_WAIT = 5
  28. local REFUEL_BARREL_ACCESS_POS = { x = -114, y = 65, z = 221, dir = 3 }
  29. --#endregion
  30.  
  31. --#region Global State
  32. local current_pos = { x = nil, y = nil, z = nil }; local current_dir = nil
  33. local roboSlot = nil; local home_pos = { x = nil, y = nil, z = nil, dir = nil }
  34. local pAutomata = nil; local pMeBridge = nil; local pColonyIntegrator = nil
  35. local DIR_VECTORS = { [0]={x=0,z=1},[1]={x=1,z=0},[2]={x=0,z=-1},[3]={x=-1,z=0} }
  36. local DIR_NAMES = {[0]="North",[1]="East",[2]="South",[3]="West"}
  37. local mounted_peripherals = {}; local undeliveredItemsBuffer = {}
  38. --#endregion
  39.  
  40. --#region Logger Function
  41. local function botLog(level, message)
  42.     local message_str = message
  43.     if type(message) ~= "string" and type(message) ~= "number" then
  44.         message_str = textutils.serialize(message, {compact=true})
  45.         if message == nil then message_str = "nil_message_passed_to_botLog" end
  46.     else message_str = tostring(message) end
  47.  
  48.     local level_display_name = "LVL?"
  49.     if LOG_LEVELS and type(LOG_LEVELS) == "table" then
  50.         for name_key, lVal_val in pairs(LOG_LEVELS) do if lVal_val == level then level_display_name = name_key; break end end
  51.     else print("Console: botLog - LOG_LEVELS is nil or not a table! Cannot determine level name.") end
  52.    
  53.     print(string.format("[%s] [%s] %s", os.date("%Y-%m-%d %H:%M:%S"), level_display_name, message_str))
  54.  
  55.     local can_write_to_file = false
  56.     if LOG_LEVELS and type(LOG_LEVELS) == "table" and current_log_level_val and LOG_FILE_NAME_CONST and type(LOG_FILE_NAME_CONST) == "string" then
  57.         if DEBUG_LOGGING_ENABLED or level >= (LOG_LEVELS.WARN or 3) then
  58.             if level >= current_log_level_val then
  59.                 can_write_to_file = true
  60.             end
  61.         end
  62.     end
  63.  
  64.     if can_write_to_file then
  65.         local levelNameInFile = "UNK_LVL"
  66.         if LOG_LEVELS then for name, lVal in pairs(LOG_LEVELS) do if lVal == level then levelNameInFile = name; break end end end
  67.         local logMessageToFile = string.format("[%s] [%s] %s", os.date("%Y-%m-%d %H:%M:%S"), levelNameInFile, message_str)
  68.         local f, err = fs.open(LOG_FILE_NAME_CONST, "a")
  69.         if f then
  70.             f.write(logMessageToFile .. "\n"); f.close()
  71.         else
  72.             print("CONSOLE: LOG FILE OPEN ERROR for '"..LOG_FILE_NAME_CONST.."' (in botLog): " .. tostring(err))
  73.         end
  74.     elseif DEBUG_LOGGING_ENABLED then
  75.         if not LOG_LEVELS or type(LOG_LEVELS) ~= "table" then print("Console: botLog - Cannot write to file, LOG_LEVELS invalid.") end
  76.         if not current_log_level_val then print("Console: botLog - Cannot write to file, current_log_level_val invalid.") end
  77.         if not LOG_FILE_NAME_CONST or type(LOG_FILE_NAME_CONST) ~= "string" then print("Console: botLog - Cannot write to file, LOG_FILE_NAME_CONST invalid.") end
  78.     end
  79. end
  80. --#endregion
  81.  
  82. --#region Peripheral Management
  83. function findPeripheral(name,type_arg,required)
  84.     if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"FindP: "..name.." type '"..tostring(type_arg).."'")end
  85.     if type(type_arg) ~= "string" then
  86.         if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "FindP: Invalid type arg. Expected string, got " .. type(type_arg)) end
  87.         return nil
  88.     end
  89.     local p=peripheral.find(type_arg)
  90.     if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"FindP: peripheral.find Result for '"..type_arg.."': "..tostring(p))end
  91.     if p then
  92.         if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"Found peripheral: "..name) end
  93.         mounted_peripherals[name]=p
  94.         return p
  95.     else
  96.         local m="Peripheral NOT FOUND: "..name.." (type: " .. type_arg .. ")"
  97.         if required then
  98.             if LOG_LEVELS then botLog(LOG_LEVELS.FATAL,m.." - REQUIRED!") end
  99.         else
  100.             if LOG_LEVELS then botLog(LOG_LEVELS.WARN,m) end
  101.         end
  102.         return nil
  103.     end
  104. end
  105.  
  106. function initCorePeripherals()
  107.     print("Console: CHKPT - Enter initCorePeripherals")
  108.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"initCoreP: Start") end
  109.     pAutomata=findPeripheral("Automata",AUTOMATA_PERIPHERAL_NAME,true)
  110.    
  111.     if not pAutomata then
  112.         if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"initCoreP: Automata peripheral missing. Cannot proceed.") end
  113.         print("Console: CHKPT - initCorePeripherals FAIL (Automata missing)")
  114.         return false
  115.     end
  116.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"initCoreP: Core peripherals OK.") end
  117.     print("Console: CHKPT - initCorePeripherals OK")
  118.     return true
  119. end
  120.  
  121. function findHomeLocationPeripherals()
  122.     print("Console: CHKPT - Enter findHomeLocationPeripherals")
  123.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"findHomeLocP: Start (should be at home and oriented)") end
  124.  
  125.     if not (home_pos and home_pos.x and current_pos and current_pos.x == home_pos.x and current_pos.y == home_pos.y and current_pos.z == home_pos.z) then
  126.         if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"findHomeLocP: Called when not at stored home coordinates.") end
  127.     end
  128.     if not (home_pos and home_pos.dir ~= nil and current_dir == home_pos.dir) then
  129.         if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"findHomeLocP: Not facing home direction (".. (home_pos and DIR_NAMES[home_pos.dir] or "N/A")..").") end
  130.         if home_pos and home_pos.dir ~= nil then
  131.             if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "findHomeLocP: Attempting re-orientation to home dir: " .. DIR_NAMES[home_pos.dir]) end
  132.             if not ml.turnToDir(home_pos.dir) then
  133.                 if LOG_LEVELS then botLog(LOG_LEVELS.WARN, "findHomeLocP: Re-orientation failed.") end
  134.             end
  135.         else
  136.              if LOG_LEVELS then botLog(LOG_LEVELS.WARN, "findHomeLocP: home_pos.dir is nil, cannot re-orient.") end
  137.         end
  138.     end
  139.  
  140.     if not pMeBridge then
  141.         pMeBridge=findPeripheral("ME Bridge",ME_BRIDGE_PERIPHERAL_NAME,true)
  142.     elseif DEBUG_LOGGING_ENABLED and LOG_LEVELS then
  143.         botLog(LOG_LEVELS.DEBUG, "findHomeLocP: pMeBridge already attached.")
  144.     end
  145.  
  146.     if not pColonyIntegrator then
  147.         pColonyIntegrator=findPeripheral("Colony Integrator",COLONY_INTEGRATOR_PERIPHERAL_NAME,true)
  148.     elseif DEBUG_LOGGING_ENABLED and LOG_LEVELS then
  149.         botLog(LOG_LEVELS.DEBUG, "findHomeLocP: pColonyIntegrator already attached.")
  150.     end
  151.  
  152.  
  153.     if not (pMeBridge and pColonyIntegrator)then
  154.         if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"findHomeLocP: ME Bridge or Colony Integrator missing after checks.") end
  155.         print("Console: CHKPT - findHomeLocationPeripherals FAIL")
  156.         return false
  157.     end
  158.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"findHomeLocP: Home location peripherals OK.") end
  159.     print("Console: CHKPT - findHomeLocationPeripherals OK")
  160.     return true
  161. end
  162. --#endregion
  163.  
  164. --#region JSON Data Handling
  165. function saveData() if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"saveData: Attempt")end; if roboSlot==nil or not home_pos or home_pos.x==nil or not current_pos or current_pos.x==nil or current_dir==nil then if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"saveData: Skip, incomplete data.")end; return false end; local d={roboSlot=roboSlot,home_pos=home_pos,current_pos=current_pos,current_dir=current_dir}; if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"saveData: Data: "..textutils.serialize(d))end; local s,e=textutils.serialiseJSON(d); if not s then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"saveData: Serialize fail: "..tostring(e))end; return false end; local f,fe=fs.open(BOT_DATA_FILE,"w"); if not f then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"saveData: Open file fail: "..tostring(fe))end; return false end; f.write(s);f.close(); if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"Bot data saved.")end; return true end
  166. function loadData() print("Console: CHKPT - Enter loadData"); if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"loadData: Attempt from '"..BOT_DATA_FILE.."'")end; if not fs.exists(BOT_DATA_FILE)then if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"loadData: File not found.")end; print("Console: CHKPT - loadData: No file"); return false end; local f,fe=fs.open(BOT_DATA_FILE,"r"); if not f then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"loadData: Open file fail: "..tostring(fe))end; print("Console: CHKPT - loadData: Open fail"); return false end; local s=f.readAll();f.close(); if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"loadData: File content: "..s)end; local sc,d=pcall(textutils.unserialiseJSON,s); if not sc or type(d)~="table"then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"loadData: Parse fail. SC:"..tostring(sc)..",D:"..tostring(d))end; print("Console: CHKPT - loadData: Parse JSON fail"); return false end; if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"loadData: Parsed: "..textutils.serialize(d))end; if d.roboSlot and d.home_pos and d.home_pos.x~=nil and d.home_pos.y~=nil and d.home_pos.z~=nil and d.home_pos.dir~=nil and d.current_pos and d.current_pos.x~=nil and d.current_pos.y~=nil and d.current_pos.z~=nil and d.current_dir~=nil then roboSlot=d.roboSlot;home_pos=d.home_pos;current_pos=d.current_pos;current_dir=d.current_dir; if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"Bot data loaded.")end; print("Console: CHKPT - loadData: OK"); return true else if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"loadData: Incomplete/malformed data in JSON.")end; print("Console: CHKPT - loadData: Malformed data"); return false end end
  167. --#endregion
  168.  
  169. --#region Movement Library (ml)
  170. ml = {}
  171. function ml.setPos(x,y,z,dirNum) current_pos={x=x,y=y,z=z}; current_dir=dirNum; if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, string.format("ml.setPos: X%sY%sZ%sD%s (%s)",x,y,z,dirNum,DIR_NAMES[dirNum])) end; saveData() end
  172. function ml.inspect() if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "ml.inspect: Called") end; local s,d=turtle.inspect(); if s and d then if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.inspect: OK, Block: "..d.name) end; return d elseif s and not d then if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.inspect: OK, Empty.")end; return nil else if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"ml.inspect: Fail: " .. tostring(d))end; return nil end end
  173. function ml.inspectUp() if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "ml.inspectUp: Called") end; local s,d=turtle.inspectUp(); if s and d then if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.inspectUp: OK, Block: "..d.name)end; return d else if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.inspectUp: OK, Empty/fail.")end; return nil end end
  174. function ml.inspectDown() if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "ml.inspectDown: Called") end; local s,d=turtle.inspectDown(); if s and d then if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.inspectDown: OK, Block: "..d.name)end; return d else if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.inspectDown: OK, Empty/fail.")end; return nil end end
  175. local function genericMove(moveFunc,actionName,updatesPos,updatesDir) local s,e=pcall(moveFunc); if s then if LOG_LEVELS then botLog(LOG_LEVELS.INFO,actionName.." OK. Fuel:"..turtle.getFuelLevel())end; if updatesPos and current_pos and current_pos.x~=nil and current_dir~=nil then local oX,oY,oZ=current_pos.x,current_pos.y,current_pos.z; if actionName=="forward"then current_pos.x=current_pos.x+DIR_VECTORS[current_dir].x;current_pos.z=current_pos.z+DIR_VECTORS[current_dir].z elseif actionName=="back"then current_pos.x=current_pos.x-DIR_VECTORS[current_dir].x;current_pos.z=current_pos.z-DIR_VECTORS[current_dir].z elseif actionName=="up"then current_pos.y=current_pos.y+1 elseif actionName=="down"then current_pos.y=current_pos.y-1 end; if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"gMove Pos "..oX..","..oY..","..oZ.." -> "..current_pos.x..","..current_pos.y..","..current_pos.z)end; end; if updatesDir and current_dir~=nil then local oD=current_dir; if actionName=="turnLeft"then current_dir=(current_dir-1+4)%4 elseif actionName=="turnRight"then current_dir=(current_dir+1)%4 end; if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"gMove Dir "..(oD and DIR_NAMES[oD] or "nil").." -> "..(current_dir and DIR_NAMES[current_dir] or "nil"))end; end; if updatesPos or updatesDir then saveData() end; return true else if LOG_LEVELS then botLog(LOG_LEVELS.WARN,actionName.." FAIL: "..tostring(e))end; return false end end
  176. function ml.forward() return genericMove(turtle.forward,"forward",true,false) end
  177. function ml.back() return genericMove(turtle.back,"back",true,false) end
  178. function ml.up() return genericMove(turtle.up,"up",true,false) end
  179. function ml.down() return genericMove(turtle.down,"down",true,false) end
  180. function ml.turnLeft() return genericMove(turtle.turnLeft,"turnLeft",false,true) end
  181. function ml.turnRight() return genericMove(turtle.turnRight,"turnRight",false,true) end
  182. function ml.select(slot) if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.select: Slot "..slot) end; turtle.select(slot); return true end
  183. function ml.getItemCount(slot) local c=turtle.getItemCount(slot); if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.getItemCount: Slt "..slot.." has "..c)end; return c end
  184. function ml.getItemDetail(slot) local d=turtle.getItemDetail(slot); if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.getItemDetail: Slt "..slot.." detail: "..(d and textutils.serialize(d, {compact=true}) or "nil"))end; return d end
  185. function ml.getFuelLevel() local l=turtle.getFuelLevel(); if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.getFuelLevel: "..l)end; return l end
  186. function ml.getFuelLimit() local l=turtle.getFuelLimit(); if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.getFuelLimit: "..l)end; return l end
  187. function ml.drop(count) local sl=turtle.getSelectedSlot();local dt=ml.getItemDetail(sl);local iN=(dt and dt.name or "unk item");local aC=count or ml.getItemCount(sl);if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.drop: Try drop "..aC.." "..iN.." from slt "..sl)end;if aC==0 then return true end;local sc;if count then sc=turtle.drop(count)else sc=turtle.drop()end;if sc then if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"ml.drop: OK from slt "..sl)end else if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"ml.drop: FAIL from slt "..sl)end end;return sc end
  188. function ml.suck(count) local sl=turtle.getSelectedSlot();local aC=count or 1;if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.suck: Try suck "..aC.." into slt "..sl)end;local sc;if count then sc=turtle.suck(count)else sc=turtle.suck()end;if sc then if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"ml.suck: OK into slt "..sl .. " (req: "..aC..")")end else if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"ml.suck: FAIL into slt "..sl)end end;return sc end
  189. function ml.refuel() ml.select(FUEL_SLOT);local it=ml.getItemDetail(FUEL_SLOT);if not it or it.name ~= COAL_BLOCK_NAME then if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"ml.refuel: Fail: No/wrong fuel. Need '"..COAL_BLOCK_NAME.."', Has: "..(it and it.name or "nil"))end;return false end;if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.refuel: Attempt from slt "..FUEL_SLOT.." with "..it.name)end;local iF=ml.getFuelLevel();local s=turtle.refuel();if s then if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"ml.refuel: OK. Fuel: "..ml.getFuelLevel().." (was "..iF..")")end else if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"ml.refuel: turtle.refuel() fail.")end end;return s end
  190. function ml.turnToDir(targetDirNum) if current_dir==nil then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"ml.turnToDir: current_dir is nil.")end; return false end;if targetDirNum<0 or targetDirNum>3 then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"ml.turnToDir: Invalid targetDir: "..targetDirNum)end; return false end;if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.turnToDir: From "..(DIR_NAMES[current_dir] or "nil").."("..current_dir..") to "..DIR_NAMES[targetDirNum].."("..targetDirNum..")")end;if current_dir==targetDirNum then return true end;local df=(targetDirNum-current_dir+4)%4;if df==1 then return ml.turnRight()elseif df==2 then return ml.turnRight() and ml.turnRight()elseif df==3 then return ml.turnLeft()end;return false end
  191. function ml.moveTo(tx,ty,tz,tdir_opt) print(string.format("Console: ml.moveTo Start - Tgt X%sY%sZ%sD%s", tx, ty, tz, (tdir_opt and DIR_NAMES[tdir_opt] or "any"))); if LOG_LEVELS then botLog(LOG_LEVELS.INFO, string.format("ml.moveTo: Tgt X%sY%sZ%sD%s | Cur X%sY%sZ%sD%s",tx,ty,tz,(tdir_opt and DIR_NAMES[tdir_opt] or "any"), current_pos.x,current_pos.y,current_pos.z,(current_dir and DIR_NAMES[current_dir] or "nil")))end; local function att(aF,cnt,axisName)for i=1,cnt do if not aF()then return false end;if ml.getFuelLevel()<5 and ml.getFuelLimit()>0 then if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"ml.moveTo: Low fuel ("..ml.getFuelLevel()..")!")end end;sleep(0.05)end;return true end; if current_pos.y~=ty then if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.moveTo: Adj Y "..current_pos.y.."->"..ty)end; while current_pos.y<ty do if not ml.up()then if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"ml.moveTo: Blocked UP at Y="..current_pos.y.." to Y="..ty)end;return false end end;while current_pos.y>ty do if not ml.down()then if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"ml.moveTo: Blocked DOWN at Y="..current_pos.y.." to Y="..ty)end;return false end end;if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.moveTo: Y OK at "..current_pos.y)end end; if current_pos.x~=tx then if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.moveTo: Adj X "..current_pos.x.."->"..tx)end; if current_pos.x<tx then if not ml.turnToDir(1)then return false end;if not att(ml.forward,tx-current_pos.x,"East")then if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"ml.moveTo: Blocked EAST at X="..current_pos.x)end;return false end elseif current_pos.x>tx then if not ml.turnToDir(3)then return false end;if not att(ml.forward,current_pos.x-tx,"West")then if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"ml.moveTo: Blocked WEST at X="..current_pos.x)end;return false end end;if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.moveTo: X OK at "..current_pos.x)end end; if current_pos.z~=tz then if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.moveTo: Adj Z "..current_pos.z.."->"..tz)end; if current_pos.z<tz then if not ml.turnToDir(0)then return false end;if not att(ml.forward,tz-current_pos.z,"North")then if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"ml.moveTo: Blocked NORTH at Z="..current_pos.z)end;return false end elseif current_pos.z>tz then if not ml.turnToDir(2)then return false end;if not att(ml.forward,current_pos.z-tz,"South")then if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"ml.moveTo: Blocked SOUTH at Z="..current_pos.z)end;return false end end;if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.moveTo: Z OK at "..current_pos.z)end end; if tdir_opt~=nil and current_dir~=tdir_opt then if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.moveTo: Adj final dir to "..DIR_NAMES[tdir_opt])end; if not ml.turnToDir(tdir_opt)then return false end end; if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"ml.moveTo: Target vicinity. Final Pos: X:"..current_pos.x.." Y:"..current_pos.y.." Z:"..current_pos.z.." Dir:"..(current_dir and DIR_NAMES[current_dir] or "nil"))end; print(string.format("Console: ml.moveTo End - Cur X%sY%sZ%sD%s", current_pos.x, current_pos.y, current_pos.z, (current_dir and DIR_NAMES[current_dir] or "nil"))); return current_pos.x==tx and current_pos.y==ty and current_pos.z==tz and (tdir_opt == nil or current_dir == tdir_opt) end
  192. --#endregion
  193.  
  194. --#region Core Logic Functions
  195. function initializeBot()
  196.     print("Console: CHKPT - Enter initializeBot");
  197.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"initializeBot: Start")end;
  198.     if not pAutomata then if LOG_LEVELS then botLog(LOG_LEVELS.FATAL,"initializeBot: pAutomata nil!")end; print("Console: initializeBot - pAutomata nil, FAIL"); return false end;
  199.    
  200.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"initializeBot: Warp 'home'")end;
  201.     local ws,we=pcall(function()return pAutomata.warpToPoint("home")end);
  202.     if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"initializeBot: Warp pcall: SC="..tostring(ws)..", RES="..tostring(we))end;
  203.     if not ws or not we then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"initializeBot: Warp fail: SC="..tostring(ws)..", RES="..tostring(we))end; print("Console: initializeBot - Warp FAIL"); return false end;
  204.    
  205.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"initializeBot: Warp OK. At physical home.")end;
  206.     current_pos={x=nil,y=nil,z=nil};current_dir=nil;
  207.  
  208.     local me_bridge_peripheral_found = false
  209.     for i=1,4 do
  210.         if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "initializeBot: Try " .. i .. "/4 find ME Bridge ("..ME_BRIDGE_PERIPHERAL_NAME..").") end
  211.         pMeBridge = peripheral.find(ME_BRIDGE_PERIPHERAL_NAME)
  212.         if pMeBridge then
  213.             if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "initializeBot: ME Bridge peripheral (type '"..ME_BRIDGE_PERIPHERAL_NAME.."') found on try " .. i .. ".") end
  214.             mounted_peripherals["ME Bridge"] = pMeBridge
  215.             me_bridge_peripheral_found = true
  216.             break
  217.         end
  218.         if i < 4 then
  219.             if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "initializeBot: ME Bridge not found. Turning right.") end
  220.             if not turtle.turnRight() then
  221.                 if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "initializeBot: turtle.turnRight() failed during ME Bridge search.") end
  222.                 return false
  223.             end
  224.             sleep(0.2)
  225.         end
  226.     end
  227.  
  228.     if not me_bridge_peripheral_found then
  229.         if LOG_LEVELS then botLog(LOG_LEVELS.FATAL, "initializeBot: ME Bridge peripheral (type '"..ME_BRIDGE_PERIPHERAL_NAME.."') NOT found after 4 tries. REQUIRED.") end
  230.         return false
  231.     end
  232.  
  233.     pColonyIntegrator = findPeripheral("Colony Integrator", COLONY_INTEGRATOR_PERIPHERAL_NAME, true)
  234.     if not pColonyIntegrator then
  235.         if LOG_LEVELS then botLog(LOG_LEVELS.FATAL, "initializeBot: Colony Integrator NOT found (REQUIRED).") end
  236.         return false
  237.     end
  238.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"initializeBot: Home location peripherals (ME Bridge, Colony Integrator) found.") end
  239.  
  240.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "initializeBot: Confirming visual to ME Bridge block ('"..ME_BRIDGE_NAME.."')...") end
  241.     local visually_oriented_to_me_block = false
  242.     for visual_orient_attempt = 1, 4 do
  243.         local success_inspect, block_in_front = turtle.inspect()
  244.         if success_inspect and block_in_front and block_in_front.name == ME_BRIDGE_NAME then
  245.             if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "initializeBot: Visually confirmed ME_BRIDGE_NAME block in front (try " .. visual_orient_attempt .. ").") end
  246.             visually_oriented_to_me_block = true
  247.             break
  248.         end
  249.         if visual_orient_attempt < 4 then
  250.             if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "initializeBot: Not visually facing ME_BRIDGE_NAME. Turning right.") end
  251.             if not turtle.turnRight() then
  252.                 if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "initializeBot: turtle.turnRight() failed during visual ME Bridge confirm.") end
  253.                 return false
  254.             end
  255.             sleep(0.2)
  256.         end
  257.     end
  258.    
  259.     if not visually_oriented_to_me_block then
  260.         if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "initializeBot: Could not visually confirm ME_BRIDGE_NAME block in front after 4 tries.") end
  261.         return false
  262.     end
  263.    
  264.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"initializeBot: Backing up from ME Bridge.")end;
  265.     if not turtle.back()then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"initializeBot: Raw turtle.back() failed.")end; print("Console: initializeBot - Back ME FAIL"); return false end;
  266.    
  267.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"initializeBot: Turning right (to face Redstone path).")end;
  268.     if not turtle.turnRight()then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"initializeBot: Raw turtle.turnRight() failed.")end; print("Console: initializeBot - TR after back FAIL"); return false end;
  269.    
  270.     local forward_count_to_redstone=0;
  271.     local redstone_retries=0;
  272.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"initializeBot: Searching for Redstone Block ("..REDSTONE_BLOCK_NAME..")...")end;
  273.     while true do
  274.         local pcall_success, inspect_success_val, block_data_val_or_errmsg = pcall(turtle.inspect);
  275.        
  276.         if pcall_success and inspect_success_val and block_data_val_or_errmsg and type(block_data_val_or_errmsg) == "table" and block_data_val_or_errmsg.name==REDSTONE_BLOCK_NAME then
  277.             if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"initializeBot: Redstone Block found after " .. forward_count_to_redstone .. " forward moves.")end;
  278.             break
  279.         end;
  280.        
  281.         if DEBUG_LOGGING_ENABLED and LOG_LEVELS then
  282.             local block_ahead_log_str = "pcall_fail"
  283.             if pcall_success then
  284.                 if inspect_success_val then block_ahead_log_str = (block_data_val_or_errmsg and type(block_data_val_or_errmsg)=="table" and block_data_val_or_errmsg.name or "empty")
  285.                 else block_ahead_log_str = "inspect_fail:" .. tostring(block_data_val_or_errmsg) end
  286.             else block_ahead_log_str = "pcall_fail:" .. tostring(inspect_success_val) end
  287.             botLog(LOG_LEVELS.DEBUG,"initializeBot: Redstone not found. Fwd. Count:"..forward_count_to_redstone.." Ahead: " .. block_ahead_log_str)
  288.         end;
  289.        
  290.         if turtle.forward()then
  291.             forward_count_to_redstone=forward_count_to_redstone+1;
  292.             redstone_retries=0
  293.         else
  294.             if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"initializeBot: Path to Redstone obstructed. Retry "..(redstone_retries+1).."/"..MAX_REDSTONE_BLOCK_RETRIES)end;
  295.             redstone_retries=redstone_retries+1;
  296.             if redstone_retries>=MAX_REDSTONE_BLOCK_RETRIES then
  297.                 if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"initializeBot: Failed to reach Redstone Block.")end; print("Console: initializeBot - Redstone search FAIL (obstructed)"); return false
  298.             end;
  299.             sleep(REDSTONE_BLOCK_RETRY_WAIT)
  300.         end
  301.     end;
  302.    
  303.     roboSlot = forward_count_to_redstone + 1;
  304.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"initializeBot: Determined roboSlot: "..roboSlot)end;
  305.    
  306.     local redstone_block_abs_x = -110
  307.     local redstone_block_abs_y = 65
  308.     local redstone_block_abs_z = 220
  309.     local redstone_block_abs_dir = 1
  310.    
  311.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, string.format("initializeBot: Setting pos at Redstone: X%dY%dZ%dD%s(1)", redstone_block_abs_x, redstone_block_abs_y, redstone_block_abs_z, DIR_NAMES[redstone_block_abs_dir]))end;
  312.     ml.setPos(redstone_block_abs_x, redstone_block_abs_y, redstone_block_abs_z, redstone_block_abs_dir);
  313.    
  314.     home_pos.x = redstone_block_abs_x - (roboSlot - 1);
  315.     home_pos.y = redstone_block_abs_y;
  316.     home_pos.z = redstone_block_abs_z + 1;
  317.     home_pos.dir = 0;
  318.    
  319.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,string.format("initializeBot: Calc home_pos: X%sY%sZ%sD%s (%s)",home_pos.x,home_pos.y,home_pos.z,home_pos.dir, DIR_NAMES[home_pos.dir]))end;
  320.    
  321.     if not saveData()then if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"initializeBot: Save data failed post-init.")end end;
  322.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"initializeBot: Initialization complete.")end;
  323.     print("Console: CHKPT - initializeBot OK");
  324.     return true
  325. end
  326.  
  327. function maneuverToBarrelsFromHome()
  328.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"maneuverToBarrels: Start")end;
  329.     if not(current_pos.x==home_pos.x and current_pos.y==home_pos.y and current_pos.z==home_pos.z and current_dir==home_pos.dir)then
  330.         if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"maneuverToBarrels: Not at home! Cur: X"..current_pos.x.."Y"..current_pos.y.."Z"..current_pos.z.."D"..current_dir..". Home: X"..home_pos.x.."Y"..home_pos.y.."Z"..home_pos.z.."D"..home_pos.dir..". Abort.")end;
  331.         return false
  332.     end;
  333.     if not ml.moveTo(REFUEL_BARREL_ACCESS_POS.x,REFUEL_BARREL_ACCESS_POS.y,REFUEL_BARREL_ACCESS_POS.z,REFUEL_BARREL_ACCESS_POS.dir)then
  334.         if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"maneuverToBarrels: Failed ml.moveTo barrel access.")end;
  335.         return false
  336.     end;
  337.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"maneuverToBarrels: OK, at barrel access.")end;
  338.     return true
  339. end
  340.  
  341. function maneuverHomeFromBarrels()
  342.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"maneuverHome: Start")end
  343.     if not(current_pos.x==REFUEL_BARREL_ACCESS_POS.x and current_pos.y==REFUEL_BARREL_ACCESS_POS.y and current_pos.z==REFUEL_BARREL_ACCESS_POS.z and current_dir==REFUEL_BARREL_ACCESS_POS.dir)then
  344.         if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"maneuverHome: Not at barrel access! Cur: X"..current_pos.x.."Y"..current_pos.y.."Z"..current_pos.z.."D"..current_dir..". Expect: X"..REFUEL_BARREL_ACCESS_POS.x.."Y"..REFUEL_BARREL_ACCESS_POS.y.."Z"..REFUEL_BARREL_ACCESS_POS.z.."D"..REFUEL_BARREL_ACCESS_POS.dir..". Abort.")end; return false
  345.     end
  346.  
  347.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"maneuverHome: Cur pos at barrel access: X"..current_pos.x.."Y"..current_pos.y.."Z"..current_pos.z.."D"..DIR_NAMES[current_dir])end
  348.    
  349.     local deltaX = home_pos.x - current_pos.x
  350.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"maneuverHome: DeltaX to home: " .. deltaX .. " (home.x: "..home_pos.x..", cur.x: "..current_pos.x..")") end
  351.  
  352.     if deltaX ~= 0 then
  353.         local target_x_dir = (deltaX > 0) and 1 or 3
  354.         if not ml.turnToDir(target_x_dir) then
  355.             if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"maneuverHome: Failed turn for X align.")end; return false
  356.         end
  357.         for _=1, math.abs(deltaX) do
  358.             if not ml.forward() then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"maneuverHome: Failed move during X align.")end; return false end
  359.         end
  360.     end
  361.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"maneuverHome: X coord aligned. Cur: X"..current_pos.x.."Y"..current_pos.y.."Z"..current_pos.z.."D"..DIR_NAMES[current_dir]) end
  362.    
  363.     if current_pos.z ~= home_pos.z then
  364.         local deltaZ_to_home = home_pos.z - current_pos.z
  365.         local target_z_dir = (deltaZ_to_home > 0) and 0 or 2
  366.          if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"maneuverHome: Adj Z from "..current_pos.z.." to "..home_pos.z) end
  367.         if not ml.turnToDir(target_z_dir) then
  368.              if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"maneuverHome: Failed turn for Z align.")end; return false
  369.         end
  370.         for _=1, math.abs(deltaZ_to_home) do
  371.             if not ml.forward() then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"maneuverHome: Failed move during Z align.")end; return false end
  372.         end
  373.     end
  374.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"maneuverHome: Z coord aligned. Cur: X"..current_pos.x.."Y"..current_pos.y.."Z"..current_pos.z.."D"..DIR_NAMES[current_dir]) end
  375.  
  376.     if not ml.turnToDir(home_pos.dir) then
  377.         if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"maneuverHome: Failed turn to final home dir ("..DIR_NAMES[home_pos.dir]..").")end; return false
  378.     end
  379.    
  380.     if current_pos.x==home_pos.x and current_pos.y==home_pos.y and current_pos.z==home_pos.z and current_dir==home_pos.dir then
  381.         if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"maneuverHome: OK, at home.")end; return true
  382.     else
  383.         if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,string.format("maneuverHome: Homing FAILED. Pos Mismatch. Expect X%sY%sZ%sD%s, Got X%sY%sZ%sD%s", home_pos.x,home_pos.y,home_pos.z,DIR_NAMES[home_pos.dir], current_pos.x,current_pos.y,current_pos.z,DIR_NAMES[current_dir]))end;
  384.         return false
  385.     end
  386. end
  387.  
  388. function goHomeProcedure()
  389.     print("Console: CHKPT - Enter goHomeProcedure");
  390.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"goHomeProc: Start")end;
  391.     if current_pos.x==home_pos.x and current_pos.y==home_pos.y and current_pos.z==home_pos.z and current_dir==home_pos.dir then
  392.         if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"goHomeProc: Already at home.")end; print("Console: goHomeProcedure - Already home");
  393.         return true
  394.     end;
  395.    
  396.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"goHomeProc: Nav to nest entry x-113 y100 z221...")end;
  397.     if not ml.moveTo(-113,100,221,nil)then
  398.         if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"goHomeProc: Failed to nav to nest entry.")end; print("Console: goHomeProcedure - moveTo nest entry FAIL");
  399.         return false
  400.     end;
  401.    
  402.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"goHomeProc: At nest entry. Descending to Y65.")end;
  403.     while current_pos.y > 65 do
  404.         if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"goHomeProc: Descending. Cur Y:"..current_pos.y)end;
  405.         if not ml.down()then
  406.             if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"goHomeProc: Descend failed at Y:"..current_pos.y)end; print("Console: goHomeProcedure - descend FAIL");
  407.             return false
  408.         end
  409.     end;
  410.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"goHomeProc: Descended to Y65.")end;
  411.    
  412.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"goHomeProc: Moving to barrel access pos REFUEL_BARREL_ACCESS_POS")end;
  413.     if not ml.moveTo(REFUEL_BARREL_ACCESS_POS.x,REFUEL_BARREL_ACCESS_POS.y,REFUEL_BARREL_ACCESS_POS.z,REFUEL_BARREL_ACCESS_POS.dir)then
  414.         if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"goHomeProc: Failed to move to barrel access pos.")end;
  415.         return false
  416.     end;
  417.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"goHomeProc: Positioned at refuel barrel access.")end;
  418.    
  419.     if not maneuverHomeFromBarrels()then
  420.         if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"goHomeProc: maneuverHomeFromBarrels failed.")end;
  421.         return false
  422.     end;
  423.    
  424.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"goHomeProc: Successfully returned home.")end;
  425.     print("Console: CHKPT - goHomeProcedure OK");
  426.     return true
  427. end
  428.  
  429. function handleFuel()
  430.     print("Console: CHKPT - Enter handleFuel");
  431.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"handleFuel: Start")end;
  432.     if not(current_pos.x==REFUEL_BARREL_ACCESS_POS.x and current_pos.y==REFUEL_BARREL_ACCESS_POS.y and current_pos.z==REFUEL_BARREL_ACCESS_POS.z and current_dir==REFUEL_BARREL_ACCESS_POS.dir)then
  433.         if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"handleFuel: Not at barrel access. Skipping fuel.")end;
  434.         return true
  435.     end;
  436.    
  437.     local fuel_level, fuel_limit = ml.getFuelLevel(), ml.getFuelLimit();
  438.     if fuel_limit == 0 then
  439.         if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"handleFuel: Infinite fuel.")end;
  440.         return true
  441.     end;
  442.    
  443.     local fuel_percentage = (fuel_level / fuel_limit);
  444.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,string.format("handleFuel: Fuel: %d/%d (%.2f%%)",fuel_level,fuel_limit,fuel_percentage*100))end;
  445.    
  446.     local needs_refuel = fuel_percentage < REFUEL_BELOW_PERCENTAGE;
  447.     local coal_detail = ml.getItemDetail(FUEL_SLOT);
  448.     local coal_count = ml.getItemCount(FUEL_SLOT);
  449.     local needs_restock = not coal_detail or coal_detail.name ~= COAL_BLOCK_NAME or coal_count < (coal_detail and coal_detail.maxCount or 64);
  450.  
  451.     if needs_refuel or needs_restock then
  452.         if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"handleFuel: Action. Refuel="..tostring(needs_refuel)..", Restock="..tostring(needs_restock))end;
  453.        
  454.         if needs_restock then
  455.             if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"handleFuel: Restocking slt "..FUEL_SLOT.." with "..COAL_BLOCK_NAME)end;
  456.             ml.select(FUEL_SLOT);
  457.             if coal_detail and coal_detail.name ~= COAL_BLOCK_NAME and coal_count > 0 then
  458.                 if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"handleFuel: Non-"..COAL_BLOCK_NAME.." in fuel slt! Can't restock.")end
  459.             else
  460.                 local amount_to_suck = (coal_detail and coal_detail.maxCount or 64) - coal_count;
  461.                 if amount_to_suck > 0 then
  462.                     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"handleFuel: Try suck "..amount_to_suck.." "..COAL_BLOCK_NAME..".")end;
  463.                     if ml.suck(amount_to_suck)then
  464.                         if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"handleFuel: Sucked "..COAL_BLOCK_NAME..". New count: "..ml.getItemCount(FUEL_SLOT))end
  465.                     else
  466.                         if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"handleFuel: Failed to suck "..COAL_BLOCK_NAME..".")end
  467.                     end
  468.                 else
  469.                      if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"handleFuel: Fuel slt full of "..COAL_BLOCK_NAME.." or needs 0.")end
  470.                 end
  471.             end
  472.         end;
  473.        
  474.         coal_detail = ml.getItemDetail(FUEL_SLOT)
  475.         if fuel_percentage < REFUEL_BELOW_PERCENTAGE and coal_detail and coal_detail.name == COAL_BLOCK_NAME then
  476.              if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"handleFuel: Refueling...")end;
  477.              if not ml.refuel()then
  478.                 if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"handleFuel: ml.refuel() attempt failed.")end
  479.              end
  480.         elseif fuel_percentage < REFUEL_BELOW_PERCENTAGE then
  481.             if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"handleFuel: Needs refuel, but fuel slt no "..COAL_BLOCK_NAME)end
  482.         end
  483.     else
  484.         if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"handleFuel: Fuel level and stock OK.")end
  485.     end;
  486.     print("Console: CHKPT - Exit handleFuel");
  487.     return true
  488. end
  489.  
  490. function handleItemReturn()
  491.     print("Console: CHKPT - Enter handleItemReturn");
  492.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"handleItemReturn: Start")end;
  493.     if not(current_pos.x==REFUEL_BARREL_ACCESS_POS.x and current_pos.y==REFUEL_BARREL_ACCESS_POS.y and current_pos.z==REFUEL_BARREL_ACCESS_POS.z and current_dir==REFUEL_BARREL_ACCESS_POS.dir)then
  494.         if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"handleItemReturn: Not at barrel access. Skipping.")end;
  495.         return true
  496.     end;
  497.    
  498.     local items_found_to_return=false;
  499.     for slot_idx=1,15 do
  500.         if ml.getItemCount(slot_idx)>0 then
  501.             items_found_to_return=true;
  502.             if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"handleItemReturn: Found items in slt "..slot_idx.." to return.")end;
  503.             break
  504.         end
  505.     end;
  506.    
  507.     if not items_found_to_return then
  508.         if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"handleItemReturn: No items in cargo slts 1-15.")end; print("Console: handleItemReturn - No items");
  509.         return true
  510.     end;
  511.    
  512.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"handleItemReturn: Items found. Moving up to Return Barrel.")end;
  513.     if not ml.up()then
  514.         if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"handleItemReturn: Failed move up to Return Barrel.")end; print("Console: handleItemReturn - up FAIL");
  515.         return false
  516.     end;
  517.    
  518.     for slot_idx=1,15 do
  519.         ml.select(slot_idx);
  520.         local item_count_in_slot=ml.getItemCount(slot_idx);
  521.         if item_count_in_slot > 0 then
  522.             local item_detail=ml.getItemDetail(slot_idx);
  523.             local item_name = item_detail and item_detail.name or "Unknown Item";
  524.             if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"handleItemReturn: Try return "..item_count_in_slot.."x "..item_name.." from slt "..slot_idx)end;
  525.             if not ml.drop()then
  526.                 if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"handleItemReturn: Failed drop items from slt "..slot_idx)end
  527.             end
  528.         end
  529.     end;
  530.    
  531.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"handleItemReturn: Finished returns. Moving down from Return Barrel.")end;
  532.     if not ml.down()then
  533.         if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"handleItemReturn: Failed move down from Return Barrel.")end; print("Console: handleItemReturn - down FAIL");
  534.         return false
  535.     end;
  536.    
  537.     undeliveredItemsBuffer = {}
  538.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"handleItemReturn: Item return complete.")end;
  539.     print("Console: CHKPT - Exit handleItemReturn");
  540.     return true
  541. end
  542.  
  543. function getItemsFromME(itemsToGetTable)
  544.     print("Console: CHKPT - Enter getItemsFromME")
  545.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "getItemsFromME: Start") end
  546.  
  547.     if not (current_pos.x == home_pos.x and current_pos.y == home_pos.y and current_pos.z == home_pos.z and current_dir == home_pos.dir) then
  548.         if LOG_LEVELS then botLog(LOG_LEVELS.WARN, "getItemsFromME: Not at home. Aborting.") end
  549.         return {}
  550.     end
  551.     if not pMeBridge then
  552.         if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "getItemsFromME: pMeBridge is nil. Aborting.") end
  553.         return {}
  554.     end
  555.     if type(pMeBridge.exportItem) ~= "function" then
  556.         if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "getItemsFromME: pMeBridge NO 'exportItem' method. Peripheral/mod issue? Abort ME.") end
  557.         return {}
  558.     end
  559.  
  560.  
  561.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "getItemsFromME: Moving up to ME xfer chest.") end
  562.     if not ml.up() then
  563.         if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "getItemsFromME: Failed move up to ME xfer chest.") end
  564.         return {}
  565.     end
  566.  
  567.     local fetched_item_details = {}
  568.  
  569.     for _, requested_item_spec in ipairs(itemsToGetTable) do
  570.         if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "getItemsFromME: Request " .. requested_item_spec.count .. "x " .. requested_item_spec.name .. " from ME.") end
  571.        
  572.         local export_pcall_success, export_result_or_err = pcall(function() return pMeBridge.exportItem({ name = requested_item_spec.name, count = requested_item_spec.count }, "up") end)
  573.        
  574.         if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "getItemsFromME: exportItem pcall SC=" .. tostring(export_pcall_success) .. ", Res/Err=" .. textutils.serialize(export_result_or_err)) end
  575.  
  576.         if not export_pcall_success then
  577.             if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "getItemsFromME: CRITICAL - pcall pMeBridge.exportItem failed for " .. requested_item_spec.name .. ". Err: " .. tostring(export_result_or_err)) end
  578.             goto continue_me_item_request
  579.         end
  580.        
  581.         if type(export_result_or_err) ~= "number" or export_result_or_err == 0 then
  582.              if LOG_LEVELS then botLog(LOG_LEVELS.WARN, "getItemsFromME: ME export 0/non-numeric for " .. requested_item_spec.name .. ". Actual ME resp: " .. textutils.serialize(export_result_or_err)) end
  583.             goto continue_me_item_request
  584.         end
  585.  
  586.         local actual_exported_count = export_result_or_err
  587.         if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "getItemsFromME: ME Bridge exported " .. actual_exported_count .. "x " .. requested_item_spec.name .. " to chest.") end
  588.        
  589.         local amount_remaining_to_suck_from_chest = actual_exported_count
  590.         while amount_remaining_to_suck_from_chest > 0 do
  591.             local target_slot = -1
  592.             for s = 1, 15 do
  593.                 local item_in_slot = ml.getItemDetail(s)
  594.                 if item_in_slot and item_in_slot.name == requested_item_spec.name and item_in_slot.count < item_in_slot.maxCount then
  595.                     target_slot = s
  596.                     break
  597.                 end
  598.             end
  599.             if target_slot == -1 then
  600.                 for s = 1, 15 do
  601.                     if not ml.getItemDetail(s) then
  602.                         target_slot = s
  603.                         break
  604.                     end
  605.                 end
  606.             end
  607.  
  608.             if target_slot == -1 then
  609.                 if LOG_LEVELS then botLog(LOG_LEVELS.WARN, "getItemsFromME: No inv space for '" .. requested_item_spec.name .. "' (need " .. amount_remaining_to_suck_from_chest .. "). Items may remain in chest.") end
  610.                 break
  611.             end
  612.  
  613.             ml.select(target_slot)
  614.             local space_in_this_slot = turtle.getItemSpace(target_slot)
  615.             local attempt_suck_amount = math.min(amount_remaining_to_suck_from_chest, space_in_this_slot)
  616.  
  617.             if attempt_suck_amount == 0 then
  618.                 if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "getItemsFromME: Slt " .. target_slot .. " full or no more items for " .. requested_item_spec.name .. ". Skip suck.") end
  619.                 break
  620.             end
  621.            
  622.             local count_in_slot_before_suck = ml.getItemCount(target_slot)
  623.             if ml.suck(attempt_suck_amount) then
  624.                 local count_in_slot_after_suck = ml.getItemCount(target_slot)
  625.                 local num_actually_sucked_this_op = count_in_slot_after_suck - count_in_slot_before_suck
  626.                
  627.                 if num_actually_sucked_this_op > 0 then
  628.                     amount_remaining_to_suck_from_chest = amount_remaining_to_suck_from_chest - num_actually_sucked_this_op
  629.                    
  630.                     local existing_entry_idx = -1
  631.                     for i, entry in ipairs(fetched_item_details) do
  632.                         if entry.slot == target_slot then
  633.                             existing_entry_idx = i; break
  634.                         end
  635.                     end
  636.                     if existing_entry_idx ~= -1 then
  637.                         fetched_item_details[existing_entry_idx].count = count_in_slot_after_suck
  638.                     else
  639.                         table.insert(fetched_item_details, { name = requested_item_spec.name, slot = target_slot, count = count_in_slot_after_suck })
  640.                     end
  641.                     if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "getItemsFromME: Sucked " .. num_actually_sucked_this_op .. "x " .. requested_item_spec.name .. " to slt " .. target_slot .. ". Total: " .. count_in_slot_after_suck .. ". Left in chest: " .. amount_remaining_to_suck_from_chest) end
  642.                 else
  643.                     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "getItemsFromME: ml.suck() 0 items for " .. requested_item_spec.name .. " to slt " .. target_slot .. ". Chest empty?") end
  644.                     break
  645.                 end
  646.             else
  647.                 if LOG_LEVELS then botLog(LOG_LEVELS.WARN, "getItemsFromME: ml.suck() failed for " .. requested_item_spec.name .. " to slt " .. target_slot .. ". Chest obstructed/empty?") end
  648.                 break
  649.             end
  650.         end
  651.         ::continue_me_item_request::
  652.     end
  653.  
  654.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "getItemsFromME: Finished all requests. Moving down from ME chest.") end
  655.     if not ml.down() then
  656.         if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "getItemsFromME: Failed to move down from ME xfer chest.") end
  657.     end
  658.  
  659.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "getItemsFromME: Process complete. Fetched " .. #fetched_item_details .. " item stacks/details.") end
  660.     print("Console: CHKPT - Exit getItemsFromME")
  661.     return fetched_item_details
  662. end
  663.  
  664. function leaveNest()
  665.     print("Console: CHKPT - Enter leaveNest");
  666.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"leaveNest: Start")end;
  667.    
  668.     local start_exit_pos_x = home_pos.x
  669.     local start_exit_pos_y = home_pos.y
  670.     local start_exit_pos_z = home_pos.z - 1
  671.     local start_exit_dir = 1
  672.  
  673.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, string.format("leaveNest: Moving to redstone block pos (X%sY%sZ%sD%s) for exit.", start_exit_pos_x, start_exit_pos_y, start_exit_pos_z, DIR_NAMES[start_exit_dir]))end;
  674.     if not ml.moveTo(start_exit_pos_x, start_exit_pos_y, start_exit_pos_z, start_exit_dir)then
  675.         if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"leaveNest: Failed to move to redstone block for exit.")end;
  676.         return false
  677.     end;
  678.    
  679.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"leaveNest: Turning South (TR from East).")end;
  680.     if not ml.turnRight()then return false end;
  681.    
  682.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"leaveNest: Moving Forward (South).")end;
  683.     if not ml.forward()then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"leaveNest: Obstructed moving South.")end;return false end;
  684.    
  685.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"leaveNest: Turning West (TR from South).")end;
  686.     if not ml.turnRight()then return false end;
  687.    
  688.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"leaveNest: Moving Forward (West).")end;
  689.     if not ml.forward()then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"leaveNest: Obstructed moving West.")end;return false end;
  690.    
  691.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"leaveNest: Ascending to Y=100...")end;
  692.     while current_pos.y < 100 do
  693.         if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"leaveNest: Ascending. Cur Y:"..current_pos.y)end;
  694.         if not ml.up()then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"leaveNest: Obstructed ascent at Y:"..current_pos.y)end;return false end
  695.     end;
  696.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"leaveNest: Reached Y=100.")end;
  697.    
  698.     local target_exit_x = -111
  699.     local target_exit_y = 100
  700.     local target_exit_z = 221
  701.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, string.format("leaveNest: Moving to final exit (X%sY%sZ%s).",target_exit_x, target_exit_y, target_exit_z))end;
  702.     if not ml.moveTo(target_exit_x, target_exit_y, target_exit_z, nil)then
  703.         if LOG_LEVELS then botLog(LOG_LEVELS.WARN, string.format("leaveNest: Can't reach precise final exit. Cur Y:%s. Tgt X%sY%sZ%s.", current_pos.y, target_exit_x, target_exit_y, target_exit_z))end;
  704.         if current_pos.y ~= target_exit_y then
  705.             if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"leaveNest: Critical - Y incorrect after ascent. Expected Y"..target_exit_y)end;
  706.             return false
  707.         end
  708.     end;
  709.    
  710.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,string.format("leaveNest: OK. Cur Pos: X%sY%sZ%sD%s (%s)",current_pos.x,current_pos.y,current_pos.z,current_dir, DIR_NAMES[current_dir]))end;
  711.     print("Console: CHKPT - Exit leaveNest");
  712.     return true
  713. end
  714.  
  715. function deliverItems(target_pos,items_in_slots_details)
  716.     print("Console: CHKPT - Enter deliverItems");
  717.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,string.format("deliverItems: Target X%sY%sZ%s",target_pos.x,target_pos.y,target_pos.z))end;
  718.    
  719.     if not ml.moveTo(target_pos.x,target_pos.y,target_pos.z,nil)then
  720.         if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"deliverItems: Failed move to delivery loc ("..target_pos.x..","..target_pos.y..","..target_pos.z.."). Buffering items.")end;
  721.         for _,item_detail_entry in ipairs(items_in_slots_details)do
  722.             table.insert(undeliveredItemsBuffer,{name=item_detail_entry.name,count=item_detail_entry.count,original_slot=item_detail_entry.slot})
  723.         end;
  724.         if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"deliverItems: All items for this delivery buffered. Buffer size:"..#undeliveredItemsBuffer)end;
  725.         return false
  726.     end;
  727.    
  728.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"deliverItems: Arrived at delivery loc. Dropping items.")end;
  729.     for _,item_detail_entry in ipairs(items_in_slots_details)do
  730.         ml.select(item_detail_entry.slot);
  731.         local count_to_drop = ml.getItemCount(item_detail_entry.slot);
  732.        
  733.         if count_to_drop > 0 then
  734.             if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"deliverItems: Try drop "..count_to_drop.."x "..item_detail_entry.name.." from slt "..item_detail_entry.slot)end;
  735.             if not ml.drop(count_to_drop)then
  736.                 if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"deliverItems: Failed drop all ("..item_detail_entry.name..") from slt "..item_detail_entry.slot)end;
  737.                 local remaining_count = ml.getItemCount(item_detail_entry.slot);
  738.                 if remaining_count > 0 then
  739.                     table.insert(undeliveredItemsBuffer,{name=item_detail_entry.name,count=remaining_count,original_slot=item_detail_entry.slot});
  740.                     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"deliverItems: "..remaining_count.."x "..item_detail_entry.name.." from slt "..item_detail_entry.slot.." added to buffer.")end
  741.                 end
  742.             else
  743.                 if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"deliverItems: OK dropped "..count_to_drop.."x "..item_detail_entry.name.." from slt "..item_detail_entry.slot)end
  744.             end
  745.         end
  746.     end;
  747.    
  748.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"deliverItems: Delivery attempt complete.")end;
  749.     print("Console: CHKPT - Exit deliverItems");
  750.     return true
  751. end
  752. --#endregion
  753.  
  754. --#region Main Loop
  755. local function run()
  756.     print("Console: CHKPT - run() CALLED")
  757.     do
  758.         local fileNameToOpen = LOG_FILE_NAME_CONST
  759.         if type(fileNameToOpen) ~= "string" then
  760.             print("Console: CRITICAL - LOG_FILE_NAME_CONST nil. Forcing default.")
  761.             fileNameToOpen = "villagebot_forced_CRITICAL.log"
  762.         end
  763.         local f,ferr=fs.open(fileNameToOpen,"w")
  764.         if f then
  765.             f.write(string.format("[%s] VillageBot Log Initialized.\n",os.date("%Y-%m-%d %H:%M:%S")))
  766.             f.close()
  767.             print("Console: Log file reset: " .. fileNameToOpen)
  768.         else
  769.             print("Console: CRITICAL - Log init FAIL for '" .. tostring(fileNameToOpen) .. "': "..tostring(ferr))
  770.             if LOG_LEVELS and pcall then
  771.                  pcall(botLog,LOG_LEVELS.FATAL,"CRITICAL - Log init FAIL: "..tostring(ferr))
  772.             end
  773.             return
  774.         end
  775.     end
  776.  
  777.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"VillageBot v1.7 Starting...") else print("Console: VillageBot v1.7 Starting... (LOG_LEVELS nil)") end
  778.     sleep(0.1)
  779.     if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"RUN: Init core peripherals...") end; sleep(0.1)
  780.     local corePOK=initCorePeripherals();
  781.     if not corePOK then if LOG_LEVELS then botLog(LOG_LEVELS.FATAL,"RUN: initCoreP FAILED. Terminating.")end; print("Console: Error - Core P init FAILED. Terminate."); return end
  782.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"RUN: Core Peripherals OK.")end; sleep(0.1)
  783.    
  784.     local data_setup_successful=false
  785.     if loadData() and roboSlot~=nil and home_pos and home_pos.x~=nil and current_pos and current_pos.x~=nil and current_dir~=nil then
  786.         if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"RUN: Bot data loaded. RoboSlot:"..roboSlot)end
  787.         data_setup_successful=true
  788.     else
  789.         if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"RUN: No valid data file/incomplete. Full initialization.")end
  790.         if fs.exists(BOT_DATA_FILE) then
  791.              if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"RUN: Existing data file invalid. Deleting.")end
  792.              pcall(fs.delete, BOT_DATA_FILE)
  793.         end
  794.         if initializeBot()then
  795.             if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"RUN: Bot full initialization OK.")end
  796.             data_setup_successful=true
  797.         else
  798.             if LOG_LEVELS then botLog(LOG_LEVELS.FATAL,"RUN: Bot full initialization FAILED. Terminating.")end;print("Console: Error - Bot core init FAILED. Terminate.");return
  799.         end
  800.     end
  801.     if not data_setup_successful then if LOG_LEVELS then botLog(LOG_LEVELS.FATAL,"RUN: Failed load/init bot data. Terminating.")end;print("Console: FATAL - Data setup FAILED. Terminate.");return end
  802.    
  803.     if not pMeBridge or not pColonyIntegrator then
  804.         if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "RUN: Home location P (ME, ColonyIntegrator) not confirmed. Ensure home & find.") end
  805.         if not (current_pos.x == home_pos.x and current_pos.y == home_pos.y and current_pos.z == home_pos.z and current_dir == home_pos.dir) then
  806.             if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "RUN: Bot not home. Running goHomeProcedure.") end
  807.             if not goHomeProcedure() then
  808.                 if LOG_LEVELS then botLog(LOG_LEVELS.FATAL, "RUN: goHomeProcedure failed during setup. Cannot find home P. Terminating.") end
  809.                 return
  810.             end
  811.         end
  812.         if not findHomeLocationPeripherals() then
  813.             if LOG_LEVELS then botLog(LOG_LEVELS.FATAL, "RUN: Failed to find/attach home P after ensuring home. Terminating.") end
  814.             return
  815.         end
  816.     end
  817.  
  818.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"RUN: Data load/init phase complete. Required P should be found."); end; sleep(0.1)
  819.     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"RUN: Entering main operational loop...")end;
  820.    
  821.     while true do
  822.         -- Declare ALL loop-specific locals at the top to avoid goto scope issues
  823.         local work_order_data = nil
  824.         local items_to_fetch = nil
  825.         local fetched_items_summary = nil
  826.         local get_work_pcall_success = false -- For getBuilderResources pcall
  827.         local work_order_result_from_api = nil -- Result from getBuilderResources
  828.  
  829.         local all_wo_pcall_success = false -- For getWorkOrders pcall
  830.         local all_wo_result = nil      -- Result from getWorkOrders
  831.         local all_work_orders = nil
  832.         local my_assigned_work_order_details = nil
  833.         local builder_hut_pos_for_api_call = nil
  834.  
  835.         local needs_dedicated_barrel_trip_flag = false
  836.         local fuel_check_still_needed_flag = true
  837.         local item_return_check_still_needed_flag = true
  838.         local was_at_barrels_this_cycle_leg = false
  839.  
  840.         if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "===== Cycle Start =====")end; sleep(0.1)
  841.  
  842.         if not (current_pos.x == home_pos.x and current_pos.y == home_pos.y and current_pos.z == home_pos.z and current_dir == home_pos.dir) then
  843.             if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "LOOP: Not home. Cur: X"..current_pos.x.."Y"..current_pos.y.."Z"..current_pos.z.."D"..(current_dir and DIR_NAMES[current_dir] or "nil")..". Running goHomeProcedure.")end
  844.             if not goHomeProcedure() then
  845.                 if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"LOOP: goHomeProcedure failed. Retry cycle after delay.")end
  846.                 sleep(60); goto continue_main_loop_cycle
  847.             end
  848.             if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: goHomeProcedure OK. Bot should be home (passed barrels).")end
  849.             was_at_barrels_this_cycle_leg = true
  850.         else
  851.             if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: Started cycle at home.")end
  852.         end
  853.  
  854.         if was_at_barrels_this_cycle_leg then
  855.             if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: Bot was at barrels during goHome transit. Performing checks.")end
  856.         else
  857.             local current_fuel_level = ml.getFuelLevel(); local current_fuel_limit = ml.getFuelLimit()
  858.             if current_fuel_limit == 0 or (current_fuel_limit > 0 and (current_fuel_level / current_fuel_limit >= REFUEL_BELOW_PERCENTAGE)) then
  859.                 fuel_check_still_needed_flag = false
  860.                 if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: Fuel OK/infinite, no trip *just* for low fuel %.")end
  861.             else
  862.                 if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: Fuel low. Trip for fuel may be needed.")end
  863.             end
  864.  
  865.             local items_in_cargo_slots = false
  866.             for slot_idx=1,15 do if ml.getItemCount(slot_idx) > 0 then items_in_cargo_slots = true; break; end end
  867.             if not items_in_cargo_slots then
  868.                 item_return_check_still_needed_flag = false
  869.                 if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: No items in cargo, no trip *just* for item return.")end
  870.             else
  871.                  if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: Items in cargo. Trip for item return may be needed.")end
  872.             end
  873.            
  874.             local coal_detail_check = ml.getItemDetail(FUEL_SLOT)
  875.             local needs_fuel_slot_restock = not coal_detail_check or coal_detail_check.name ~= COAL_BLOCK_NAME or ml.getItemCount(FUEL_SLOT) < (coal_detail_check and coal_detail_check.maxCount or 64)
  876.             if needs_fuel_slot_restock then
  877.                  if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: Fuel slt needs restock. Trip for fuel may be needed.")end
  878.                  fuel_check_still_needed_flag = true
  879.             end
  880.  
  881.             needs_dedicated_barrel_trip_flag = fuel_check_still_needed_flag or item_return_check_still_needed_flag
  882.  
  883.             if needs_dedicated_barrel_trip_flag then
  884.                 if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "LOOP: Home, but needs fuel/return. Maneuvering to barrels. FuelNeeded="..tostring(fuel_check_still_needed_flag).." ItemReturnNeeded="..tostring(item_return_check_still_needed_flag))end
  885.                 if not maneuverToBarrelsFromHome() then
  886.                     if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "LOOP: Failed maneuver to barrels from home. Retry cycle after delay.")end
  887.                     sleep(60); goto continue_main_loop_cycle
  888.                 end
  889.                 was_at_barrels_this_cycle_leg = true
  890.             else
  891.                 if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: Home, no dedicated fuel/return ops needed from here.")end
  892.             end
  893.         end
  894.  
  895.         if was_at_barrels_this_cycle_leg then
  896.             if item_return_check_still_needed_flag then
  897.                 if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: Item return at barrels.")end
  898.                 if not handleItemReturn() then
  899.                     if LOG_LEVELS then botLog(LOG_LEVELS.WARN, "LOOP: Issue during item return at barrels. Continuing.")end
  900.                 end
  901.             end
  902.             if fuel_check_still_needed_flag then
  903.                 if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: Fuel handling at barrels.")end
  904.                 if not handleFuel() then
  905.                     if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "LOOP: Failed fuel handling at barrels. Retry cycle after delay.")end;
  906.                     sleep(60); goto continue_main_loop_cycle
  907.                 end
  908.             end
  909.            
  910.             if not (current_pos.x == home_pos.x and current_pos.y == home_pos.y and current_pos.z == home_pos.z and current_dir == home_pos.dir) then
  911.                 if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: Not home after barrel ops. Maneuvering home.")end
  912.                 if not maneuverHomeFromBarrels() then
  913.                     if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "LOOP: Failed maneuver home from barrels. Retry cycle after delay.")end
  914.                     sleep(60); goto continue_main_loop_cycle
  915.                 end
  916.             end
  917.         end
  918.        
  919.         if not(current_pos.x==home_pos.x and current_pos.y==home_pos.y and current_pos.z==home_pos.z and current_dir==home_pos.dir) then
  920.              if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"LOOP: CRITICAL - NOT HOME before get work! Pos: X"..current_pos.x.."Y"..current_pos.y.."Z"..current_pos.z.."D"..(current_dir and DIR_NAMES[current_dir] or "nil")..". Forcing goHomeProcedure.")end
  921.              if not goHomeProcedure() then
  922.                  if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"LOOP: Critical Fail on forced goHomeProcedure. Retry cycle after delay.")end
  923.                  sleep(60); goto continue_main_loop_cycle
  924.              end
  925.         end
  926.         if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"LOOP: Pos confirmed home before work tasks.")end
  927.  
  928.         if not pColonyIntegrator then
  929.             if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "LOOP: pColonyIntegrator nil. Cannot get work. Retry cycle.") end
  930.             sleep(30); goto continue_main_loop_cycle
  931.         end
  932.  
  933.         if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"LOOP: Fetching all work orders.")end
  934.         all_wo_pcall_success, all_wo_result = pcall(function() return pColonyIntegrator.getWorkOrders() end)
  935.  
  936.         if not all_wo_pcall_success or not all_wo_result or type(all_wo_result) ~= "table" then
  937.             if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "LOOP: pcall getWorkOrders() failed or invalid data. Res/Err: " .. textutils.serialize(all_wo_result) .. ". Retry cycle.") end
  938.             sleep(30); goto continue_main_loop_cycle
  939.         end
  940.        
  941.         all_work_orders = all_wo_result
  942.         if #all_work_orders == 0 then
  943.             if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "LOOP: No active work orders from getWorkOrders(). Wait & retry.") end
  944.             sleep(30); goto continue_main_loop_cycle
  945.         end
  946.  
  947.         if roboSlot < 1 or roboSlot > #all_work_orders then
  948.             if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "LOOP: roboSlot (" .. roboSlot .. ") out of bounds for work orders (size: " .. #all_work_orders .. "). Wait & retry.") end
  949.             sleep(30); goto continue_main_loop_cycle
  950.         end
  951.  
  952.         my_assigned_work_order_details = all_work_orders[roboSlot]
  953.         if not my_assigned_work_order_details or
  954.            not my_assigned_work_order_details.builder or
  955.            type(my_assigned_work_order_details.builder) ~= "table" or
  956.            not my_assigned_work_order_details.builder.x or
  957.            not my_assigned_work_order_details.builder.y or
  958.            not my_assigned_work_order_details.builder.z then
  959.             if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "LOOP: Assigned WO at index " .. roboSlot .. " invalid or missing builder pos. Details: " .. textutils.serialize(my_assigned_work_order_details) .. ". Retry cycle.") end
  960.             sleep(30); goto continue_main_loop_cycle
  961.         end
  962.  
  963.         builder_hut_pos_for_api_call = my_assigned_work_order_details.builder
  964.  
  965.         if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "LOOP: Fetching resources via getBuilderResources for builder hut at X:" .. builder_hut_pos_for_api_call.x .. "Y:" .. builder_hut_pos_for_api_call.y .. "Z:" .. builder_hut_pos_for_api_call.z .. " (roboSlot " .. roboSlot .. ")") end
  966.         get_work_pcall_success, work_order_result_from_api = pcall(function() return pColonyIntegrator.getBuilderResources(builder_hut_pos_for_api_call) end)
  967.        
  968.         if not get_work_pcall_success then
  969.             if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "LOOP: pcall pColonyIntegrator.getBuilderResources() failed. Err: "..tostring(work_order_result_from_api)..". Retry cycle.") end
  970.             sleep(30); goto continue_main_loop_cycle
  971.         end
  972.        
  973.         work_order_data = work_order_result_from_api
  974.  
  975.         if not work_order_data or type(work_order_data) ~= "table" then
  976.             if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "LOOP: No work data or invalid from getBuilderResources. Data: "..textutils.serialize(work_order_data) ..". Wait & retry.") end
  977.             sleep(30); goto continue_main_loop_cycle
  978.         end
  979.  
  980.         if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: Received work data from getBuilderResources: " .. textutils.serialize(work_order_data)) end
  981.  
  982.         if work_order_data.resources and type(work_order_data.resources) == "table" and
  983.            work_order_data.hutLocation and type(work_order_data.hutLocation) == "table" and
  984.            work_order_data.hutLocation.x and work_order_data.hutLocation.y and work_order_data.hutLocation.z then
  985.            
  986.             if #work_order_data.resources == 0 then
  987.                 if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "LOOP: WO for roboSlot "..roboSlot.." has no resources in getBuilderResources response. Task complete for now. Waiting.") end
  988.                 sleep(30); goto continue_main_loop_cycle
  989.             end
  990.  
  991.             if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "LOOP: Valid work data. Resources: "..#work_order_data.resources..", Hut: X"..work_order_data.hutLocation.x .. "Y"..work_order_data.hutLocation.y .. "Z"..work_order_data.hutLocation.z) end
  992.             items_to_fetch = work_order_data.resources
  993.             fetched_items_summary = getItemsFromME(items_to_fetch)
  994.            
  995.             if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"LOOP: getItemsFromME returned "..#fetched_items_summary.." item slot details.")end
  996.            
  997.             local has_items_to_deliver = false
  998.             if fetched_items_summary and #fetched_items_summary > 0 then
  999.                 for _, item_entry in ipairs(fetched_items_summary) do
  1000.                     if item_entry.count > 0 then has_items_to_deliver = true; break; end
  1001.                 end
  1002.             end
  1003.  
  1004.             if has_items_to_deliver then
  1005.                 if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"LOOP: Items fetched. Leaving nest.")end
  1006.                 if not leaveNest()then
  1007.                     if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"LOOP: Failed to leave nest. Items returned next cycle. Retry cycle after delay.")end
  1008.                     sleep(30);goto continue_main_loop_cycle
  1009.                 end
  1010.                 if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"LOOP: leaveNest OK.")end
  1011.                
  1012.                 if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"LOOP: Delivering items to hut X:"..work_order_data.hutLocation.x.."Y:"..work_order_data.hutLocation.y.."Z:"..work_order_data.hutLocation.z)end
  1013.                 if not deliverItems(work_order_data.hutLocation, fetched_items_summary)then
  1014.                     if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"LOOP: Delivery issues. Undelivered items buffered.")end
  1015.                 else
  1016.                     if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"LOOP: deliverItems process completed for this WO.")end
  1017.                 end
  1018.             else
  1019.                 if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"LOOP: No items fetched from ME for WO, or ME bridge issue.")end
  1020.             end
  1021.         else
  1022.             if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"LOOP: Work data from getBuilderResources incomplete/malformed. Structure: "..textutils.serialize(work_order_data)..". Wait & retry.")end
  1023.             sleep(30); goto continue_main_loop_cycle
  1024.         end
  1025.  
  1026.         if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"===== Cycle End OK =====")end
  1027.         ::continue_main_loop_cycle::
  1028.         if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"LOOP: Sleeping 30s before next cycle.")end
  1029.         print("Console: LOOP - Cycle End. Sleep 30s.")
  1030.         sleep(30)
  1031.     end
  1032.     if LOG_LEVELS then botLog(LOG_LEVELS.FATAL,"RUN: Main loop EXITED UNEXPECTEDLY!")end; print("Console: FATAL - Main loop EXITED!")
  1033. end
  1034. --#endregion
  1035.  
  1036. -- Start the bot
  1037. print("Console: DEBUG - Script exec start. Calling run().")
  1038. run()
  1039. print("Console: DEBUG - Script exec finished. run() completed/exited.")
  1040. if LOG_LEVELS and LOG_FILE_NAME_CONST and type(LOG_FILE_NAME_CONST) == "string" then
  1041.     pcall(botLog,LOG_LEVELS.FATAL, "SCRIPT ENDED ABNORMALLY: Reached end of file after run() call.")
  1042. else
  1043.     print("Console: SCRIPT ENDED ABNORMALLY (LOG_LEVELS or LOG_FILE_NAME_CONST invalid).")
  1044. end
Add Comment
Please, Sign In to add comment