Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Construction Turtle (Builder)
- local mtx, mty, mtz = -205, 72, 113
- local mtd = 1
- local mRange = 0
- -- mtx, mty, mtz are coordinates of
- -- resupply dock, and can also be used
- -- to assign absolute coordinates to
- -- turtle if no GPS system is available.
- -- mtd is the direction the turtle
- -- should be facing on approach to the
- -- resupply dock, and can be used to
- -- initialize the turtle direction if
- -- no GPS system is available.
- -- mRange stores turtles theoretical
- -- maximum modem range assuming
- -- clear weather
- local tx, ty, tz, td = 0, 0, 0, 0
- -- tx, ty, tz are absolute world coords
- -- td represents direction turtle is facing
- local bty, btx, btz, btd = 0, 1, 1, 1
- -- variables for turtle location within
- -- current construction chunk
- local gpsLinked = false
- local commLog = {}
- -- commLog table stores information from
- -- incoming messages to check for duplicates
- local m, d = nil, nil
- -- handles for peripherals
- local destructiveTurtle = false
- -- toggle to define whether or not turtle is
- -- allowed to break blocks
- local roomForFuel = true
- -- toggle to determine whether or not turtle
- -- will reserve slot 16 for on-board fuel reserve
- local cInvSlot = 1
- -- variable indexing current turtle inventory
- -- slot
- local maxMats = 1
- -- variable indicating how many different material
- -- types are specified in coordinate block
- local cInvCatalog = {}
- for i = 1, 16, 1 do
- cInvCatalog[i] = {0, 0}
- end
- -- table to contain index values for all
- -- turtle inventory slots using format:
- -- {itemtype, quantity}
- local maxFuel = 8000
- -- variable for upper limit on turtle fuel
- -- refuel function will not consume more fuel
- -- if fuel level is above maxFuel
- local tLabel, tID = os.getComputerLabel (), os.getComputerID ()
- -- assigned modem channel for turtle
- local North, East, South, West = 1, 2, 3, 4
- -- numeric values for compass directions
- local workBlock = {}
- -- table to contain build coordinates
- -- received from central computer
- function termStatus ()
- term.clear()
- term.setCursorPos(1, 1)
- write (tLabel..' ('..tostring(tID)..')')
- term.setCursorPos(15, 1)
- write ('Fuel: '..turtle.getFuelLevel())
- term.setCursorPos(1, 2)
- write ('GPS: ')
- term.setCursorPos(6, 2)
- if gpsLinked then
- write ('OK')
- else write ('*NO*')
- end
- term.setCursorPos(12, 2)
- write ('Modem: ')
- term.setCursorPos(19, 2)
- if m == nil then
- write('*NO*')
- else write ('OK')
- end
- term.setCursorPos (24, 2)
- write ('Range: '..tostring(mRange)..'m')
- term.setCursorPos (1, 3)
- local tFacingStr = ""
- if td == 1 then
- tFacingStr = "north"
- elseif td == 2 then
- tFacingStr = "east"
- elseif td == 3 then
- tFacingStr = "south"
- elseif td == 4 then
- tFacingStr = "west"
- end
- write ('Y= '..tostring(ty)..' X= '..tostring(tx)..' Z= '..tostring(tz)..' Facing: '..tFacingStr)
- term.setCursorPos(1, 5)
- write ('Inventory:')
- for i = 1, 4, 1 do
- local ix = 1 + ((i-1) * 10)
- term.setCursorPos (ix, 7)
- term.write (i..': ')
- term.setCursorPos ((ix + 4), 7)
- term.write (cInvCatalog[i][1]..':'..cInvCatalog[i][2])
- term.setCursorPos (ix, 8)
- term.write ((i + 4)..': ')
- term.setCursorPos ((ix + 4), 8)
- term.write (cInvCatalog[i+4][1]..':'..cInvCatalog[i+4][2])
- term.setCursorPos (ix, 9)
- term.write ((i + 8)..': ')
- term.setCursorPos ((ix + 4), 9)
- term.write (cInvCatalog[i+8][1]..':'..cInvCatalog[i+8][2])
- term.setCursorPos (ix, 10)
- term.write ((i + 12)..': ')
- term.setCursorPos ((ix + 4), 10)
- term.write (cInvCatalog[i+12][1]..':'..cInvCatalog[i+12][2])
- end
- term.setCursorPos (1, 12)
- end
- function refuel ()
- turtle.select (16)
- while (turtle.getItemCount(16) > 0) and
- (maxFuel > turtle.getFuelLevel()) do
- turtle.refuel(1)
- end
- end
- function turnLeft ()
- if turtle.turnLeft () then
- if (td - 1) == 0 then
- td = 4
- else td = (td - 1)
- end
- else
- print ("ERROR attempting to turn left!")
- end
- end
- function turnRight ()
- if turtle.turnRight () then
- if (td + 1) == 5 then
- td = 1
- else td = (td + 1)
- end
- else
- print ("ERROR attempting to turn right!")
- end
- end
- function moveUp ()
- if turtle.up () then
- ty = ty + 1
- else
- print ("ERROR attempting to move up!")
- end
- end
- function moveDown ()
- if turtle.down () then
- ty = ty - 1
- else
- print ("ERROR attempting to move down!")
- end
- end
- function moveForward ()
- if turtle.forward () then
- if td == 1 then tz = tz + 1
- elseif td == 2 then tx = tx + 1
- elseif td == 3 then tz = tz - 1
- elseif td == 4 then tx = tx - 1
- end
- else
- print ("ERROR attempting to move forward!")
- end
- end
- function moveBack ()
- if turtle.back () then
- if td == 1 then tz = tz - 1
- elseif td == 2 then tx = tx - 1
- elseif td == 3 then tz = tz + 1
- elseif td == 4 then tx = tx + 1
- end
- else
- print ("ERROR attempting to move back!")
- end
- end
- function manageInv (itemType)
- -- manages turtle's internal inventory, ensuring
- -- 'sample' block remains in slot 1 for
- -- comparison during resupply. Function returns
- -- false if inventory is empty.
- local maxSlots = 0
- if destructiveTurtle then maxSlots = 12
- elseif roomForFuel then maxSlots = 15
- else maxSlots = 16
- end
- for i = 1, maxSlots, 1 do
- if (cInvCatalog[i][1] == itemType) and
- (turtle.getItemCount (i) > 1) then
- turtle.select(i)
- return true
- end
- end
- return false
- end
- function placeDown (blockTab)
- -- places block below turtle
- -- returns 0 if successful, 1 if no inventory,
- -- 2 if other error
- if manageInv(blockTab[1]) then
- local ok = turtle.placeDown()
- if ok then return 0
- else return 2
- end
- else return 1
- end
- end
- function placeForward (blockTab)
- -- places block in front of turtle
- -- should be used for directional placements only
- -- error codes as with placeDown
- if manageInv(blockTab[1]) then
- local ok = turtle.place()
- if ok then return 0
- else return 2
- end
- else return 1
- end
- end
- function faceAbs (ftd)
- -- function to change turtle direction based
- -- on absolute coordinates
- if ftd > td then
- for i = 1, (ftd - td), 1 do
- turnRight ()
- end
- elseif ftd < td then
- for i = 1, (td - ftd), 1 do
- turnLeft ()
- end
- end
- end
- function faceDir (curDir, faceTo)
- -- function to change turtle direction based
- -- on relative coordinates
- if (curDir == 4) and (faceTo == 1) then
- turnRight()
- elseif (curDir == 1) and (faceTo == 4) then
- turnLeft()
- elseif (faceTo == 0) then
- return false
- elseif (curDir > faceTo) then
- for i = 1, (curDir - faceTo), 1 do
- turnLeft()
- end
- elseif (faceTo > curDir) then
- for i = 1, (faceTo - curDir), 1 do
- turnRight()
- end
- end
- end
- function moveTo (yDif, xDif, zDif, cDir)
- if xDif ~= 0 then
- if xDif > 0 then
- faceDir (cDir, 2)
- cDir = 2
- for i = 1, xDif, 1 do
- moveForward()
- end
- elseif xDif < 0 then
- faceDir (cDir, 4)
- cDir = 4
- for i = 1, (xDif * -1) do
- moveForward()
- end
- end
- end
- if zDif ~= 0 then
- if zDif > 0 then
- faceDir (cDir, 3)
- cDir = 1
- for i = 1, zDif, 1 do
- moveForward()
- end
- elseif zDif < 0 then
- faceDir (cDir, 1)
- cDir = 3
- for i = 1, (zDif * -1) do
- moveForward()
- end
- end
- end
- if yDif ~= 0 then
- if yDif > 0 then
- for i = 1, yDif, 1 do
- moveUp()
- end
- elseif yDif < 0 then
- for i = 1, (yDif * -1), 1 do
- moveDown()
- end
- end
- end
- return cDir
- end
- function initInvCatalog ()
- -- examines turtle inventory and sets item
- -- types and quantities in table
- local matched = false
- local maxSlots, tItemType = 0, 1
- if destructiveTurtle then maxSlots = 12
- elseif roomForFuel then maxSlots = 15
- else maxSlots = 16
- end
- for i = 1, 16, 1 do
- cInvCatalog[i][1] = 0
- end
- for i = 1, maxSlots, 1 do
- cInvCatalog[i][2] = turtle.getItemCount (i)
- if (cInvCatalog[i][1] == 0) and
- (not (cInvCatalog[i][2] == 0)) then
- turtle.select (i)
- for ii = 1, maxSlots, 1 do
- if not (i == ii) then
- if turtle.compareTo(ii) and not
- (cInvCatalog[ii][1] == 0) then
- cInvCatalog[i][1] = cInvCatalog[ii][1]
- matched = true
- end
- end
- end
- if not matched then
- cInvCatalog[i][1] = tItemType
- tItemType = tItemType + 1
- else matched = false
- end
- end
- end
- end
- function checkCommLog (msg)
- local sType = msg[2]
- if commLog[sType] == nil then
- commLog[sType] = {}
- commLog[sType][1] = { msg[3], msg[4], msg[5], {msg[6], msg[1]} }
- return true
- else
- for i = 1, #commLog[sType], 1 do
- if (commLog[sType][i][1] == msg[3]) and
- (commlog[sType][i][2] == msg[4]) and
- (commLog[sType][i][3] == msg[5]) then
- local msgs = #commLog[sType][i][4]
- for ii = 1, msgs, 1 do
- if commLog[sType][i][4][ii] == {msg[6], msg[1]} then
- return false
- end
- end
- table.insert (commLog[sType][i][4], {msg[6], msg[1]})
- if msgs > 5 then
- table.remove (commLog[sType][i][4], 1)
- end
- return true
- else
- table.insert (commLog[sType], {msg[3], msg[4], msg[5], {msg[6], msg[1]}})
- return true
- end
- end
- end
- end
- function reqMessageID ()
- local IDStr = tostring( os.day() )..'-'..tostring( os.time () )
- return IDStr
- end
- function listen ()
- local event, modemSide, senderChannel,
- replyChannel, message, senderDistance =
- os.pullEvent("modem_message")
- print ('Received message on channel '..tostring(senderChannel))
- local tTab = textutils.unserialize (message)
- if checkCommLog (tTab) then
- if tTab[1] == 1 then
- print ('Device status requested.')
- elseif tTab[1] == 2 then
- -- insert debug prints in place of move orders
- -- confirm accurate math
- print ('Relocation order received.')
- local newCoords = tTab[7]
- local nY = newCoords[1] - ty
- moveTo (nY, 0, 0, td)
- nY = newCoords[2] - ty
- local nX, nZ = 0, 0
- if tx > 0 then
- if newCoords[3] <= 0 then
- nX = newCoords[3] + (-1 * tx)
- else
- nX = newCoords[3] - tx
- end
- else
- if newCoords[3] <= 0 then
- nX = newCoords[3] + (-1 * tx)
- else
- nX = newCoords[3] + (-1 * tx)
- end
- end
- if tz > 0 then
- if newCoords[4] <= 0 then
- nZ = newCoords[4] + (-1 * tz)
- else
- nZ = newCoords[4] - tz
- end
- else
- if newCoords[4] <= 0 then
- nZ = newCoords[4] + (-1 * tz)
- else
- nZ = newCoords[4] + (-1 * tz)
- end
- end
- moveTo (nY, nX, nZ, td)
- print ('Yoff: '..tostring(nY)..' Xoff: '..tostring(nX)..' Zoff: '..tostring(nZ))
- elseif tTab[1] == 3 then
- print ('Build order received.')
- end
- else
- print ('Error receiving message:')
- print ('Duplicate indicated.')
- end
- end
- function reqChunk ()
- local tTab = {1, 5, tLabel, tID, tID, reqMessageID ()}
- m.transmit (1, tID, textutils.serialize (tTab))
- listen ()
- end
- function outOfBounds (wy, wx, wz)
- if (wy < 1) or (wy > 16) then
- return true
- elseif (wx < 1) or (wx > 16) then
- return true
- elseif (wz < 1) or (wz > 16) then
- return true
- else return false
- end
- end
- function advNext (cty, ctx, ctz, seekDir)
- -- seekDir indicates direction to move on
- -- horizontal plane
- -- 0 = right to left, 1 = left to right
- if seekDir == 0 then
- if math.ceil (ctx / 2) > math.floor (ctx / 2) then
- ctz = ctz + 1
- if ctz > 16 then
- ctz = 16
- ctx = ctx + 1
- end
- else
- ctz = ctz - 1
- if ctz < 1 then
- ctz = 1
- ctx = ctx + 1
- if ctx > 16 then
- ctx = 16
- cty = cty + 1
- end
- end
- end
- elseif seekDir == 1 then
- if math.ceil (ctx / 2) > math.floor (ctx / 2) then
- ctz = ctz - 1
- if ctz < 1 then
- ctz = 1
- ctx = ctx - 1
- if ctx < 1 then
- ctx = 1
- cty = cty + 1
- end
- end
- else ctz = ctz + 1
- if ctz > 16 then
- ctz = 16
- ctx = ctx - 1
- end
- end
- end
- if cty > 16 then return cty, ctx, ctz, {nil, nil}
- else return cty, ctx, ctz, workBlock[cty][ctx][ctz]
- end
- end
- function buildChunk ()
- -- builds block defined by workBlock
- local wty, wtx, wtz, wtm = 0, 0, 0, 0
- if workBlock == nil then
- print ('ERROR: Block table undefined.')
- print ('Unable to build block.')
- return false
- else
- moveUp ()
- bty = 1
- maxMats = 0
- for i = 1, 16, 1 do
- for ii = 1, 16, 1 do
- for iii = 1, 16, 1 do
- if workBlock[i][ii][iii][1] > maxMats then
- maxMats = workBlock[i][ii][iii][1]
- end
- end
- end
- end
- end
- local nty, ntx, ntz, ntm, pDir = 1, 1, 1, {}, 0
- local wty, wtx, wtz, wtm = 0, 0, 0, {}
- for i = 1, 16, 1 do
- for ii = 1, maxMats, 1 do
- if math.ceil (ii / 2) > math.floor (ii / 2) then
- nty, ntx, ntz = i, 1, 1
- pDir = 0
- else
- nty, ntx, ntz = i, 16, 1
- pDir = 1
- end
- ntm = workBlock[nty][ntx][ntz]
- if (nty == i) and (ntm[1] == ii) and (ntm[2] > 0) then
- wty, wtx, wtz = nty, ntx, ntz
- if ntm[2] == 1 then
- wtz = wtz + 1
- elseif ntm[2] == 2 then
- wtx = wtx + 1
- elseif ntm[2] == 3 then
- wtz = wtz - 1
- elseif ntm[2] == 4 then
- wtx = wtx - 1
- end
- if (not (outOfBounds (wty, wtx, wtz))) then
- if (workBlock[wty][wtx][wtz][1] > 0) then
- wtm = workBlock[wty][wtx][wtz]
- btd = moveTo (wty - bty, wtx - btx, wtz - btz, btd)
- bty = wty
- btx = wtx
- btz = wtz
- if not (wtm[2] == 0) then
- faceDir (btd, wtm[2])
- btd = wtm[2]
- end
- placeDown(wtm)
- workBlock[wty][wtx][wtz] = {0, 0}
- faceDir (btd, ntm[2])
- btd = ntm[2]
- moveBack()
- bty = nty
- btx = ntx
- btz = ntz
- placeDown(ntm)
- workBlock[nty][ntx][ntz] = {0, 0}
- end
- end
- end
- while not (nty > i) do
- nty, ntx, ntz, ntm = advNext (nty, ntx, ntz, pDir)
- if (nty == i) and (ntm[1] == ii) and (ntm[2] > 0) then
- wty, wtx, wtz = nty, ntx, ntz
- if ntm[2] == 1 then
- wtz = wtz + 1
- elseif ntm[2] == 2 then
- wtx = wtx + 1
- elseif ntm[2] == 3 then
- wtz = wtz - 1
- elseif ntm[2] == 4 then
- wtx = wtx - 1
- end
- if (not (outOfBounds (wty, wtx, wtz))) then
- if (workBlock[wty][wtx][wtz][1] > 0) then
- wtm = workBlock[wty][wtx][wtz]
- btd = moveTo ((wty - bty), (wtx - btx), (wtz - btz), btd)
- bty = wty
- btx = wtx
- btz = wtz
- if not (wtm[2] == 0) then
- faceDir (btd, wtm[2])
- btd = wtm[2]
- end
- placeDown(wtm)
- workBlock[wty][wtx][wtz] = {0, 0}
- faceDir (btd, ntm[2])
- btd = ntm[2]
- moveBack()
- btx = ntx
- btz = ntz
- btd = ntm[2]
- placeDown(ntm)
- workBlock[wty][ntx][ntz] = {0, 0}
- end
- end
- end
- end
- end
- nty, ntx, ntz = i, 1, 1
- ntm = workBlock[i][1][1]
- if (ntm[2] == 0) and (ntm[1] > 0) then
- btd = moveTo ((nty - bty), (ntx - btx), (ntz - btz), btd)
- bty = nty
- btx = ntx
- btz = ntz
- placeDown(ntm)
- workBlock[bty][btx][btz][1] = 0
- end
- while not (nty > i) do
- nty, ntx, ntz, ntm = advNext (nty, ntx, ntz, 0)
- if (nty == i) and (ntm[2] == 0) and (ntm[1] > 0) then
- btd = moveTo ((nty - bty), (ntx - btx), (ntz - btz), btd)
- bty = nty
- btx = ntx
- btz = ntz
- placeDown(ntm)
- workBlock[bty][btx][btz][1] = 0
- end
- end
- nty, ntx, ntz = i, 16, 1
- ntm = workBlock[i][16][1]
- if (ntm[2] > 0) and (ntm[1] > 0) then
- btd = moveTo ((nty - bty), (ntx - btx), (ntz - btz), btd)
- bty = nty
- btx = ntx
- btz = ntz
- faceDir (btd, ntm[2])
- btd = ntm[2]
- placeDown(ntm)
- workBlock[i][16][1][1] = 0
- end
- while not (nty > i) do
- nty, ntx, ntz, ntm = advNext (nty, ntx, ntz, 1)
- if (not (nty > bty)) and (ntm[2] > 0) and (ntm[1] > 0) then
- btd = moveTo ((nty - bty), (ntx - btx), (ntz - btz), btd)
- bty = nty
- btx = ntx
- btz = ntz
- faceDir (btd, ntm[2])
- btd = ntm[2]
- placeDown(ntm)
- workBlock[bty][btx][btz][1] = 0
- end
- end
- end
- return true
- end
- function getModemRange (mY)
- local modHeight = 0
- if mY <= 96 then modHeight = 0
- else modHeight = (mY - 96)
- end
- local tempRange = math.floor (64 + (modHeight * (320 / 159)))
- print ('Current maximum range is ', tempRange, 'm')
- return tempRange
- end
- function initTurtle ()
- local periLoc = {"top", "bottom", "left", "right", "front", "back"}
- local periStr, tempStr = "", ""
- for i = 1, 6, 1 do
- periStr = peripheral.getType (periLoc[i])
- if periStr == "modem" then
- m = peripheral.wrap (periLoc[i])
- m.open (tID)
- elseif periStr == "drive" then
- print ('Drive detected (not connected): '..periLoc[i])
- end
- end
- print ('Pausing for network startup.')
- sleep (2)
- local fx, fy, fz = gps.locate(3)
- if fx == nil then
- tx = mtx
- ty = mty
- tz = mtz
- td = mtd
- else
- gpsLinked = true
- sleep (0.5)
- tx = fx
- ty = fy
- tz = fz
- print (tx, ty, tz)
- if turtle.back() then
- -- account for fringe case where movement pushes
- -- turtle out of gps range
- fx, fy, fz = gps.locate (3)
- if not (fx == nil) then
- print (fx, fy, fz)
- if fx ~= tx then
- if fx > tx then
- td = East
- else
- td = West
- end
- else
- if fz > tz then
- td = North
- else
- td = South
- end
- end
- else
- turtle.forward()
- if turtle.forward() then
- fx, fy, fz = gps.locate (3)
- if not (fx == nil) then
- if fx ~= tx then
- if fx > tx then
- td = East
- else
- td = West
- end
- else
- if fz > tz then
- td = North
- else
- td = South
- end
- end
- else
- print ('Error detecting turtle direction:')
- print ('Out of range.')
- end
- else
- print ('Error detecting turtle direction:')
- print ('Forward movement restricted.')
- end
- end
- else
- print ('Error initializing turtle facing.')
- print ('Turtle could not reverse.')
- end
- tx = fx
- ty = fy
- tz = fz
- end
- tempStr = "Builder_"..tostring(tID)
- if (tLabel == "") or (tLabel ~= tempStr) then
- os.setComputerLabel (tempStr)
- tLabel = tempStr
- end
- mRange = getModemRange (ty)
- local msgContainer = textutils.serialize ({0, 5, tLabel, tID, tID, reqMessageID ()})
- m.transmit (1, tID, msgContainer)
- initInvCatalog()
- termStatus()
- end
- initTurtle ()
- termStatus()
- -- refuel ()
- while true do
- listen ()
- end
- --[[
- refuel ()
- local newChunk = true
- local oMsgTab = {}
- local oMsgStr = ""
- reqChunk ()
- while newChunk do
- termStatus()
- newChunk = buildChunk ()
- print ('buildChunk returned : ', newChunk)
- oMsgTab = {2, 5, tLabel, tID, tID, reqMessageID ()}
- oMsgStr = textutils.serialize (oMsgTab)
- m.transmit (0, tID, oMsgStr)
- sleep (1)
- reqChunk ()
- end
- m.close(tID)--]]
Advertisement
Add Comment
Please, Sign In to add comment