Compare commits
86 Commits
4afa3e68d1
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 479fd0bb4e | |||
|
|
dbd2687ffe | ||
|
|
b8a9ab5342 | ||
|
|
20caa43f8b | ||
|
|
9f60686676 | ||
|
|
8a1f5d0768 | ||
|
|
be2c995f86 | ||
|
|
1b29082bee | ||
|
|
bdc5407326 | ||
|
|
eee0919110 | ||
|
|
41a60f00a3 | ||
|
|
cfb3074158 | ||
|
|
e84d807957 | ||
|
|
035ab99fcc | ||
|
|
477007bc59 | ||
|
|
563ae7dd3c | ||
|
|
88a94caf74 | ||
|
|
7639e0c178 | ||
|
|
6ca1ac6f7b | ||
|
|
86fbf428b2 | ||
|
|
fc0b34731f | ||
|
|
56ab1255e2 | ||
|
|
15e280a1f3 | ||
|
|
004ec6e5d4 | ||
|
|
f5f937fe12 | ||
|
|
4f07fa660b | ||
|
|
343e393780 | ||
|
|
a6a0d9f932 | ||
|
|
5aae3ab55b | ||
|
|
b32923a8fd | ||
|
|
ba6bf5a102 | ||
|
|
3a4aa8bf60 | ||
|
|
8ac0a41981 | ||
|
|
a63a25e5eb | ||
|
|
907dfb569c | ||
|
|
1f765d59a7 | ||
|
|
784106e5b7 | ||
|
|
00d40b5549 | ||
|
|
7689b6d362 | ||
|
|
59856ff0ca | ||
|
|
3151b02dc9 | ||
|
|
2949ba5703 | ||
|
|
390235a2c8 | ||
|
|
f18da2263b | ||
|
|
d35b7e7f62 | ||
|
|
8210503a23 | ||
|
|
e147e1e17d | ||
|
|
9d4bb4b6a8 | ||
|
|
35872227c4 | ||
|
|
4ac7f74be5 | ||
|
|
d754141597 | ||
|
|
14bd8c215d | ||
|
|
d1309c95af | ||
|
|
e64786bb30 | ||
|
|
bdf9d150a6 | ||
|
|
bcbaba516c | ||
|
|
798fcc42a1 | ||
|
|
bd69058208 | ||
|
|
a6948364a0 | ||
|
|
620ffc7ace | ||
|
|
a86af0d0fe | ||
|
|
286625904b | ||
|
|
7f29b499ff | ||
|
|
c08d6e973b | ||
|
|
51287b6d03 | ||
|
|
ee5f4e8f6e | ||
|
|
41894a5542 | ||
|
|
dec935be2d | ||
|
|
7e77588436 | ||
|
|
aa31b4523e | ||
|
|
c8be939ce7 | ||
|
|
b2fa43410f | ||
|
|
444301a915 | ||
|
|
c587099140 | ||
|
|
55779b1b33 | ||
|
|
97f8d86aa1 | ||
|
|
8f396e5027 | ||
|
|
4cfebcbdaa | ||
|
|
b3f659b2b7 | ||
|
|
a5eb903c90 | ||
|
|
8355faffad | ||
|
|
1b0a016222 | ||
|
|
8485ae5f32 | ||
|
|
c01b9304b9 | ||
|
|
b54c2f2257 | ||
|
|
5ac9658c3a |
703
dominic/pairingtool.lua
Normal file
703
dominic/pairingtool.lua
Normal file
@@ -0,0 +1,703 @@
|
||||
args = {...}
|
||||
x, z, direction = 0, 0, 0
|
||||
turtlestate = {
|
||||
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, noop, noop, depth)
|
||||
turtle.turnLeft()
|
||||
digDeep(turtle.down, noop, noop, depth)
|
||||
turtle.turnLeft()
|
||||
digDeep(turtle.up, noop, noop, 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
|
||||
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() })
|
||||
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.ceil(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
|
||||
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()
|
||||
|
||||
for i = 1, 10 do
|
||||
print(iTo2Dcoords(i))
|
||||
end
|
||||
@@ -1,4 +1,5 @@
|
||||
import math
|
||||
import time
|
||||
|
||||
def pair(x, y):
|
||||
return math.floor((x + y) * (x + y + 1)/2 + y)
|
||||
@@ -12,10 +13,18 @@ def unpairZ(z):
|
||||
j = math.floor(math.sqrt(0.25 + 2*z) - 0.5)
|
||||
return z - j * (j+1)/2;
|
||||
|
||||
def unpair2D(j):
|
||||
quadrantI = j % 4 # 0-3 quadrant
|
||||
x, z = int(unpairX(j)), int(unpairZ(j)) # coords in first quadrant
|
||||
x, z = adjustToQuadrant(quadrantI, x, z) # map coords correctly into other quadrants
|
||||
return x, z
|
||||
|
||||
lookup = [-10, 4, 1, 3, 0, 2]
|
||||
def isDiggingSpot(x, y):
|
||||
val = lookup[(y % 5) + 1]
|
||||
return (x % 5) == val
|
||||
x, y = int(x), int(y)
|
||||
val = lookup[(((y % 5)+5)%5) + 1]
|
||||
out = ((x % 5)+ 5) % 5 == val
|
||||
return out
|
||||
|
||||
global offset
|
||||
offset = 10
|
||||
@@ -30,4 +39,48 @@ def ithSpot(i):
|
||||
else:
|
||||
i = i - 1
|
||||
j = j + 1
|
||||
|
||||
def adjustToQuadrant(i, x, z):
|
||||
if i % 4 == 0:
|
||||
return x, z
|
||||
elif i % 4 == 1:
|
||||
return -z-1, x
|
||||
elif i % 4 == 2:
|
||||
return z, -x-1
|
||||
elif i % 4 == 3:
|
||||
return -z-1, -x-1
|
||||
|
||||
def iTo2Dcoords(j):
|
||||
i = j // 4
|
||||
quadrantI = j % 4 # 0-3 quadrant
|
||||
counter = 0 # number of digging spots found
|
||||
j = 0 # enumerate 2D plane
|
||||
while True:
|
||||
x, z = int(unpairX(j)), int(unpairZ(j)) # coords in first quadrant
|
||||
x, z = adjustToQuadrant(quadrantI, x, z) # map coords correctly into other quadrants
|
||||
if isDiggingSpot(x, z):
|
||||
if counter == i:
|
||||
return (x,z)
|
||||
break
|
||||
counter += 1
|
||||
j += 1
|
||||
|
||||
def findIfor(coords):
|
||||
j = 0
|
||||
counter = 0
|
||||
while True:
|
||||
x, z = unpair2D(j)
|
||||
print(j, x, z)
|
||||
if isDiggingSpot(x, z):
|
||||
if (x, z) in coords:
|
||||
print(f"{j} -> {x}, {z}")
|
||||
coords.remove((x,z))
|
||||
counter += 1
|
||||
if not coords:
|
||||
break
|
||||
j += 1
|
||||
time.sleep(0.6)
|
||||
|
||||
findIfor([
|
||||
(4, 0),
|
||||
])
|
||||
|
||||
156
kai/gitgud.lua
Normal file
156
kai/gitgud.lua
Normal file
@@ -0,0 +1,156 @@
|
||||
--[[
|
||||
|
||||
Usages:
|
||||
> gitgud sync <repo path> <local path>
|
||||
download file from repo
|
||||
|
||||
> gitgud delete <local path>
|
||||
delete downloaded file
|
||||
|
||||
> gitgud
|
||||
re-download all synced files
|
||||
|
||||
> gitgud run <repo path>
|
||||
fetch and exec file from repo
|
||||
|
||||
]]
|
||||
|
||||
if not http then error("http is not enabled") end
|
||||
|
||||
local function get(url)
|
||||
local response, err = http.get(url)
|
||||
if not response then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
local status, err = response.getResponseCode()
|
||||
if status ~= 200 then
|
||||
return nil, (status .. " " .. err)
|
||||
end
|
||||
|
||||
local result = response.readAll()
|
||||
response.close()
|
||||
return result
|
||||
end
|
||||
|
||||
local function ensure_dotlua(path)
|
||||
if string.match(path, "%.lua$") then
|
||||
return path
|
||||
else
|
||||
return path .. ".lua"
|
||||
end
|
||||
end
|
||||
|
||||
local function gitea_url(path)
|
||||
return "https://git.leafbla.de/dominic/turtles/raw/branch/master/".. path
|
||||
end
|
||||
|
||||
local function download_file(repo_path, local_path)
|
||||
write("Downloading " .. repo_path .. " as " .. local_path .. "... ")
|
||||
local result, err = get(gitea_url(repo_path))
|
||||
if not result then
|
||||
print()
|
||||
printError(err)
|
||||
return false
|
||||
end
|
||||
|
||||
local f = fs.open(local_path, "w")
|
||||
f.write(result)
|
||||
f.close()
|
||||
|
||||
print("OK")
|
||||
return true
|
||||
end
|
||||
|
||||
-- keep track of downloaded files
|
||||
local storage_path = ".gitgud"
|
||||
|
||||
local storage = {}
|
||||
if fs.exists(storage_path) then
|
||||
local f = fs.open(storage_path, "r")
|
||||
storage = textutils.unserialize(f.readAll())
|
||||
f.close()
|
||||
end
|
||||
|
||||
local function update_storage()
|
||||
local f = fs.open(storage_path, "w")
|
||||
f.write(textutils.serialize(storage))
|
||||
f.close()
|
||||
end
|
||||
|
||||
local args = {...}
|
||||
|
||||
if #args == 0 then
|
||||
|
||||
-- Lua being Lua, of course #storage won't work
|
||||
local count = 0
|
||||
for _ in pairs(storage) do
|
||||
count = count + 1
|
||||
end
|
||||
|
||||
print("Syncing " .. count .. " files.")
|
||||
|
||||
local success_count = 0
|
||||
for local_path, repo_path in pairs(storage) do
|
||||
local success = download_file(repo_path, local_path)
|
||||
if success then
|
||||
success_count = success_count + 1
|
||||
end
|
||||
end
|
||||
|
||||
print("Done. " .. success_count .. " out of " .. count .. " files synced.")
|
||||
|
||||
elseif args[1] == "sync" then
|
||||
local usage = "gitgud sync <repo path> <local path>"
|
||||
local repo_path = args[2] or error(usage)
|
||||
local local_path = args[3] or error(usage)
|
||||
|
||||
repo_path = ensure_dotlua(repo_path)
|
||||
local_path = ensure_dotlua(local_path)
|
||||
|
||||
storage[local_path] = repo_path
|
||||
update_storage()
|
||||
|
||||
download_file(repo_path, local_path)
|
||||
|
||||
elseif args[1] == "delete" then
|
||||
local usage = "gitgud delete <local path>"
|
||||
local local_path = args[2] or error(usage)
|
||||
|
||||
local_path = ensure_dotlua(local_path)
|
||||
|
||||
storage[local_path] = nil
|
||||
update_storage()
|
||||
|
||||
fs.delete(local_path)
|
||||
|
||||
elseif args[1] == "run" then
|
||||
local usage = "gitgud run <repo path> [args...]"
|
||||
local repo_path = args[2] or error(usage)
|
||||
|
||||
repo_path = ensure_dotlua(repo_path)
|
||||
|
||||
write("Downloading " .. repo_path .. "... ")
|
||||
local result, err = get(gitea_url(repo_path))
|
||||
if not result then
|
||||
print()
|
||||
printError(err)
|
||||
else
|
||||
print("OK")
|
||||
end
|
||||
|
||||
local func, err = load(result, repo_path, "t", _ENV)
|
||||
if not func then
|
||||
printError(err)
|
||||
return
|
||||
end
|
||||
local success, err = pcall(func, select(3, ...))
|
||||
if not success then
|
||||
printError(err)
|
||||
end
|
||||
|
||||
else
|
||||
print("Unknown command " .. args[1])
|
||||
print("Try \"sync\", \"delete\" or \"run\"")
|
||||
|
||||
end
|
||||
30
kai/home.lua
Normal file
30
kai/home.lua
Normal file
@@ -0,0 +1,30 @@
|
||||
local T = require("lib")
|
||||
|
||||
local function greedy_move(x, z, o)
|
||||
print("Move Target: " .. x .. "," .. z .. " (" .. o .. ")")
|
||||
if z ~= T.state.z then
|
||||
if z > T.state.z then
|
||||
T.rotateTowards("+z")
|
||||
else
|
||||
T.rotateTowards("-z")
|
||||
end
|
||||
for _ = 1, math.abs(z - T.state.z) do
|
||||
T.fwd()
|
||||
end
|
||||
end
|
||||
|
||||
if x ~= T.state.x then
|
||||
if x > T.state.x then
|
||||
T.rotateTowards("+x")
|
||||
else
|
||||
T.rotateTowards("-x")
|
||||
end
|
||||
for _ = 1, math.abs(x - T.state.x) do
|
||||
T.fwd()
|
||||
end
|
||||
end
|
||||
|
||||
T.rotateTowards(o)
|
||||
end
|
||||
|
||||
greedy_move(0, 0, "+z")
|
||||
135
kai/lib.lua
135
kai/lib.lua
@@ -1,5 +1,5 @@
|
||||
-- Do not lose state when reset (chunkloading etc)
|
||||
state = (function ()
|
||||
local state = (function ()
|
||||
local path = ".state"
|
||||
local state_table = {}
|
||||
|
||||
@@ -21,6 +21,32 @@ state = (function ()
|
||||
})
|
||||
end)()
|
||||
|
||||
-- Not sure whether this is a good idea
|
||||
--[[
|
||||
if state.x == nil or state.y == nil or state.z == nil or state.o == nil then
|
||||
printError("[lib] position is not set")
|
||||
printError("[lib] defaulting to 0, 0, 0, +z")
|
||||
state.x = 0
|
||||
state.y = 0
|
||||
state.z = 0
|
||||
state.o = 0
|
||||
end
|
||||
]]
|
||||
|
||||
local function setPosition(x, y, z, direction)
|
||||
local o = ({
|
||||
["+z"] = 0,
|
||||
["-x"] = 1,
|
||||
["-z"] = 2,
|
||||
["+x"] = 3,
|
||||
})[direction]
|
||||
|
||||
state.x = x
|
||||
state.y = y
|
||||
state.z = z
|
||||
state.o = o
|
||||
end
|
||||
|
||||
--[[
|
||||
orientation:
|
||||
0 = South (+z)
|
||||
@@ -29,48 +55,91 @@ end)()
|
||||
3 = East (+x)
|
||||
]]
|
||||
|
||||
function move(raw_move, position_update)
|
||||
local function move(raw_move, position_update)
|
||||
return function()
|
||||
success, err = raw_move()
|
||||
local success, err = raw_move()
|
||||
if not success then
|
||||
return false, err
|
||||
end
|
||||
position_update()
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local fwd = move(turtle.forward, function()
|
||||
if state.o == 1 or state.o == 3 then
|
||||
state.x = state.x + ((state.o == 1) and -1 or 1)
|
||||
elseif state.o == 0 or state.o == 2 then
|
||||
state.z = state.z + ((state.o == 2) and -1 or 1)
|
||||
end
|
||||
end)
|
||||
|
||||
local back = move(turtle.back, function()
|
||||
if state.o == 1 or state.o == 3 then
|
||||
state.x = state.x + ((state.o == 1 and 1 or -1))
|
||||
elseif state.o == 0 or state.o == 2 then
|
||||
state.z = state.z + ((state.o == 2) and 1 or -1)
|
||||
end
|
||||
end)
|
||||
|
||||
local up = move(turtle.up, function()
|
||||
state.y = state.y + 1
|
||||
end)
|
||||
|
||||
local down = move(turtle.down, function()
|
||||
state.y = state.y - 1
|
||||
end)
|
||||
|
||||
local left = move(turtle.turnLeft, function()
|
||||
state.o = (state.o - 1) % 4
|
||||
end)
|
||||
|
||||
local right = move(turtle.turnRight, function()
|
||||
state.o = (state.o + 1) % 4
|
||||
end)
|
||||
|
||||
local function getOrientation()
|
||||
return ({"+z", "-x", "-z", "+x"})[1 + state.o]
|
||||
end
|
||||
|
||||
local function rotateTowards(direction)
|
||||
local target_o = ({
|
||||
["+z"] = 0,
|
||||
["-x"] = 1,
|
||||
["-z"] = 2,
|
||||
["+x"] = 3,
|
||||
})[direction]
|
||||
|
||||
if not target_o then
|
||||
error(tostring(direction) .. " is not a valid direction.")
|
||||
end
|
||||
|
||||
local delta_o = (target_o - state.o) % 4
|
||||
|
||||
if delta_o == 0 then
|
||||
-- orientation already correct
|
||||
elseif delta_o == 1 then
|
||||
right()
|
||||
elseif delta_o == 2 then
|
||||
right()
|
||||
right()
|
||||
elseif delta_o == 3 then
|
||||
left()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return {
|
||||
state = state,
|
||||
|
||||
fwd = move(turtle.forward, function()
|
||||
if state.o == 1 or state.o == 3 then
|
||||
state.x = state.x + ((state.o == 1) and -1 or 1)
|
||||
else
|
||||
state.z = state.z + ((state.o == 2) and -1 or 1)
|
||||
end
|
||||
end),
|
||||
fwd = fwd,
|
||||
back = back,
|
||||
up = up,
|
||||
down = down,
|
||||
left = left,
|
||||
right = right,
|
||||
|
||||
back = move(turtle.back, function()
|
||||
if state.o == 1 or state.o == 3 then
|
||||
state.x = state.x + ((state.o == 1 and 1 or -1))
|
||||
else
|
||||
state.z = state.z + ((state.o == 2) and 1 or -1)
|
||||
end
|
||||
end),
|
||||
|
||||
up = move(turtle.up, function()
|
||||
state.y = state.y + 1
|
||||
end),
|
||||
|
||||
down = move(turtle.down, function()
|
||||
state.y = state.y - 1
|
||||
end),
|
||||
|
||||
left = move(turtle.turnLeft, function()
|
||||
state.o = (state.o - 1) % 4
|
||||
end),
|
||||
|
||||
right = move(turtle.turnRight, function()
|
||||
state.o = (state.o + 1) % 4
|
||||
end),
|
||||
setPosition = setPosition,
|
||||
getOrientation = getOrientation,
|
||||
rotateTowards = rotateTowards,
|
||||
}
|
||||
260
kai/woodfarm.lua
Normal file
260
kai/woodfarm.lua
Normal file
@@ -0,0 +1,260 @@
|
||||
local T = require("lib")
|
||||
|
||||
--[[
|
||||
|
||||
States:
|
||||
- MOVE_TO_TREE
|
||||
- CHECK_TREE
|
||||
- ASCEND_TREE
|
||||
- FINALIZE_TREE
|
||||
- OUTPUT
|
||||
- RESUPPLY_SAPS
|
||||
- RESUPPLY_FUEL
|
||||
|
||||
Persistent Variables:
|
||||
- current_state
|
||||
- current_tree [1,14]
|
||||
- current_row [1,6]
|
||||
|
||||
Inventory:
|
||||
64 + 20 Saplings in Slots 1 and 2
|
||||
|
||||
]]
|
||||
|
||||
local MAX_TREE = 14
|
||||
local MAX_ROW = 6
|
||||
|
||||
local OUTPUT_TARGET = { x = 2, z = 0, o = "+z" }
|
||||
local SAPS_TARGET = { x = 1, z = 0, o = "+z" }
|
||||
local FUEL_TARGET = { x = 0, z = 0, o = "+z" }
|
||||
|
||||
local TREE_MAX_HEIGHT = 7
|
||||
-- Saplings are at y = -1 (and coordinates are zero-based)
|
||||
local TREE_MAX_Y = TREE_MAX_HEIGHT - 2
|
||||
local LOG_NAME = "minecraft:birch_log"
|
||||
|
||||
local SAP_SLOT = 1
|
||||
local BACKUP_SAP_SLOT = 2
|
||||
local REFUEL_SLOT = 3
|
||||
|
||||
local SAP_SLOT_TARGET_COUNT = 64
|
||||
local BACKUP_SAP_SLOT_TARGET_COUNT = 20
|
||||
|
||||
-- Should be enough even if every tree is fully grown
|
||||
local FUEL_LEVEL_TARGET = 1000
|
||||
|
||||
local function calculate_tree_position(row_index, tree_index)
|
||||
|
||||
local x = (row_index - 1) * 5
|
||||
local z
|
||||
|
||||
if row_index % 2 == 1 then
|
||||
z = -2 * tree_index
|
||||
else
|
||||
z = -30 + 2 * tree_index
|
||||
end
|
||||
|
||||
return x, z
|
||||
end
|
||||
|
||||
local function greedy_move(x, z, o)
|
||||
print("Move Target: " .. x .. "," .. z .. " (" .. o .. ")")
|
||||
if z ~= T.state.z then
|
||||
if z > T.state.z then
|
||||
T.rotateTowards("+z")
|
||||
else
|
||||
T.rotateTowards("-z")
|
||||
end
|
||||
for _ = 1, math.abs(z - T.state.z) do
|
||||
while not T.fwd() do
|
||||
sleep(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if x ~= T.state.x then
|
||||
if x > T.state.x then
|
||||
T.rotateTowards("+x")
|
||||
else
|
||||
T.rotateTowards("-x")
|
||||
end
|
||||
for _ = 1, math.abs(x - T.state.x) do
|
||||
while not T.fwd() do
|
||||
sleep(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
T.rotateTowards(o)
|
||||
end
|
||||
|
||||
local function ensure_item_count(count)
|
||||
if turtle.getItemCount() >= count then
|
||||
return
|
||||
end
|
||||
turtle.suck(count - turtle.getItemCount())
|
||||
-- turtle.suck might not suck enough items if the target container does not have them
|
||||
-- but it won't tell us if this happened...
|
||||
while turtle.getItemCount() ~= count do
|
||||
sleep(1)
|
||||
turtle.suck(count - turtle.getItemCount())
|
||||
end
|
||||
end
|
||||
|
||||
local state_machine = {
|
||||
|
||||
["MOVE_TO_TREE"] = function()
|
||||
-- get target tree coordinates
|
||||
-- and move such that we are facing it
|
||||
local x, z = calculate_tree_position(T.state.current_row, T.state.current_tree)
|
||||
local o
|
||||
|
||||
if T.state.current_row ~= 1 and T.state.current_tree == 1 then
|
||||
-- we just turned towards a new row and are approaching in positive x direction
|
||||
x = x - 1
|
||||
o = "+x"
|
||||
elseif T.state.current_row % 2 == 0 then
|
||||
-- we are in an even row and approaching in positive z direction
|
||||
z = z - 1
|
||||
o = "+z"
|
||||
else
|
||||
-- we are approaching in negative z direction
|
||||
z = z + 1
|
||||
o = "-z"
|
||||
end
|
||||
|
||||
greedy_move(x, z, o)
|
||||
return "CHECK_TREE"
|
||||
end,
|
||||
|
||||
["CHECK_TREE"] = function()
|
||||
if not turtle.detect() then
|
||||
-- no tree, so skip ascending
|
||||
T.fwd()
|
||||
return "FINALIZE_TREE"
|
||||
else
|
||||
-- tree present, chop it down
|
||||
turtle.dig()
|
||||
T.fwd()
|
||||
turtle.digDown()
|
||||
return "ASCEND_TREE"
|
||||
end
|
||||
end,
|
||||
|
||||
["ASCEND_TREE"] = function()
|
||||
local success, data = turtle.inspectUp()
|
||||
if not success and T.state.y < TREE_MAX_Y - 1 then
|
||||
-- probably reset after chopping a block
|
||||
T.up()
|
||||
end
|
||||
|
||||
while true do
|
||||
local success, data = turtle.inspectUp()
|
||||
if not success or data.name ~= LOG_NAME then
|
||||
-- chopped all the wood
|
||||
break
|
||||
end
|
||||
turtle.digUp()
|
||||
if T.state.y == TREE_MAX_Y - 1 then
|
||||
-- we are below the last log, no need to move up
|
||||
break
|
||||
end
|
||||
T.up()
|
||||
end
|
||||
return "FINALIZE_TREE"
|
||||
end,
|
||||
|
||||
["FINALIZE_TREE"] = function()
|
||||
-- make sure we are directly above the sapling target
|
||||
while T.state.y > 0 do
|
||||
while not T.down() do
|
||||
-- another tree might have spawned leaves below us
|
||||
turtle.digDown()
|
||||
end
|
||||
end
|
||||
|
||||
turtle.select(SAP_SLOT)
|
||||
-- make sure we have a sapling
|
||||
if turtle.getItemCount() == 0 then
|
||||
turtle.select(BACKUP_SAP_SLOT)
|
||||
turtle.transferTo(SAP_SLOT)
|
||||
turtle.select(SAP_SLOT)
|
||||
end
|
||||
turtle.placeDown()
|
||||
|
||||
if T.state.current_tree < MAX_TREE then
|
||||
-- go to the next tree in this row
|
||||
T.state.current_tree = T.state.current_tree + 1
|
||||
return "MOVE_TO_TREE"
|
||||
elseif T.state.current_row < MAX_ROW then
|
||||
-- go to the first tree in the next row
|
||||
T.state.current_tree = 1
|
||||
T.state.current_row = T.state.current_row + 1
|
||||
return "MOVE_TO_TREE"
|
||||
else
|
||||
-- went through the entire farm once
|
||||
return "OUTPUT"
|
||||
end
|
||||
end,
|
||||
|
||||
["OUTPUT"] = function()
|
||||
|
||||
greedy_move(OUTPUT_TARGET.x, OUTPUT_TARGET.z, OUTPUT_TARGET.o)
|
||||
|
||||
-- Drop all logs
|
||||
for slot = 1, 16 do
|
||||
turtle.select(slot)
|
||||
data = turtle.getItemDetail()
|
||||
if data and data.name == LOG_NAME then
|
||||
turtle.drop()
|
||||
end
|
||||
end
|
||||
|
||||
return "RESUPPLY_SAPS"
|
||||
end,
|
||||
|
||||
["RESUPPLY_SAPS"] = function()
|
||||
|
||||
greedy_move(SAPS_TARGET.x, SAPS_TARGET.z, SAPS_TARGET.o)
|
||||
|
||||
turtle.select(SAP_SLOT)
|
||||
ensure_item_count(SAP_SLOT_TARGET_COUNT)
|
||||
|
||||
turtle.select(BACKUP_SAP_SLOT)
|
||||
ensure_item_count(BACKUP_SAP_SLOT_TARGET_COUNT)
|
||||
|
||||
return "RESUPPLY_FUEL"
|
||||
end,
|
||||
|
||||
["RESUPPLY_FUEL"] = function()
|
||||
|
||||
greedy_move(FUEL_TARGET.x, FUEL_TARGET.z, FUEL_TARGET.o)
|
||||
|
||||
if turtle.getFuelLevel() < FUEL_LEVEL_TARGET then
|
||||
local fuel_count = math.ceil((FUEL_LEVEL_TARGET - turtle.getFuelLevel()) / 80)
|
||||
turtle.select(REFUEL_SLOT)
|
||||
ensure_item_count(fuel_count)
|
||||
turtle.refuel()
|
||||
end
|
||||
|
||||
T.state.current_row = 1
|
||||
T.state.current_tree = 1
|
||||
return "MOVE_TO_TREE"
|
||||
end,
|
||||
|
||||
}
|
||||
|
||||
-- initial setup
|
||||
|
||||
if not T.state.current_state then
|
||||
T.setPosition(0, 0, 0, "+z")
|
||||
T.state.current_state = "RESUPPLY_FUEL"
|
||||
end
|
||||
|
||||
-- main loop
|
||||
while true do
|
||||
print("---------------")
|
||||
print("State: " .. T.state.current_state)
|
||||
print("Pos: " .. T.state.x .. "," .. T.state.z .. "(" .. T.getOrientation() .. ")")
|
||||
T.state.current_state = state_machine[T.state.current_state]()
|
||||
end
|
||||
211
mine/client.lua
211
mine/client.lua
@@ -1,11 +1,13 @@
|
||||
args = {...}
|
||||
x, z, direction = 0, 0, 0
|
||||
turtlestate = {
|
||||
startfuel = 0,
|
||||
name = os.getComputerLabel(),
|
||||
id = os.getComputerID(),
|
||||
fuel = "",
|
||||
state = "init",
|
||||
job = nil
|
||||
job = nil,
|
||||
ores = {}
|
||||
}
|
||||
|
||||
function noop() end
|
||||
@@ -83,7 +85,7 @@ function digSafe(inspectAction, digAction)
|
||||
if status then
|
||||
if block["name"]:lower():find("turtle") then
|
||||
-- turtle in front of me. its free space
|
||||
return true
|
||||
break
|
||||
else
|
||||
digAction()
|
||||
-- gravel may take time to fall.
|
||||
@@ -91,7 +93,7 @@ function digSafe(inspectAction, digAction)
|
||||
end
|
||||
else
|
||||
-- No block in front of me. good
|
||||
return true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -104,6 +106,13 @@ function moveSafe(moveAction, inspectAction, digAction)
|
||||
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
|
||||
@@ -120,6 +129,12 @@ end
|
||||
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
|
||||
@@ -181,22 +196,25 @@ function selectFuel()
|
||||
end
|
||||
|
||||
function digShaft()
|
||||
turtle.digDown()
|
||||
selectCobble()
|
||||
turtle.placeUp()
|
||||
turtle.down()
|
||||
--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, noop, noop, depth)
|
||||
digDeep(turtle.up, turtle.digUp, turtle.inspectUp, depth)
|
||||
turtle.turnLeft()
|
||||
digDeep(turtle.down, noop, noop, depth)
|
||||
digDeep(turtle.down, turtle.digDown, turtle.inspectDown, depth)
|
||||
turtle.turnLeft()
|
||||
digDeep(turtle.up, turtle.digUp, turtle.inspectUp, depth)
|
||||
turtle.turnLeft()
|
||||
digDeep(turtle.up, noop, noop, depth)
|
||||
selectCobble()
|
||||
turtle.up()
|
||||
turtle.placeDown()
|
||||
turtle.up()
|
||||
turtle.digUp()
|
||||
turtle.up()
|
||||
--turtle.digUp()
|
||||
--turtle.up()
|
||||
--faceDir(0)
|
||||
end
|
||||
|
||||
function digTo(x, z)
|
||||
@@ -403,13 +421,17 @@ function drawStatus()
|
||||
print()
|
||||
print(" \""..turtlestate["name"].."\"")
|
||||
print()
|
||||
print()
|
||||
if turtlestate["job"] then
|
||||
print("Current job: "..tostring(turtlestate["job"]))
|
||||
else
|
||||
print("Current job: ")
|
||||
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
|
||||
@@ -418,7 +440,13 @@ function drawStatus()
|
||||
print()
|
||||
print("Status:")
|
||||
print(" "..turtlestate["state"])
|
||||
print()
|
||||
if turtlestate["morestate"] then
|
||||
print(" "..turtlestate["morestate"])
|
||||
else
|
||||
print()
|
||||
end
|
||||
--print(" "..turtlestate["state"])
|
||||
turtlestate["morestate"] = nil
|
||||
end
|
||||
|
||||
function turtleAI()
|
||||
@@ -481,19 +509,24 @@ function enqueueForJob2()
|
||||
end
|
||||
turtle.turnLeft()
|
||||
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)
|
||||
return job
|
||||
rednet.broadcast("syn")
|
||||
server, message, proto = rednet.receive(2) -- ACK
|
||||
if not message then
|
||||
retrying = true
|
||||
else
|
||||
if not retrying then
|
||||
retrying = true
|
||||
--print("No job received. I will keep retrying.")
|
||||
--turtlestate["state"] = "Waiting for job... (retrying)"
|
||||
updateState({ state = "Waiting for job... (retrying)" })
|
||||
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
|
||||
@@ -513,7 +546,7 @@ function faceDir(dir)
|
||||
end
|
||||
end
|
||||
-- directions: 0, 1, 2, 3 -> x, z, -x, -z
|
||||
function goToCoordXZ(targetX, targetZ, extraaction)
|
||||
function goToCoordXZ2(targetX, targetZ, extraaction)
|
||||
if targetX > x then
|
||||
faceDir(0)
|
||||
while (targetX > x) do
|
||||
@@ -548,41 +581,127 @@ function goToCoordXZ(targetX, targetZ, extraaction)
|
||||
end
|
||||
end
|
||||
|
||||
function goToJob(job)
|
||||
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)..")" })
|
||||
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)
|
||||
moveSafe(turtle.forward, turtle.inspect, noop)
|
||||
moveSafe(turtle.forward, turtle.inspect, noop)
|
||||
moveSafe(turtle.forward, turtle.inspect, noop)
|
||||
-- reset coords, descend
|
||||
x, z = 0, 0
|
||||
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()
|
||||
repeat sleep(0.6) until (not digSafe(turtle.inspectUp, turtle.digUp()))
|
||||
digSafe(turtle.inspectUp, turtle.digUp)
|
||||
end
|
||||
goToCoord(jobX, jobZ, extraaction)
|
||||
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"])
|
||||
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()
|
||||
goToJob(job)
|
||||
-- returnToQueue()
|
||||
break
|
||||
--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
|
||||
|
||||
function extraaction()
|
||||
repeat sleep(0.6) until (not digSafe(turtle.inspectUp, turtle.digUp()))
|
||||
end
|
||||
-- turtleAI()
|
||||
faceDir(3)
|
||||
goToCoordXZ(4, 2, extraaction)
|
||||
goToCoordXZ(0, 0, extraaction)
|
||||
goToCoordXZ(4, 2, extraaction)
|
||||
|
||||
turtleAI2()
|
||||
|
||||
130
mine/server.lua
130
mine/server.lua
@@ -1,46 +1,118 @@
|
||||
rednet.open("back")
|
||||
|
||||
state = {}
|
||||
ores = {}
|
||||
|
||||
thelog = {"", "", "", "", "", ""}
|
||||
logsize = 6
|
||||
logpos = 1
|
||||
|
||||
curjob = 69
|
||||
while true do
|
||||
print("From what index do you want to resume jobs?")
|
||||
x = read()
|
||||
if tonumber(x) then
|
||||
curjob = tonumber(x)
|
||||
break
|
||||
end
|
||||
print("That's not a number.")
|
||||
end
|
||||
firstjob = nil
|
||||
totalfuel = 0
|
||||
|
||||
|
||||
function getNextJob()
|
||||
curjob = curjob + 1
|
||||
return curjob - 1
|
||||
end
|
||||
|
||||
function getOres(ore)
|
||||
return ores[ore] or 0
|
||||
end
|
||||
|
||||
function drawState()
|
||||
-- server has 19x50 terminal
|
||||
print(" [ Server Control Panel ]")
|
||||
print()
|
||||
print(" First Job: "..tostring(firstjob))
|
||||
print(" Current Job: "..tostring(curjob))
|
||||
print(" Fuel consumed: "..tostring(totalfuel).." ("..tostring(math.ceil(totalfuel/80))..")")
|
||||
print()
|
||||
n1 = tostring(getOres("minecraft:coal_ore"))
|
||||
n2 = tostring(getOres("minecraft:iron_ore"))
|
||||
n3 = tostring(getOres("minecraft:gold_ore"))
|
||||
n4 = tostring(getOres("minecraft:lapis_ore"))
|
||||
n5 = tostring(getOres("minecraft:redstone_ore"))
|
||||
n6 = tostring(getOres("minecraft:emerald_ore"))
|
||||
n7 = tostring(getOres("minecraft:diamond_ore"))
|
||||
n8 = tostring(getOres("mekanism:tin_ore"))
|
||||
n9 = tostring(getOres("mekanism:copper_ore"))
|
||||
n10 = tostring(getOres("mekanism:osmium_ore"))
|
||||
n11 = tostring(getOres("create:zinc_ore"))
|
||||
n12 = tostring(getOres("create:copper_ore"))
|
||||
print(" C I G "..n1.." "..n2.." "..n3)
|
||||
print(" L R E D "..n4.." "..n5.." "..n6.." "..n7)
|
||||
print(" T C O "..n8.." "..n9.." "..n10)
|
||||
print(" Z C "..n11.." "..n12)
|
||||
print()
|
||||
print("--------------------------------------------------")
|
||||
for i = logpos, (logpos + logsize - 1) do
|
||||
print(thelog[((i-1) % logsize)+1]) -- map from 0..n-1 to 1..n
|
||||
end
|
||||
end
|
||||
|
||||
function log(s)
|
||||
thelog[logpos] = s
|
||||
logpos = (logpos + 1) % logsize
|
||||
logpos = ((logpos - 1) % logsize ) + 1
|
||||
drawState()
|
||||
end
|
||||
|
||||
while true do
|
||||
sender, message, proto = rednet.receive("jobs")
|
||||
log("From what index do you want to resume jobs?")
|
||||
x = read()
|
||||
if tonumber(x) then
|
||||
curjob = tonumber(x)
|
||||
firstjob = tonumber(x)
|
||||
break
|
||||
end
|
||||
log("That's not a number.")
|
||||
end
|
||||
|
||||
while true do
|
||||
sender, message, proto = rednet.receive()
|
||||
if not message then
|
||||
sleep(0.6)
|
||||
else
|
||||
--print("> raw: "..message)
|
||||
if message == "gibjob" then
|
||||
if rs.getInput("right") then
|
||||
job = getNextJob()
|
||||
rednet.broadcast(tostring(job), "newjob")
|
||||
print("Found job request. Offering "..tostring(job))
|
||||
if message == "syn" then
|
||||
receiver = sender
|
||||
rednet.send(receiver, "ack")
|
||||
_, message, _ = rednet.receive()
|
||||
if message then
|
||||
if message == "gibjob" then
|
||||
if rs.getInput("top") then
|
||||
job = getNextJob()
|
||||
rednet.send(receiver, tostring(job))
|
||||
log("Found job request. Offering "..tostring(job))
|
||||
else
|
||||
rednet.send(receiver, "nojobs")
|
||||
end
|
||||
drawState()
|
||||
elseif message == "report" then
|
||||
_, job, _ = rednet.receive()
|
||||
thejob = tonumber(job)
|
||||
_, fuel, _ = rednet.receive()
|
||||
thefuel = tonumber(fuel)
|
||||
totalfuel = totalfuel + thefuel
|
||||
while true do
|
||||
_, ore, _ = rednet.receive()
|
||||
if ore == "done" then
|
||||
break
|
||||
end
|
||||
_, number, _ = rednet.receive()
|
||||
--thenumber = tonumber(thenumber)
|
||||
if ores[ore] then
|
||||
ores[ore] = ores[ore] + tonumber(number)
|
||||
else
|
||||
ores[ore] = tonumber(number)
|
||||
end
|
||||
end
|
||||
log("Job "..thejob.." has been completed")
|
||||
drawState()
|
||||
rednet.send(receiver, "thanks")
|
||||
end
|
||||
end
|
||||
else
|
||||
-- numberic job is complete
|
||||
completejob = tonumber(message)
|
||||
fuelused = "??"
|
||||
fuelsender, fuelmessage, fuelproto = rednet.receive("fuel")
|
||||
if fuelmessage then
|
||||
fuelused = fuelmessage
|
||||
end
|
||||
print("Job "..tostring(completejob).." was completed, "..fuelused.." fuel was used")
|
||||
rednet.broadcast("thanks", "jobcomplete")
|
||||
log = io.open("jobs.log","a")
|
||||
log:write(tostring(completejob),"\n")
|
||||
log:close()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user