args = {...} x, z, direction = 0, 0, 0 turtlestate = { name = os.getComputerLabel(), id = os.getComputerID(), fuel = "", state = "init", job = nil, ores = {} } function noop() end function pair(x, y) return math.floor((x + y) * (x + y + 1)/2 + y) end function unpairX(z) local j = math.floor(math.sqrt(0.25 + 2*z) - 0.5) return j - (z - j*(j+1)/2) end function unpairZ(z) local j = math.floor(math.sqrt(0.25 + 2*z) - 0.5) return z - j * (j+1)/2; end lookup = {4, 1, 3, 0, 2} local function isDiggingSpot(x, y) local val = lookup[(y % 5) + 1] return (x % 5) == val end offset = 10 function ithSpot(i) j = offset while true do x, z = unpairX(j), unpairZ(j) if isDiggingSpot(x, z) then if i <= 1 then return x, z else i = i - 1 end end j = j + 1 end end function adjustToQuadrant(i, x, z) if i % 4 == 0 then return x, z elseif i % 4 == 1 then return -z-1, x elseif i % 4 == 2 then return z, -x-1 elseif i % 4 == 3 then return -z-1, -x-1 end end function iTo2Dcoords(j) i = math.floor(j / 4) quadrantI = j % 4 -- 0-3 quadrant counter = 0 -- number of digging spots found j = 0 -- enumerate 2D plane while true do x, z = unpairX(j), unpairZ(j) -- coords in first quadrant x, z = adjustToQuadrant(quadrantI, x, z) -- map coords correctly into other quadrants if isDiggingSpot(x, z) then if counter == i then return x, z end counter = counter + 1 end j = j + 1 end end function digSafe(inspectAction, digAction) while true do local status, block = inspectAction() if status then if block["name"]:lower():find("turtle") then -- turtle in front of me. its free space break else digAction() -- gravel may take time to fall. sleep(1) end else -- No block in front of me. good break end end end -- move safely into the direction, not hurting other turtles, but freeing the path if needed. function moveSafe(moveAction, inspectAction, digAction) while true do local status, block = inspectAction() if status then if block["name"]:lower():find("turtle") then -- turtle in front of me. lets wait for it to move sleep(0.6) elseif block["name"]:lower():find("water") or block["name"]:lower():find("lava") then if moveAction() then break else digAction() updateState({ state = "I am stuck trying to walk into a liquid." }) end else digAction() end else -- nothing in the way, try to move if moveAction() then break end end end end -- If the block in front of the turtle is desired, take it. function grabOres() local status, block = turtle.inspect() if status and block["name"]:lower():find("ore") then ore = block["name"]:lower() if turtlestate["ores"][ore] then turtlestate["ores"][ore] = turtlestate["ores"][ore] + 1 else turtlestate["ores"][ore] = 1 end turtle.dig() end end -- dig all the way down to bedrock, collect ores -- Parameters: -- * moveAction: the **vertical** move action, eg turtle.down -- * digAction: the **vertical** dig action, eg turtle.digDown -- * inpectAction: the **vertical** inspect action, eg turtle.inspectDown -- * limit: if >= 0 * the number of blocks to dig -- * dig until bedrock is hit -- -- -- Returns: the depth dug function digDeep(moveAction, digAction, inspectAction, limit) local depth = 0 grabOres() while true do -- termination condition: -- * if limit != -1: limit > 0 -- * otherwise : bedrock beneath if limit < 0 then local status, nextblock = inspectAction() if status and nextblock["name"] == "minecraft:bedrock" then return depth end else if limit == 0 then return depth end end -- Limit not reached: keep digging depth = depth + 1 limit = limit - 1 digAction() moveAction() grabOres() -- inspect block in front of turtle, take if neccessary end end function selectCobble() for i = 1,16 do turtle.select(i) item = turtle.getItemDetail() if item and item["name"] == "minecraft:cobblestone" then break end end end function selectFuel() for i = 1,16 do turtle.select(i) item = turtle.getItemDetail() if item and (item["name"] == "minecraft:coal" or item["name"] == "minecraft:charcoal") then break end end end function digShaft() --turtle.digDown() --selectCobble() --turtle.placeUp() moveSafe(turtle.down, turtle.inspectDown, turtle.digDown) --turtle.down() depth = digDeep(turtle.down, turtle.digDown, turtle.inspectDown, -1) turtle.turnLeft() digDeep(turtle.up, turtle.digUp, turtle.inspectUp, depth) turtle.turnLeft() digDeep(turtle.down, turtle.digDown, turtle.inspectDown, depth) turtle.turnLeft() digDeep(turtle.up, turtle.digUp, turtle.inspectUp, depth) turtle.turnLeft() selectCobble() turtle.up() turtle.placeDown() --turtle.digUp() --turtle.up() --faceDir(0) end function digTo(x, z) --print("Digging to rel. coord ("..tostring(x)..", "..tostring(z)..")") while z > 0 do moveSafe(turtle.forward, turtle.inspect, turtle.dig) z = z - 1 repeat sleep(0.6) until (not turtle.digUp()) end turtle.turnRight() while x > 0 do moveSafe(turtle.forward, turtle.inspect, turtle.dig) x = x - 1 repeat sleep(0.6) until (not turtle.digUp()) end end function goToSpawn(x, z) moveSafe(turtle.up, turtle.inspectUp, turtle.digUp) while z > 0 do moveSafe(turtle.forward, turtle.inspect, turtle.dig) z = z - 1 end turtle.turnRight() while x > 0 do moveSafe(turtle.forward, turtle.inspect, turtle.dig) x = x - 1 end end function moveSafeForward() moveSafe(turtle.forward, turtle.inspect, noop) end function goToBarrel(path) if path == 0 then turtle.turnLeft() moveSafe(turtle.forward, turtle.inspect, noop) turtle.turnRight() moveSafe(turtle.forward, turtle.inspect, noop) moveSafe(turtle.forward, turtle.inspect, noop) moveSafe(turtle.forward, turtle.inspect, noop) moveSafe(turtle.forward, turtle.inspect, noop) moveSafe(turtle.forward, turtle.inspect, noop) turtle.turnRight() moveSafe(turtle.forward, turtle.inspect, noop) moveSafe(turtle.forward, turtle.inspect, noop) moveSafe(turtle.down, turtle.inspectDown, noop) else moveSafe(turtle.forward, turtle.inspect, noop) turtle.turnRight() moveSafe(turtle.forward, turtle.inspect, noop) turtle.turnLeft() moveSafe(turtle.forward, turtle.inspect, noop) moveSafe(turtle.forward, turtle.inspect, noop) moveSafe(turtle.forward, turtle.inspect, noop) moveSafe(turtle.down, turtle.inspectDown, noop) turtle.turnRight() end end function leaveBarrel(path) if path == 0 then moveSafe(turtle.forward, turtle.inspect, noop) moveSafe(turtle.forward, turtle.inspect, noop) moveSafe(turtle.forward, turtle.inspect, noop) turtle.turnRight() moveSafe(turtle.forward, turtle.inspect, noop) moveSafe(turtle.forward, turtle.inspect, noop) turtle.turnRight() else moveSafe(turtle.forward, turtle.inspect, noop) moveSafe(turtle.forward, turtle.inspect, noop) moveSafe(turtle.forward, turtle.inspect, noop) turtle.turnRight() moveSafe(turtle.forward, turtle.inspect, noop) turtle.turnRight() end end function reportDuty(id, fuelconsumed) moveSafe(turtle.down, turtle.inspectDown, noop) moveSafe(turtle.down, turtle.inspectDown, noop) moveSafe(turtle.down, turtle.inspectDown, noop) moveSafeForward() moveSafeForward() moveSafeForward() moveSafeForward() moveSafeForward() moveSafeForward() moveSafeForward() moveSafeForward() rednet.open("bottom") --print("Proto: Sending completed Job id") rednet.broadcast(tostring(id), "jobs") sleep(0.6) --print("Proto: Sending fuel status") rednet.broadcast(tostring(fuelconsumed), "fuel") while true do --print("Proto: Awaiting thanks") sender, message, proto = rednet.receive("jobcomplete") if message == "thanks" then break else sleep(1) end end --print("Proto: Received thanks") end function enqueueTurtle() moveSafe(turtle.up, turtle.inspectUp, noop) moveSafe(turtle.up, turtle.inspectUp, noop) moveSafe(turtle.up, turtle.inspectUp, noop) turtle.turnLeft() moveSafeForward() moveSafeForward() moveSafeForward() turtle.turnRight() while true do local status, block = turtle.inspectDown() if not status then if turtle.down() then break -- we moved in line end else if turtle.forward() then -- pass, thats ok else local status, block = turtle.inspect() if status and not block["name"]:lower():find("turtle") then turtle.dig() turtle.forward() turtle.digUp() turtle.digDown() end end end end -- we moved into line turtle.turnLeft() turtle.turnLeft() end function doRefuel() moveSafeForward() turtle.turnRight() while turtle.getFuelLevel() < 1500 do turtle.suck(4) selectFuel() turtle.refuel() end turtle.turnLeft() end function goToJob() moveSafeForward() moveSafeForward() moveSafeForward() end function waitForJob() --print("Waiting for job...") while true do status, block = turtle.inspectDown() if status and block["name"] == "computercraft:wired_modem_full" then break else moveSafeForward() end end rednet.open("bottom") local retrying = false while true do rednet.broadcast("gibjob", "jobs") sender, message, proto = rednet.receive("newjob", 2) if message then job = tonumber(message) --print("Received job "..tostring(job)) return job else if not retrying then retrying = true --print("No job received. I will keep retrying.") turtlestate["state"] = "Waiting for job... (retrying)" end end end end function emptyToBarrel() sleep(0.4) for i = 1,16 do turtle.select(i) sleep(0.1) turtle.dropDown() end end function drawStatus() print("Turtle ("..tostring(turtlestate["id"])..")") print() print(" \""..turtlestate["name"].."\"") print() if turtlestate["job"] then print("Current job: "..tostring(turtlestate["job"])) else print("Current job: -") end print() if turtlestate["startfuel"] then print("Starting Fuel: "..tostring(turtlestate["startfuel"])) else print("Starting Fuel: ") end if turtlestate["job"] then print("Recent fuel usage: "..tostring(turtlestate["fuel"])) else print("Recent fuel usage: ") end print() print("Status:") print(" "..turtlestate["state"]) if turtlestate["morestate"] then print(" "..turtlestate["morestate"]) else print() end --print(" "..turtlestate["state"]) turtlestate["morestate"] = nil end function turtleAI() while true do turtlestate["state"] = "Waiting for job..." drawStatus() thejob = waitForJob() turtlestate["job"] = thejob turtlestate["state"] = "Refueling..." drawStatus() doRefuel() fuel = turtle.getFuelLevel() turtlestate["state"] = "Headed to the jobsite..." drawStatus() goToJob() x, z = ithSpot(thejob) digTo(x,z) turtlestate["state"] = "Digging the Shaft..." drawStatus() digShaft() turtlestate["state"] = "Returning to the station..." drawStatus() goToSpawn(x, z) path = math.floor(math.random() + 0.5) turtlestate["state"] = "Unloading Inventory..." drawStatus() goToBarrel(path) emptyToBarrel() leaveBarrel(path) fuelconsumed = fuel - turtle.getFuelLevel() --print("I consumed "..tostring(fuelconsumed).." fuel") --print("Reporting Duty") turtlestate["fuel"] = fuelconsumed turtlestate["state"] = "Reporting duty..." drawStatus() reportDuty(thejob, fuelconsumed) turtlestate["job"] = nil turtlestate["state"] = "Going back in line..." drawStatus() enqueueTurtle() end end function updateState(update) for k,v in pairs(update) do turtlestate[k] = v end drawStatus() end function enqueueForJob2() updateState({ state = "Waiting for job..." }) while true do status, block = turtle.inspectDown() if status and block["name"] == "computercraft:wired_modem_full" then break else moveSafeForward() end end turtle.turnLeft() rednet.open("bottom") local retrying = false while true do rednet.broadcast("syn") server, message, proto = rednet.receive(2) -- ACK if not message then retrying = true else rednet.send(server, "gibjob") _, job, _ = rednet.receive() if job then if job == "nojobs" then updateState({ state = "Waiting for job... (retrying)" }) sleep(3) else updateState({ state = "I was assigned job "..job }) return tonumber(job) end end end end end function faceDir(dir) if ((direction - dir) % 4 == 2) then turtle.turnRight() turtle.turnRight() direction = (direction + 2) % 4 elseif ((direction - dir) % 4 == 1) then turtle.turnLeft() direction = (direction -1) % 4 elseif ((direction - dir) % 4 == 3) then turtle.turnRight() direction = (direction + 1) % 4 end end -- directions: 0, 1, 2, 3 -> x, z, -x, -z function goToCoordXZ2(targetX, targetZ, extraaction) if targetX > x then faceDir(0) while (targetX > x) do moveSafe(turtle.forward, turtle.inspect, turtle.dig) x = x + 1 extraaction() end end if targetX < x then faceDir(2) while (targetX < x) do moveSafe(turtle.forward, turtle.inspect, turtle.dig) x = x - 1 extraaction() end end if targetZ > z then faceDir(1) while (targetZ > z) do moveSafe(turtle.forward, turtle.inspect, turtle.dig) z = z + 1 extraaction() end end if targetZ < z then faceDir(3) while (targetZ < z) do moveSafe(turtle.forward, turtle.inspect, turtle.dig) z = z - 1 extraaction() end end end function goToJob2(job) jobX, jobZ = iTo2Dcoords(job) -- this does all the magic updateState({ state = "Going on the job...", morestate = "Jobsite is at ("..tostring(jobX)..", "..tostring(jobZ)..")" }) -- move to hole moveSafe(turtle.forward, turtle.inspect, noop) moveSafe(turtle.forward, turtle.inspect, noop) moveSafe(turtle.forward, turtle.inspect, noop) -- reset coords, descend x, z, direction = 0, 0, 0 moveSafe(turtle.down, turtle.inspectDown, noop) moveSafe(turtle.down, turtle.inspectDown, noop) moveSafe(turtle.down, turtle.inspectDown, noop) -- go to job function extraaction() digSafe(turtle.inspectUp, turtle.digUp) end goToCoordXZ2(jobX, jobZ, extraaction) end function unloadStuffs() updateState({ state = "Now unloading..." }) sleep(0.4) for i = 1,16 do turtle.select(i) sleep(0.1) turtle.drop() end end function doRefuel2() moveSafe(turtle.forward, turtle.inspect, noop) moveSafe(turtle.forward, turtle.inspect, noop) moveSafe(turtle.forward, turtle.inspect, noop) curfuel = turtle.getFuelLevel() targetfuel = 1500 if turtlestate["fuel"] ~= "" then targetfuel = 4 * turtlestate["fuel"] end if curfuel > targetfuel then return end updateState({ state = "Refueling... "..tostring(curfuel).." -> "..tostring(targetfuel) }) coalneeded = math.ceil((targetfuel - curfuel) / 80) turtle.select(1) while turtle.getFuelLevel() < targetfuel do grabnow = math.min(coalneeded, 64) if turtle.suckDown(grabnow) then -- turtle can grab turtle.refuel() coalneeded = coalneeded - grabnow else -- blabla error updateState({ state = "Refueling... Error: Out of coal" }) sleep(5) end end updateState({ startfuel = turtle.getFuelLevel() }) print(turtlestate["startfuel"]) sleep(4) end slots = { {7,-6}, {7, -7}, {7, -8}, {7,-5}, {7,-4} } function goToUnloading() updateState({ state = "Going to unload resources..." }) moveSafe(turtle.up, turtle.inspectUp, turtle.digUp) goToCoordXZ2(7, -6, noop) moveSafe(turtle.up, turtle.inspectUp, turtle.digUp) slot = math.random(5) storageX, storageZ = slots[slot][1], slots[slot][2] goToCoordXZ2(storageX, storageZ, noop) moveSafe(turtle.up, turtle.inspectUp, turtle.digUp) faceDir(2) moveSafe(turtle.forward, turtle.inspect, noop) end function reportDuty2() updateState({ state = "Returning to report duty..." }) moveSafe(turtle.up, turtle.inspectUp, noop) moveSafe(turtle.up, turtle.inspectUp, noop) moveSafe(turtle.up, turtle.inspectUp, noop) moveSafe(turtle.up, turtle.inspectUp, noop) for i = 1,12 do moveSafeForward() end rednet.open("top") id = turtlestate["job"] fuelconsumed = turtlestate["startfuel"] - turtle.getFuelLevel() turtlestate["fuel"] = fuelconsumed rednet.broadcast("syn") server, _, _ = rednet.receive() -- ACK rednet.send(server, "report") rednet.send(server, tostring(id)) rednet.send(server, tostring(fuelconsumed)) for k, v in pairs(turtlestate["ores"]) do rednet.send(server, k) rednet.send(server, v) end turtlestate["ores"] = {} rednet.broadcast("done", "ores") server, _, _ = rednet.receive() -- thanks end function turtleAI2() while true do local job = enqueueForJob2() --turtlestate["job"] = job updateState({ job = job }) doRefuel2() --turtlestate["startfuel"] = turtle.getFuelLevel() goToJob2(job) digShaft() goToUnloading() unloadStuffs() reportDuty2() moveSafe(turtle.down, turtle.inspectDown, noop) moveSafe(turtle.down, turtle.inspectDown, noop) moveSafe(turtle.down, turtle.inspectDown, noop) moveSafe(turtle.down, turtle.inspectDown, noop) turtle.turnLeft() end end -- turtleAI() turtleAI2()