Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --Start networking
- rednet.open('right')
- local currentSlot = 1
- --Start location of turtle is its coordinates
- local myX = 0
- local myY = 0
- local myZ = 0
- --Start look direction - forward
- local spinningVector = { {0, 1}, {1, 0}, {0, -1}, {-1, 0} }
- local currentSpinningVector = 1
- --ID server computer
- local serverId = 0
- --Current mission
- local myMission = {x1 = 0, y1 = 0, z1 = 0, x2 = 0, y2 = 0, z2 = 0}
- --Height to fly
- local flyingHeight = 90
- --Stop mission or not
- local stopMission = false
- --Get arguments from message
- local function parseArgs(message)
- local args = {}
- for arg in string.gmatch(message, '<(%S+)>') do
- table.insert(args, arg)
- end
- return args
- end
- -- Helper functions
- local function alwaysTrue()
- return true
- end
- local function alwaysFalse()
- return false
- end
- --Turn turtle (left or right)
- local function rotate(direction)
- if (direction == 'right') then
- turtle.turnRight()
- currentSpinningVector = currentSpinningVector + 1
- else
- turtle.turnLeft()
- currentSpinningVector = currentSpinningVector - 1
- end
- if (currentSpinningVector < 1) then
- currentSpinningVector = 4
- end
- if (currentSpinningVector > 4) then
- currentSpinningVector = 1
- end
- end
- --Face turtle north in local coordinates
- local function faceNorth()
- while (currentSpinningVector ~= 1) do
- rotate('left')
- end
- end
- local function changePosition(direction)
- if (direction == 'down') then
- myZ = myZ - 1
- end
- if (direction == 'up') then
- myZ = myZ + 1
- end
- if (direction == 'forward') then
- vec = spinningVector[currentSpinningVector]
- myX = myX + vec[1]
- myY = myY + vec[2]
- end
- if (direction == 'back') then
- vec = spinningVector[currentSpinningVector]
- myX = myX - vec[1]
- myY = myY - vec[2]
- end
- end
- --Move turtle one step in any direction
- --If isSoft, will return false on facing something
- local function stepUp(direction, isSoft)
- --Detect and move functions
- local moveF = turtle.forward
- local detectF = turtle.detect
- local digF = turtle.dig
- if (direction == 'down') then
- moveF = turtle.down
- detectF = turtle.detectDown
- digF = turtle.digDown
- end
- if (direction == 'up') then
- moveF = turtle.up
- detectF = turtle.detectUp
- digF = turtle.digUp
- end
- if (direction == 'back') then
- moveF = turtle.back
- detectF = alwaysFalse
- digF = alwaysTrue
- end
- while (detectF()) do
- if (isSoft) then
- return false
- end
- if (not digF()) then
- print('Cant dig!')
- error()
- end
- end
- if (not moveF()) then
- if (turtle.getFuelLevel() <= 0) then
- print('Refueling...')
- turtle.select(1)
- if (not turtle.refuel(1)) then
- print('Out of fuel.')
- return false
- end
- turtle.select(currentSlot)
- end
- if (not moveF()) then
- print('Cant move on! Trying to move later...')
- for i=0, 40 do
- os.sleep(3)
- if (moveF()) then
- break
- end
- if (i >= 39) then
- print('No more attempts. Im stuck.')
- return false
- end
- end
- end
- end
- --Change position
- changePosition(direction)
- return true
- end
- local function myPos()
- write('X = ')
- write(myX)
- write('; Y = ')
- write(myY)
- write('; Z = ')
- print(myZ)
- end
- local function gpsLocate()
- local location = {0,0,0}
- myX, myY, myZ = gps.locate(5, false)
- if (myX == nil or myY == nil or myZ == nil) then
- print('Cant reach GPS')
- return false
- end
- return true
- end
- --Try to purge inventory
- local function unload()
- print('Trying to unload')
- local chestFound = false
- --Function to drop items
- local dropF = turtle.drop
- --Find chest
- --Try in front
- for i=1, 4 do
- if (turtle.detect()) then
- chestFound = true
- break
- end
- rotate('left')
- end
- if (not chestFound) then
- --Try up
- if (turtle.detectUp()) then
- chestFound = true
- dropF = turtle.dropUp
- end
- end
- if (not chestFound) then
- --Try down
- if (turtle.detectDown()) then
- chestFound = true
- dropF = turtle.dropDown
- end
- end
- if (not chestFound) then
- print('No chest around')
- return false
- end
- local totalUnloaded = 0
- for i=2, 16 do
- local thisCount = turtle.getItemCount(i);
- if (thisCount > 0) then
- totalUnloaded = totalUnloaded + thisCount
- turtle.select(i)
- dropF()
- end
- end
- --Done.
- print('Unloaded ' .. totalUnloaded .. ' items.')
- return true
- end
- --Refuel
- local function refuelFromChest()
- print('Trying to refuel')
- local chestFound = false
- --Function to drop items
- local suckF = turtle.suck
- local dropF = turtle.drop
- --Find chest
- --Try in front
- for i=1, 4 do
- if (turtle.detect()) then
- chestFound = true
- break
- end
- rotate('left')
- end
- if (not chestFound) then
- --Try up
- if (turtle.detectUp()) then
- chestFound = true
- suckF = turtle.suckUp
- dropF = turtle.dropUp
- end
- end
- if (not chestFound) then
- --Try down
- if (turtle.detectDown()) then
- chestFound = true
- suckF = turtle.suchDown
- dropF = turtle.dropDown
- end
- end
- if (not chestFound) then
- print('No chest around')
- return false
- end
- turtle.select(1)
- dropF()
- while ( (turtle.getItemSpace(1) > 4) and (suckF())) do
- write('.')
- end
- --Drop unnecessary
- if (turtle.getItemSpace(2)) then
- turtle.select(2)
- if (turtle.compareTo(1)) then
- dropF()
- end
- end
- --Done.
- print('Refueled.')
- return true
- end
- --Calibrate turtle coordinates
- --Find exit
- local function findWayOut()
- for i=0, 5 do
- if (not turtle.detect()) then
- return;
- end
- turtle.turnLeft()
- end
- end
- local function calibrate()
- findWayOut()
- --Crawl out of cage
- if (not stepUp('forward', true)) then
- print('Error while calibrating. Cant be miner.')
- error()
- end
- --Zero position
- if (not gpsLocate()) then
- error()
- end
- local zeroX = myX
- local zeroY = myY
- local zeroZ = myZ
- if (not stepUp('forward', true)) then
- print('Error while calibrating. Cant be miner.')
- error()
- end
- --Y+1 position
- gpsLocate()
- local yX = myX
- local yY = myY
- local yZ = myZ
- if (not stepUp('back', true)) then
- print('Error while calibrating. Cant be miner.')
- error()
- end
- rotate('right')
- if (not stepUp('forward', true)) then
- print('Error while calibrating. Cant be miner.')
- error()
- end
- --X+1 position
- gpsLocate()
- local xX = myX
- local xY = myY
- local xZ = myZ
- rotate('left')
- rotate('left')
- if (not stepUp('forward', true)) then
- print('Error while calibrating. Cant be miner.')
- error()
- end
- rotate('right')
- if (not stepUp('back', true)) then
- print('Error while calibrating. Cant be miner.')
- error()
- end
- --Calculate vectors now
- --Vector forward and back
- local fV = {0, 0}
- if (yX - zeroX > 0) then
- fV[1] = 1
- end
- if (yX - zeroX < 0) then
- fV[1] = -1
- end
- if (yY - zeroY > 0) then
- fV[2] = 1
- end
- if (yY - zeroY < 0) then
- fV[2] = -1
- end
- spinningVector[1][1] = fV[1]
- spinningVector[1][2] = fV[2]
- spinningVector[3][1] = 0-fV[1]
- spinningVector[3][2] = 0-fV[2]
- --Vector right and left
- local rV = {0, 0}
- if (xX - zeroX > 0) then
- rV[1] = 1
- end
- if (xX - zeroX < 0) then
- rV[1] = -1
- end
- if (xY - zeroY > 0) then
- rV[2] = 1
- end
- if (xY - zeroY < 0) then
- rV[2] = -1
- end
- spinningVector[2][1] = rV[1]
- spinningVector[2][2] = rV[2]
- spinningVector[4][1] = 0-rV[1]
- spinningVector[4][2] = 0-rV[2]
- --Debug
- --print('zero: ' .. zeroX .. ', ' .. zeroY .. ', ' .. zeroZ)
- --print('y+ : ' .. yX .. ', ' .. yY .. ', ' .. yZ)
- --print('x+ : ' .. xX .. ', ' .. xY .. ', ' .. xZ)
- --print('z+ : ' .. zX .. ', ' .. zY .. ', ' .. zZ)
- --for i=1, 4 do
- -- write(spinningVector[i][1])
- -- print(', ' .. spinningVector[i][2])
- -- print('')
- --end
- --error()
- --Final position
- gpsLocate()
- end
- -- Send message via rednet
- local function sendMessage(id, message)
- rednet.send(id, message)
- end
- --Rotate 180 degrees
- local function rotate180()
- rotate('right')
- rotate('right')
- end
- -- Introduce turtle in network
- local function introduce()
- local message = 'turtle <hello> <' .. myX .. '> <' .. myY .. '> <' .. myZ .. '>'
- write('Introducing myself: ')
- print(message)
- rednet.broadcast(message)
- end
- local function turnToVector(x, y)
- --Find right vector
- local targetId = 0
- for targetId,vector in pairs(spinningVector) do
- if (vector[1] == x and vector[2] == y) then
- break
- end
- end
- local dir = 'right'
- if ( (currentSpinningVector - targetId) % 4 == 1) then
- dir = 'left'
- end
- while (spinningVector[currentSpinningVector][1] ~= x or
- spinningVector[currentSpinningVector][2] ~= y) do
- rotate(dir)
- end
- end
- --Try to make step in any direction
- local function vectorStep(x, y, z, isSoft)
- if (x == 0 and y == 0 and z == 0) then
- return true
- end
- local stepAmount = -1
- local vector = {0, 0}
- --Try to move along Y
- if (y ~= 0) then
- vector = {0, -1}
- if (y < 0) then
- vector = {0, 1}
- stepAmount = 1
- end
- turnToVector(vector[1], vector[2])
- if (stepUp('forward', isSoft)) then
- y = y + stepAmount
- return x,y,z
- end
- end
- --Try to move along X
- if (x ~= 0) then
- stepAmount = -1
- vector = {-1, 0}
- if (x < 0) then
- vector = {1, 0}
- stepAmount = 1
- end
- turnToVector(vector[1], vector[2])
- if (stepUp('forward', isSoft)) then
- x = x + stepAmount
- return x,y,z
- end
- end
- --Try to move along Z
- if (z ~= 0) then
- stepAmount = -1
- local zDir = 'down'
- if (z < 0) then
- zDir = 'up'
- stepAmount = 1
- end
- if (stepUp(zDir, isSoft)) then
- z = z + stepAmount
- return x,y,z
- end
- end
- --Too bad, nothig help.
- return x,y,z
- end
- --Try to reach point without destroying anything
- local function moveTo(x, y, z)
- --Calculate distance
- local dX = myX - x
- local dY = myY - y
- local dZ = myZ - z
- local newX
- local newY
- local newZ
- while (dX ~= 0 or dY ~= 0 or dZ ~= 0) do
- newX,newY,newZ = vectorStep(dX, dY, dZ, true)
- if (newX == dX and newY == dY and newZ == dZ) then
- newX,newY,newZ = vectorStep(dX, dY, dZ, false)
- end
- if (newX == dX and newY == dY and newZ == dZ) then
- return false
- end
- dX = newX
- dY = newY
- dZ = newZ
- end
- --Arrived!
- --Face north
- --faceNorth()
- print('Moved to finish. My position: ')
- myPos()
- return true
- end
- -- Dir through to point
- local function digTo(x, y, z)
- --Calculate distance
- local dX = x - myX
- local dY = y - myY
- local dZ = z - myZ
- local vector = {0, 0}
- --Move along Y
- if (dY ~= 0) then
- vector = {0, 1}
- if (dY < 0) then
- vector = {0, -1}
- dY = math.abs(dY)
- end
- turnToVector(vector[1], vector[2])
- for i=1, dY do
- if (not stepUp('forward', false)) then
- return false
- end
- end
- end
- --Move along X
- if (dX ~= 0) then
- vector = {1, 0}
- if (dX < 0) then
- dX = math.abs(dX)
- vector = {-1, 0}
- end
- turnToVector(vector[1], vector[2])
- for i=1, dX do
- if (not stepUp('forward', false)) then
- return false
- end
- end
- end
- --Move along Z
- if (dZ ~= 0) then
- local zDir = 'up'
- if (dZ < 0) then
- dZ = math.abs(dZ)
- zDir = 'down'
- end
- for i=1, dZ do
- if (not stepUp(zDir, false)) then
- return false
- end
- end
- end
- --Arrived!
- --Face north
- --faceNorth()
- --print('Digged to finish. My position: ')
- --myPos()
- return true
- end
- --Get turtles global fuel level
- function fuelLevel()
- return turtle.getItemCount(1)
- end
- --Get on flying height to move long distances
- local function toFlyingHeight()
- print('Getting on flying height ' .. flyingHeight)
- if (not moveTo(myX, myY, flyingHeight)) then
- print('Cant get on flying height!')
- error()
- end
- end
- local function outputMission()
- print('From: ' .. myMission.x1 .. ', ' .. myMission.y1 .. ', ' .. myMission.z1)
- print('To: ' .. myMission.x2 .. ', ' .. myMission.y2 .. ', ' .. myMission.z2)
- print('Home: ' .. myMission.homeX .. ', ' .. myMission.homeY .. ', ' .. myMission.homeZ)
- print('Start fuel: ' .. myMission.totalFuel)
- end
- --Return home
- local function goHome()
- stopMission = false
- print('Going home: ' .. myMission.homeX .. ', ' .. myMission.homeY .. ', ' .. myMission.homeZ)
- --Get no flying height
- toFlyingHeight()
- --Move to landing point
- if (not moveTo(myMission.homeX, myMission.homeY, flyingHeight)) then
- print('Cant reach home landing point!')
- error()
- end
- print('Landing...')
- --Land
- if (not moveTo(myMission.homeX, myMission.homeY, myMission.homeZ)) then
- print('Cant land!')
- error()
- end
- print('Asking home')
- --We are home, ask get in
- sendMessage(serverId, 'turtle <wanthome>')
- return true
- end
- --Do our mission.
- local function doMission()
- print('Doing mission!')
- outputMission()
- --Get on flying height
- toFlyingHeight()
- --Calculate start and end point
- local sX = myMission.x1
- local sY = myMission.y1
- local sZ = myMission.z1
- local eX = myMission.x2
- local eY = myMission.y2
- local eZ = myMission.z2
- if (sZ < eZ) then
- local t
- t = eZ
- eZ = sZ
- sZ = t
- end
- if (sX > eX) then
- local t
- t = eX
- eX = sX
- sX = t
- end
- if (sY > eY) then
- local t
- t = eY
- eY = sY
- sY = t
- end
- --Go to start point
- print('Going to start point of mining: ' .. sX .. ', ' .. sY .. ', ' .. sZ)
- if (not moveTo(sX, sY, sZ)) then
- print('Cant reach start point!')
- error()
- end
- --We are on start position.
- local totalLevels = math.abs(eZ - sZ)-1
- outputMission()
- print('Total levels: ' .. totalLevels)
- for iZ=0, totalLevels do
- if (stopMission) then
- break
- end
- z = sZ - iZ
- print('Z-level: ' .. iZ .. ' / ' .. totalLevels )
- if (not digTo(myX, myY, z)) then
- print('Cant reach start point of Z-level!')
- error()
- end
- local reverse = false
- if (myX == eX) then
- reverse = true
- end
- for x = sX, eX do
- if (stopMission) then
- break
- end
- if (reverse) then
- x = eX - (x-sX)
- end
- --Dig along Y
- if (not digTo(x, myY, myZ)) then
- print('Cant reach start point of row!')
- error()
- end
- --On start pos
- local toY = eY
- if (myY == eY) then
- toY = sY
- end
- --Dig
- if (not digTo(myX, toY, myZ)) then
- print('Cant dig row!')
- error()
- end
- end
- end
- --Mission is over, go home
- goHome()
- end
- print('Calibrating...')
- calibrate()
- write('I am on position: ')
- myPos()
- introduce()
- term.clear()
- print('Awaiting orders. Press Q to terminate client.')
- while true do
- --Recieve event
- local event, id, message = os.pullEvent()
- --Rednet signal
- if (event == "rednet_message") then
- --print(message)
- --Command from server
- local pos = string.find(message, "command")
- if ((pos ~= nil) and (pos == 1)) then
- local args = parseArgs(message)
- command = args[1]
- --Asked for states
- if (command == 'states') then
- --The one who asked for states is server
- serverId = id
- --Fuel
- local fuel = fuelLevel()
- --Loaded slots
- local loadedSlots = 0
- for i=2, 16 do
- if (turtle.getItemCount(i) > 0) then
- loadedSlots = loadedSlots + 1
- end
- end
- --Send back message
- local states = "turtle <states> <" .. tostring(fuel) .. '> <' .. tostring(loadedSlots) .. '>'
- print('Sending ' .. states .. ' to ' .. tostring(id))
- sendMessage(id, states)
- end
- --Move to
- if (command == 'move') then
- local toX = tonumber(args[2])
- local toY = tonumber(args[3])
- local toZ = tonumber(args[4])
- local response = args[5]
- myPos()
- print('Moving to ' .. toX .. ', ' .. toY .. ', ' .. toZ)
- moveTo(toX, toY, toZ)
- --Send back report
- if (response ~= nil) then
- sendMessage(id, 'turtle <' .. response .. '> <' .. myX .. '> <' .. myY .. '> <' .. myZ .. '>')
- end
- end
- --Reintroduce
- if (command == 'reintroduce') then
- introduce()
- serverId = id
- print('Reintroduced.')
- end
- --Get mission
- if (command == 'mission') then
- myMission.x1 = tonumber(args[2])
- myMission.y1 = tonumber(args[3])
- myMission.z1 = tonumber(args[4])
- myMission.x2 = tonumber(args[5])
- myMission.y2 = tonumber(args[6])
- myMission.z2 = tonumber(args[7])
- local response = args[8]
- write('Got new mission: ')
- write(myMission.x1)
- write(', ')
- write(myMission.y1)
- write(', ')
- write(myMission.z1)
- write(' - ')
- write(myMission.x2)
- write(', ')
- write(myMission.y2)
- write(', ')
- write(myMission.z2)
- --error()
- --Send back report
- if (response ~= nil) then
- sendMessage(id, 'turtle <' .. response .. '>')
- end
- end
- --We are telled to do out mission by ourselves.
- if (command == 'domission') then
- --Init mission
- --Current position is our home.
- myMission.homeX = args[2]
- myMission.homeY = args[3]
- myMission.homeZ = args[4]
- --Start fuel level
- myMission.totalFuel = fuelLevel()
- --Do mission.
- doMission()
- end
- --Unload
- if (command == 'unload') then
- unload()
- local response = args[2]
- --Send back report
- if (response ~= nil) then
- sendMessage(id, 'turtle <' .. response .. '>')
- end
- end
- --Refuel
- if (command == 'refuel') then
- refuelFromChest()
- local response = args[2]
- --Send back report
- if (response ~= nil) then
- sendMessage(id, 'turtle <' .. response .. '>')
- end
- end
- end
- end
- --Exit
- if (event == "char" and id == "q") then
- break
- end
- end
- sendMessage(serverId, 'turtle <quit>')
- print('Miner stopped.')
Add Comment
Please, Sign In to add comment