Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- assert(turtle,"This API may only be used on turtles!")
- local ver = 2.5
- local turtleOS = turtle.inspect and 1.64 or fs.getDir and 1.63 or turtle.equipRight and 1.6 or peripheral.getNames and 1.51
- local tFile = {
- --file path table
- ["cTurtle"] = "cTurtle"
- }
- tFile.directory = "/"..tFile.cTurtle.."Files"
- tFile.data = tFile.directory.."/data"
- tFile.restarted = tFile.directory.."/restarted"
- tFile.settings = tFile.directory.."/settings"
- local unlimitedFuel = turtle.getFuelLevel() == "unlimited"
- tSettings = {}
- function saveSettings(path,tTable)
- path = path or tFile.settings
- tTable = tTable or tSettings
- local file = fs.open(path,"w")
- for k,v in pairs(tTable) do
- if type(v) == "table" then
- v = textutils.serialize(v):gsub("\n%s-","")
- elseif v == true then
- v = "true"
- elseif v == false then
- v = "false"
- end
- file.writeLine(k.." = "..v)
- end
- file.close()
- end
- local function loadSettings(path,tTable)
- path = path or tFile.settings
- tTable = tTable or tSettings
- local file = fs.open(path,"r")
- local line = file.readLine()
- while line do
- local k = line:match"^%S+"
- local v = line:sub(#k+4,#line)
- if v:match"^%d+$" then --number
- v = tonumber(v)
- elseif v == "true" then --true
- v = true
- elseif v == "false" then --false
- v = false
- elseif v:match"^{.-}$" then --table
- v = textutils.unserialize(v)
- end
- tTable[k] = v
- line = file.readLine()
- end
- file.close()
- end
- --settings, configure these from external programs using cTurtle.tSettings.setting = setting then cTurtle.saveSettings()
- if fs.exists(tFile.settings) then
- loadSettings()
- else
- tSettings.renderMove = true --wether to render info page on movement or not
- tSettings.enderFuel = false --slot of enderchest containing fuel
- tSettings.autoRefuel = false --wether to check inventory for fuel before stopping when out of fuel
- tSettings.controlChannel = 9280 --channel for external modem control, modemControl(true) must be called prior to usage
- tSettings.controlResponseChannel = 9281 --channel for modem responses
- tSettings.swarmChannel = 9290 --channel for swarm controls
- tSettings.swarmResponseChannel = 9291 --channel for swarm responses
- tSettings.swarm = false --swarm number. Swarm turtles will not break other turtles.
- tSettings.formation = false --swarm formation
- tSettings.tEnderFuel = {} -- slots to check enderchest for fuel
- for i=17,54 do
- tSettings.tEnderFuel[#tSettings.tEnderFuel+1] = i
- end
- end
- tTimer = {
- --timer table
- ["inputCoords"] = 20, --time to cancel coordinate input
- ["dig"] = 0.1, --time to wait after digging a block, incase of sand or gravel
- ["moveFail"] = 0.5, --time to wait if not digging and path is blocked
- ["enderFuel"] = 60 --time between each enderchest fuel check.
- }
- --init tables
- local tColors
- --color table
- if term.isColor() then
- tColors = {
- ["screen"] = colors.lightBlue,
- ["text"] = colors.white,
- ["textBackground"] = colors.black,
- ["topBar"] = colors.blue,
- ["bottomBar"] = colors.blue,
- ["topBarText"] = colors.yellow,
- ["bottomBarText"] = colors.yellow
- }
- else
- tColors = {
- --black & white color table
- ["screen"] = colors.white,
- ["text"] = colors.white,
- ["textBackground"] = colors.black,
- ["topBar"] = colors.black,
- ["bottomBar"] = colors.black,
- ["topBarText"] = colors.white,
- ["bottomBarText"] = colors.white
- }
- end
- local tText = {
- --string table
- ["topBar"] = "cTurtle ver: "..ver,
- ["x"] = "X: ",
- ["y"] = "Y: ",
- ["z"] = "Z: ",
- ["dir"] = "Dir: ",
- ["fuel"] = "Fuel: ",
- ["failedGPS"] = "No GPS, please input co-ordinates"
- }
- local tTerm = {}
- --terminal size table
- tTerm.x,tTerm.y = term.getSize()
- tTerm.xMid = tTerm.x/2
- tTerm.yMid = tTerm.y/2
- local tCurs = {
- --cursor table
- ["x"] = 1,
- ["y"] = 1
- }
- tDir = {
- --direction conversion table
- ["X+"] = {
- "x+","-x-","1","+1","-3","east","-west","e","-w"
- },
- ["X-"] = {
- "x-","-x+","3","+3","-1","west","-east","w","-e"
- },
- ["Z+"] = {
- "z+","-z-","2","+2","-4","south","-north","s","-n"
- },
- ["Z-"] = {
- "z-","-z+","4","+4","-2","north","-south","n","-s"
- },
- ["Y+"] = {
- "y+","-y-","up","-down","top","-bottom","5","+5","-6"
- },
- ["Y-"] = {
- "y-","-y+","down","-up","bottom","-top","6","+6","-5"
- }
- }
- tDirText = {
- --text to direction conversion table
- ["forward"] = {
- "forward","front","ahead","-back","-backward","-backwards","-behind"
- },
- ["backward"] = {
- "back","backward","backwards","behind","around","-front","-forward","-ahead"
- },
- ["left"] = {
- "left","-right"
- },
- ["right"] = {
- "right","-left"
- }
- }
- tNumDir = {
- --number to symbol conversion table
- "X+",
- "Z+",
- "X-",
- "Z-",
- "Y+",
- "Y-"
- }
- tNumHeading = {
- --number to heading conversion table
- "east",
- "south",
- "west",
- "north",
- "up",
- "down"
- }
- tDirNum = {
- --symbol to number conversion table
- ["X+"] = 1,
- ["X-"] = 3,
- ["Z+"] = 2,
- ["Z-"] = 4,
- ["Y+"] = 5,
- ["Y-"] = 6
- }
- tNumSide = {
- --number to turtle side conversion table
- [1] = "front",
- [2] = "front",
- [3] = "front",
- [4] = "front",
- [5] = "top",
- [6] = "bottom"
- }
- tPos = {} --location table
- tDest = {} --destination table
- --custom native turtle functions
- tPos.selectedSlot = 1
- turtle.select(1)
- local turtleSelect = _G.turtle.select
- _G.turtle.select = function(slot)
- turtleSelect(slot)
- tPos.selectedSlot = slot
- end
- native = turtle.native or turtle
- eventHandler = {} --stores custom event handler functions
- function clearEventHandler(skipcTurtle) --idfk why i can't just redef it....
- local tKey = {}
- for k in pairs(eventHandler) do
- if not skipcTurtle
- or (k ~= "refuel" and k ~= "moveFail") then
- tKey[#tKey+1] = k
- end
- end
- for i=1,#tKey do --fuck you next
- eventHandler[tKey[i]] = nil
- end
- end
- local function waitForResponse(id) --modified to not throw away non-turtle events and handle cTurtle events
- local resBool,resString
- while true do
- local tEvent = {os.pullEvent()}
- if tEvent[1] == "turtle_response" then
- if tEvent[2] == id then
- if tEvent[3] then
- resBool = true
- else
- resBool,resString = false, tEvent[4]
- end
- return resBool,resString
- end
- elseif tEvent[1] == "cTurtle" then
- return tEvent[2]
- elseif eventHandler[tEvent[1]] then
- eventHandler[tEvent[1]](tEvent)
- end
- end
- end
- local function wrap(sCommand) --get native function
- return turtleOS >= 1.6 and native[sCommand]
- or function(...)
- local id = native[sCommand](...)
- if id == -1 then
- return false
- end
- return waitForResponse(id)
- end
- end
- -- Wrap standard commands
- local turtle = {}
- turtle["getItemCount"] = native.getItemCount
- turtle["getItemSpace"] = native.getItemSpace
- turtle["getFuelLevel"] = native.getFuelLevel
- for k,v in pairs( native ) do
- if type( k ) == "string" and type( v ) == "function" and turtle[k] == nil then
- turtle[k] = wrap( k )
- end
- end
- -- Wrap peripheral commands
- if peripheral.getType("left") == "workbench" then
- turtle["craft"] = function( ... )
- local id = peripheral.call( "left", "craft", ... )
- return waitForResponse( id )
- end
- elseif peripheral.getType("right") == "workbench" then
- turtle["craft"] = function( ... )
- local id = peripheral.call( "right", "craft", ... )
- return waitForResponse( id )
- end
- end
- --internal API functions
- tTextDir = {}
- local function updateDirs()
- --updates table containing current directions
- tTextDir.forward = tPos.dir
- tTextDir.right = dirAdd(tPos.dir)
- tTextDir.left = dirSub(tPos.dir)
- tTextDir.backward = dirAdd(tPos.dir,2)
- return tTextDir
- end
- local function getTurtleFunc(FUNCTION,DIRECTION,oneTurn)
- --simplified function for acessing all turtle functions with cTurtle's direction capabilities
- assert(DIRECTION,"No direction given for function "..FUNCTION)
- DIRECTION = dirStandardize(DIRECTION)
- if DIRECTION < 5 then -- not Y+ or Y-
- if FUNCTION == "move" then
- FUNCTION = "forward"
- end
- if oneTurn == true then
- turn(DIRECTION)
- return turtle[FUNCTION]
- elseif oneTurn == false then
- return turtle[FUNCTION]
- else
- return function()
- turn(DIRECTION)
- return turtle[FUNCTION]()
- end
- end
- elseif DIRECTION == 5 then --Y+
- if FUNCTION == "move" then
- return turtle.up
- end
- return turtle[FUNCTION.."Up"]
- elseif DIRECTION == 6 then -- Y-
- if FUNCTION == "move" then
- return turtle.down
- end
- return turtle[FUNCTION.."Down"]
- end
- end
- local function turnRight(AMOUNT)
- --proper right turn
- AMOUNT = AMOUNT or 1
- if AMOUNT < 1 then
- AMOUNT = -AMOUNT
- end
- for i=1,AMOUNT do
- tPos.dir = dirAdd(tPos.dir,1)
- saveData()
- --updates data prior to turn, to compensate for crash during turn
- turtle.turnRight()
- if renderMove then
- refreshLines()
- end
- end
- updateDirs()
- end
- local function turnLeft(AMOUNT)
- --proper left turn
- AMOUNT = AMOUNT or 1
- if AMOUNT < 1 then
- AMOUNT = -AMOUNT
- end
- for i=1,AMOUNT do
- tPos.dir = dirSub(tPos.dir,1)
- saveData()
- --updates data prior to turn, to compensate for crash during turn
- turtle.turnLeft()
- if renderMove then
- refreshLines()
- end
- end
- updateDirs()
- end
- local function sleep(time)
- -- modified to not throw away events and cancel cTurtle events if c is pressed
- local timerId = os.startTimer(time or 0)
- while true do
- local tEvent = {os.pullEvent()}
- if tEvent[1] == "timer" and tEvent[2] == timerId then
- return time
- elseif tEvent[1] == "key" and tEvent[2] == 46 then --c
- os.queueEvent("cTurtle","cancel")
- else
- os.queueEvent(unpack(tEvent))
- end
- end
- end
- --API functions
- function update(swarm)
- if swarm then --update swarm turtles through rednet
- local cTurtleFile = {
- id = "all",
- [1] = "cTurtle update"
- }
- for line in fs.open(tFile.cTurtle,"r").readLine do
- cTurtleFile[#cTurtleFile+1] = line
- end
- _G.modem.transmit(tSettings.swarmChannel,tSettings.swarmResponseChannel,cTurtleFile)
- else --update self
- local response,paste = http.get("http://pastebin.com/raw.php?i=JRPN0P8x")
- if response then
- paste = response.readAll()
- response.close()
- --save to file
- local file = fs.open(tFile.cTurtle,"w")
- file.writeLine(paste)
- file.close()
- os.reboot()
- else
- return false
- end
- end
- end
- tInput = {}
- function input()
- --enables co-ordinate input
- local tFieldOrder = {"x","y","z","dir"}
- for i=1,#tFieldOrder do
- --creates input field table
- local key,value = tFieldOrder[i],tPos[tFieldOrder[i]]
- if key == "dir" and string.match(string.format(value),"%d") then
- value = tNumDir[value]
- end
- tInput[i] = {}
- tInput[i]["value"] = string.format(value)
- tInput[i]["field"] = tText[key]
- tInput[i]["startX"] = #tInput[i]["field"]+2
- end
- term.setBackgroundColor(tColors.screen)
- term.clear()
- refreshLines()
- renderBars(tText.failedGPS)
- tCurs.x,tCurs.Y = 0,1
- term.setCursorPos(tInput[tCurs.y]["startX"],tCurs.y*2+1)
- term.setCursorBlink(true)
- local timeOut = os.startTimer(tTimer.inputCoords)
- while true do
- --user input begins
- local tEvent = {os.pullEvent()}
- if timeOut
- and (tEvent[1] == "key" or tEvent[1] == "mouse_click" or tEvent[1] == "char") then
- --cancel timeout
- timeOut = nil
- end
- if tEvent[1] == "mouse_click" then
- if tEvent[2] == 1 then
- local clickY = (tEvent[4]-1)/2
- if tFieldOrder[clickY] and tEvent[3] < tTerm.xMid-1 then
- local clickX = tEvent[3]-#tInput[clickY]["field"]-1
- if clickX > 0 then
- tCurs.y = clickY
- tCurs.x = math.min(#tInput[clickY]["value"],clickX-1)
- end
- end
- end
- elseif tEvent[1] == "key" then
- --special keyes
- if tEvent[2] == 200 then --up arrow
- tCurs.x = tCurs.x+#tInput[tCurs.y]["field"]
- tCurs.y = tCurs.y-1
- tCurs.x = tCurs.x-#tInput[math.max(1,tCurs.y)]["field"]
- elseif tEvent[2] == 208 then --down arrow
- tCurs.x = tCurs.x+#tInput[tCurs.y]["field"]
- tCurs.y = tCurs.y+1
- tCurs.x= tCurs.x-#tInput[math.min(#tInput,tCurs.y)]["field"]
- elseif tEvent[2] == 203 then --left arrow
- tCurs.x = tCurs.x-1
- elseif tEvent[2] == 205 then --right arrow
- tCurs.x = tCurs.x+1
- elseif tEvent[2] == 28 then --enter
- if tCurs.y >= #tInput then
- --input complete
- if dirStandardize(tInput[4]["value"]) then
- break
- else
- renderBars"Faulty direction."
- end
- else
- tCurs.x = tCurs.x+#tInput[tCurs.y]["field"]-#tInput[tCurs.y+1]["field"]
- tCurs.y = tCurs.y+1
- end
- elseif tEvent[2] == 14 and tCurs.x > 0 then --backspace
- tInput[tCurs.y]["value"] = string.sub(tInput[tCurs.y]["value"],1,tCurs.x-1)..string.sub(tInput[tCurs.y]["value"],tCurs.x+1,#tInput[tCurs.y]["value"])
- tCurs.x = tCurs.x-1
- elseif tEvent[2] == 206 then --end
- tCurs.x = #tInput[tCurs.y]["value"]
- elseif tEvent[2] == 206 then --home
- tCurs.x = 1
- elseif tEvent[2] == 211 then --delete
- if #tInput[tCurs.y]["value"] == 1 and tCurs.x <= 0 then
- tInput[tCurs.y]["value"] = ""
- else
- tInput[tCurs.y]["value"] = string.sub(tInput[tCurs.y]["value"],1,tCurs.x)..string.sub(tInput[tCurs.y]["value"],tCurs.x+2,#tInput[tCurs.y]["value"])
- end
- end
- --cursor check
- tCurs.y = math.min(#tInput,tCurs.y)
- tCurs.y = math.max(1,tCurs.y)
- tCurs.x = math.min(#tInput[tCurs.y]["value"],tCurs.x)
- tCurs.x = math.max(0,tCurs.x)
- elseif tEvent[1] == "char" then
- local input
- if #tInput[tCurs.y]["value"]+#tInput[tCurs.y]["field"] >= tTerm.xMid-3 then
- --limits amount of characters to bar size
- elseif tEvent[2]:match"[%+%-]" and tInput[tCurs.y]["value"]:match"[%+%-]" then
- --only one of either + or -
- elseif tInput[tCurs.y]["field"]:match"Dir:" and tEvent[2]:match"[XZxznorthNORTHsuSUweWEaA%+%-]" then
- --input to direction field, accepts +- and letters related to directions
- if tEvent[2]:match"[%+%-]" and tCurs.x ~= 1
- or tEvent[2]:match"[%+%-]" and #tInput[tCurs.y]["value"] > 1 then
- -- + and - can only be at the end of single char directions
- else
- input = true
- end
- elseif tEvent[2]:match"[0-9%+%-]" then
- --other fields, only accept numbers and +-
- if tEvent[2]:match"[%+%-]" and tCurs.x ~= 0
- or tInput[tCurs.y]["value"]:match"[%+%-]" and tCurs.x == 0 then
- -- + and - can only be at start
- else
- input = true
- end
- end
- if input then
- --input accepted
- tInput[tCurs.y]["value"] = string.sub(tInput[tCurs.y]["value"],1,tCurs.x)..tEvent[2]..string.sub(tInput[tCurs.y]["value"],tCurs.x+1,#tInput[tCurs.y]["value"])
- tCurs.x = tCurs.x+1
- end
- elseif tEvent[1] == "timer" then
- --timers
- if tEvent[2] == timeOut then
- break
- end
- end
- --updates current field on user input
- renderLine(tCurs.y)
- term.setCursorPos(tInput[tCurs.y]["startX"]+tCurs.x,tCurs.y*2+1)
- term.setCursorBlink(true)
- end
- --input complete, storing data
- tPos.x = tonumber(tInput[1]["value"])
- tPos.y = tonumber(tInput[2]["value"])
- tPos.z = tonumber(tInput[3]["value"])
- tPos.lastMove = dirStandardize(tInput[4]["value"])
- tPos.dir = tPos.lastMove
- term.setCursorBlink(false)
- term.setTextColor(colors.white)
- term.setBackgroundColor(colors.black)
- term.clear()
- term.setCursorPos(1,1)
- end
- function locate(FORCE)
- --gets turtle coordinates
- local x,y,z,dir,x2,y2,z2
- if _G.restarted or FORCE then
- --re-gets coordinates
- --via GPS
- x,y,z = gps.locate(3)
- if x and (not unlimitedFuel and turtle.getFuelLevel() > 0 or unlimitedFuel) then
- --GPS sucess, getting direction by moving
- local moved,down = false,false
- while not moved do
- while not unlimitedFuel and turtle.getFuelLevel() <= 0 do
- if tSettings.enderFuel then
- enderRestock(tSettings.enderFuel,true,tSettings.tEnderFuel)
- os.startTimer(tTimer.enderFuel)
- end
- if tSettings.autoRefuel and turtle.getFuelLevel() <= 0 then
- for i=1,16 do
- turtle.refuel(64)
- end
- end
- if turtle.getFuelLevel() <= 0 then
- if eventHandler.refuel then
- eventHandler.refuel()
- else
- renderBars("Fuel required! Press any key.")
- while true do
- local e = os.pullEvent()
- if e == "key" then
- turtle.refuel(64)
- break
- elseif e == "timer" then
- break
- end
- end
- end
- end
- end
- for i=1,4 do
- if turtle.forward() then
- moved = true
- break
- else
- turtle.turnLeft()
- end
- end
- if (turtle.detectUp() or down)
- and not moved then
- turtle.down()
- down = true
- elseif not moved then
- turtle.up()
- end
- end
- -- get new posistion
- x2,y2,z2 = gps.locate(3)
- -- calculate direction
- if x2 and (x ~= x2 or z ~= z2) then --incase second GPS fails
- if x < x2 then
- dir = "X+"
- elseif x > x2 then
- dir = "X-"
- elseif z < z2 then
- dir = "Z+"
- elseif z > z2 then
- dir = "Z-"
- end
- tPos.x = x2
- tPos.z = z2
- tPos.y = y2
- tPos.dir = tDirNum[dir]
- tPos.fuel = unlimitedFuel and 9999 or turtle.getFuelLevel()
- end
- end
- if not x
- or not x2
- or x == x2 and z == z2
- or not dir then
- --GPS failed, attempting player input
- if fs.exists(tFile.data) then
- loadData()
- else
- tPos.x = (x or 0)
- tPos.y = (y or 0)
- tPos.z = (z or 0)
- tPos.dir = 1
- tPos.fuel = unlimitedFuel and 9999 or turtle.getFuelLevel()
- end
- tDest.x = tPos.x
- tDest.y = tPos.y
- tDest.z = tPos.z
- input()
- end
- saveData()
- _G.restarted = false
- local file = fs.open(tFile.restarted,"w")
- file.writeLine"false"
- file.close()
- else
- --non-restarted call to locate
- loadData()
- end
- tDest.x = tPos.x
- tDest.y = tPos.y
- tDest.z = tPos.z
- return tPos
- end
- function renderBars(BOTTOMTEXT)
- --render top and bottom bar
- BOTTOMTEXT = BOTTOMTEXT or " "
- paintutils.drawLine(1,1,tTerm.x,1,tColors.topBar)
- paintutils.drawLine(1,tTerm.y,tTerm.x,tTerm.y,tColors.bottomBar)
- term.setCursorPos(tTerm.xMid-(#tText.topBar/2),1)
- term.setTextColor(tColors.topBarText)
- term.setBackgroundColor(tColors.topBar)
- term.write(tText.topBar)
- term.setCursorPos(tTerm.xMid-(#BOTTOMTEXT/2),tTerm.y)
- term.setTextColor(tColors.bottomBarText)
- term.setBackgroundColor(tColors.bottomBar)
- term.write(BOTTOMTEXT)
- term.setTextColor(tColors.text)
- term.setBackgroundColor(tColors.textBackground)
- end
- function refreshLines()
- term.setTextColor(tColors.text)
- term.setBackgroundColor(tColors.textBackground)
- local tFieldOrder = {"x","y","z","dir","fuel","x","y","z"}
- for i,k in pairs(tFieldOrder) do
- if i <= 5 then
- --pos, dir and fuel bars
- local value = tPos[k]
- if k == "dir" and string.match(string.format(value),"%d") then
- value = tNumDir[value]
- end
- paintutils.drawLine(2,i*2+1,tTerm.xMid-1,i*2+1,tColors.textBackground)
- term.setCursorPos(2,i*2+1)
- term.write(string.sub(k:upper(),1,1)..k:sub(2,#k)..": "..value)
- else
- --dest bars
- local value = tDest[k]
- paintutils.drawLine(tTerm.xMid+1,(i-5)*2+1,tTerm.x-1,(i-5)*2+1,tColors.textBackground)
- term.setCursorPos(tTerm.xMid+1,(i-5)*2+1)
- term.write("Dest"..k:upper()..": "..value)
- end
- end
- end
- function renderLine(LINE)
- --renders input lines
- paintutils.drawLine(2,LINE*2+1,tTerm.xMid-1,LINE*2+1,tColors.textBackground)
- term.setCursorPos(2,LINE*2+1)
- term.write(tInput[LINE]["field"]..tInput[LINE]["value"])
- end
- function loadData()
- --loads position data from file
- local file = fs.open(tFile.data,"r")
- file.readLine() --skip first line
- tPos.x = tonumber(string.sub(file.readLine(),4,10))
- tPos.y = tonumber(string.sub(file.readLine(),4,10))
- tPos.z = tonumber(string.sub(file.readLine(),4,10))
- tPos.dir = tDirNum[string.sub(file.readLine(),6,7)]
- tPos.fuel = tonumber(string.sub(file.readLine(),7,13))
- tPos.lastMove = string.sub(file.readLine(),12,13)
- if not unlimitedFuel and turtle.getFuelLevel() < tPos.fuel and _G.restarted then
- --fuel missing, correcting co-ordinates accordingly
- local lastMove = string.lower(tPos.lastMove)
- tPos[lastMove:sub(1,1)] = tPos[lastMove:sub(1,1)] + tonumber(lastMove:sub(2,2)..1)
- tPos.fuel = turtle.getFuelLevel()
- tPos.lastMove = tDirNum[tPos.lastMove]
- saveData()
- else
- tPos.fuel = unlimitedFuel and 9999 or turtle.getFuelLevel()
- tPos.lastMove = tDirNum[tPos.lastMove]
- end
- return tPos
- end
- function saveData(x,y,z,dir,fuel,path)
- x = x or tPos.x
- y = y or tPos.y
- z = z or tPos.z
- dir = dir or tPos.dir
- fuel = fuel or tPos.fuel
- path = path or tFile.data
- --saves position data to file
- local file = fs.open(path,"w")
- file.writeLine"cTurtle data file."
- file.writeLine("X: "..x)
- file.writeLine("Y: "..y)
- file.writeLine("Z: "..z)
- file.writeLine("Dir: "..tNumDir[dir])
- file.writeLine("Fuel: "..(tPos.fuel or unlimitedFuel and 9999 or turtle.getFuelLevel()))
- file.writeLine("Last move: "..tNumDir[(tPos.lastMove or dir)])
- file.close()
- end
- function dirStandardize(DIRECTION)
- --formats the given direction for usage
- assert(DIRECTION,"No direction given!")
- DIRECTION = string.format(string.lower(DIRECTION))
- if tPos.dir then
- updateDirs()
- for k,v in pairs(tDirText) do
- for i=1,#tDirText[k] do
- if DIRECTION == tDirText[k][i] then
- --checks for forward, left, right, etc.
- return tonumber(tTextDir[k])
- end
- end
- end
- end
- for k,v in pairs(tDir) do
- --checks for x+,x-,z+,north,south etc.
- for i=1,#tDir[k] do
- if DIRECTION == tDir[k][i] then
- return tonumber(tDirNum[k])
- end
- end
- end
- --failed to format direction
- error("Failed to format the given direction: "..DIRECTION,2)
- end
- function dirAdd(NUM,ADDNUM)
- --direction num right turn
- NUM = NUM+(ADDNUM or 1)
- if NUM > 4 then
- NUM = NUM-4
- end
- return NUM
- end
- function dirSub(NUM,SUBNUM)
- --direction num left turn
- NUM = NUM-(SUBNUM or 1)
- if NUM < 1 then
- NUM = 4+NUM
- end
- return NUM
- end
- function turn(DIRECTION)
- DIRECTION = dirStandardize(DIRECTION)
- if DIRECTION > 4 then
- return false --unable to turn Y+, Y-
- end
- if tSettings.renderMove then
- renderBars("Turning "..tNumDir[DIRECTION])
- end
- if DIRECTION == dirSub(tPos.dir,1) then
- --left turn when turning one left
- turnLeft(1)
- else
- local turns = 0
- while dirAdd(tPos.dir,turns) ~= DIRECTION do
- turns = turns+1
- end
- --otherwise turn right
- turnRight(turns)
- end
- if tSettings.renderMove then
- renderBars("Turn complete")
- end
- return true
- end
- function detect(DIRECTION)
- return getTurtleFunc("detect",DIRECTION,true)()
- end
- function dig(DIRECTION,SLOT,LOOP)
- if SLOT then
- turtle.select(SLOT)
- end
- local digFunc = getTurtleFunc("dig",DIRECTION,true)
- local detectFunc = getTurtleFunc("detect",DIRECTION,false)
- if LOOP then
- digFunc()
- while detectFunc() do
- digFunc()
- end
- return true
- end
- return digFunc()
- end
- function compare(DIRECTION,SLOT)
- if SLOT then
- turtle.select(SLOT)
- end
- return getTurtleFunc("compare",DIRECTION,true)()
- end
- function place(DIRECTION,SLOT,LOOP)
- if SLOT then
- turtle.select(SLOT)
- end
- local func = getTurtleFunc("place",DIRECTION,true)
- if loop then
- while not func() do
- end
- return true
- else
- return getTurtleFunc("place",DIRECTION,true)()
- end
- end
- function suck(DIRECTION,SLOT)
- if SLOT then
- turtle.select(SLOT)
- end
- return getTurtleFunc("suck",DIRECTION,true)()
- end
- function drop(DIRECTION,SLOT,AMOUNT)
- if SLOT then
- turtle.select(SLOT)
- end
- return getTurtleFunc("drop",DIRECTION,true)(AMOUNT or 64)
- end
- function select(SLOT)
- return turtle.select(SLOT)
- end
- function replace(DIRECTION,SLOT,DIGSLOT)
- if not compare(DIRECTION,SLOT) then
- dig(DIRECTION,DIGSLOT,true)
- turtle.select(SLOT or tPos.selectedSlot)
- end
- place(DIRECTION,SLOT)
- end
- function findSpace(place)
- --finds an open space and returns direction, places slected block if place
- if not turtle.detectUp() then
- while place and not turtle.placeUp() do end
- return 5,"top"
- elseif not turtle.detectDown() then
- while place and not turtle.placeDown() do end
- return 6,"bottom"
- elseif not turtle.detect() then
- while place and not turtle.place() do end
- return tPos.dir,"front"
- else
- for i=1,3 do
- turn"right"
- if not turtle.detect() then
- while place and not turtle.place() do end
- return tPos.dir,"front"
- end
- end
- end
- return false
- end
- function enderInteract(enderSlot,tItemsOut,tItemsIn)
- --[[puts down an ender chest from the slot (enderSlot), iteracts with it according to the tItems table
- using the following structure
- tItemsOut = { --push items into chest
- "Coal","Charcoal", --you can either store the name of the item directly in an index
- 1,2,3,4,5 --or the number of specific slots
- { --or use a table for more advanced options
- name = "Stone", --display name of the desired item, slot numbers work aswell
- amount = 128, --optional, amount of items to attempt to deposit
- slot = 1, --optional, slot to deposit the items to
- slot = {1,2,3,4,5} --or a table may be used for multiple slots
- }
- },
- tItemsIn = { --pull in specific items
- "Coal","Charcoal", --you can either store the name of the item directly in an index
- 1,2,3,4,5 --or the number of specific slots to pull from
- { --or use a table for more advanced options
- name = "Stone", --display name of the desired item, slot numbers work aswell
- amount = 128, --optional,amount of items to attempt to retrieve
- slot = 1, --optional,slot to store the items in
- slot = {1,2,3,4,5} --or a table may be used for multiple slots
- }
- }
- ]]
- turtle.select(enderSlot)
- local _dir,chestDir = findSpace(true)
- sleep(0.05)
- --locate open space for ender chest
- if chestDir then
- local pushDir = tNumHeading[dirStandardize("-"..chestDir)]
- local selected
- local amount = 0 -- amout of items pushed from chest
- if peripheral.getType(chestDir) == "ender_chest" then -- confirms ender chest peripheral
- tItemsOut = tItemsOut or {}
- tItemsIn = tItemsIn or {}
- for k,v in pairs(tItemsOut) do
- local class = type(v)
- if class == "number" then
- elseif class == "string" then
- else --class == "table"
- end
- end
- for k,v in pairs(tItemsIn) do
- if class == "number" then
- elseif class == "string" then
- else --class == "table"
- end
- end
- end
- end
- end
- function enderRestock(enderSlot,tTurtleSlots,tEnderSlots)
- --puts down an ender chest from the slot (enderSlot), then attempts to restock the
- --turtle slots in the table tTurtleSlots with the chest slots in tEnderSlots
- turtle.select(enderSlot)
- local _dir,chestDir = findSpace(true)
- sleep(0.05)
- --locate open space for ender chest
- if chestDir then
- local pushDir = tNumHeading[dirStandardize("-"..chestDir)]
- local tTurtleSlotsCopy
- if type(tTurtleSlots) == "table" then
- --create local copy of turtle slots table
- tTurtleSlotsCopy = {}
- for i=1,#tTurtleSlots do
- tTurtleSlotsCopy[i] = tTurtleSlots[i]
- end
- else
- tTurtleSlotsCopy = {enderSlot}
- end
- local tEnderSlotsCopy = {}
- --create local copy of ender chest slots table
- for i=1,#tEnderSlots do
- tEnderSlotsCopy[i] = tEnderSlots[i]
- end
- local selected
- local amount = 0 -- amout of items pushed from chest
- if peripheral.getType(chestDir) == "ender_chest" then -- confirms ender chest peripheral
- local chest = peripheral.wrap(chestDir)
- local chestFunc = chest.pushItemIntoSlot or chest.pushIntoSlot
- for iTurtle=1,#tTurtleSlotsCopy do
- local turtleCount = turtle.getItemCount(tTurtleSlotsCopy[iTurtle])
- if turtleCount < 64 then -- only restocks the slot if there is space
- local iEnder = 1
- while iEnder <= #tEnderSlotsCopy do --dynamic for loop
- local stack = peripheral.call(chestDir,"getStackInSlot",tEnderSlotsCopy[iEnder]) or {["qty"] = 0}
- local removed = false
- if stack.qty > 0 then -- items in ender chest slot
- local pushed = chestFunc(pushDir,tEnderSlotsCopy[iEnder],tTurtleSlots == true and stack.qty-1 or stack.qty,tTurtleSlotsCopy[iTurtle])
- turtleCount = turtleCount+pushed
- amount = amount+pushed
- if pushed == (tTurtleSlots == true and stack.qty-1 or stack.qty) then
- remove = true
- end
- if turtleCount >= 64 then --ends loop if turtle slot is full
- break
- end
- else -- no items in ender chest slot, slot is removed
- remove = true
- end
- if remove then
- table.remove(tEnderSlotsCopy,iEnder)
- else
- iEnder = iEnder+1
- end
- end
- end
- end
- end
- if tTurtleSlots == true then
- turtle.select(enderSlot)
- turtle.refuel(64)
- end
- dig(chestDir,enderSlot,true) -- retrieves the ender chest
- if amount > 0 then
- return amount
- else
- return false --no items pushed
- end
- end
- return false --chest placement failed
- end
- function enderDropoff(enderSlot,tTurtleSlots)
- --puts down an ender chest from the slot (enderSlot), then empties the specified
- --turtle slots in the table tTurtleSlots into the chest slots in tEnderSlots
- turtle.select(enderSlot)
- local _dir,chestDir = findSpace(true)
- sleep(0.1)
- --locate open space for ender chest
- if chestDir then
- local pullDir = tNumHeading[dirStandardize("-"..chestDir)]
- local tTurtleSlotsCopy = {}
- --create local copy of turtle slots table
- for i=1,#tTurtleSlots do
- tTurtleSlotsCopy[i] = tTurtleSlots[i]
- end
- local selected
- local amount = 0 -- amout of items stored in chest
- if peripheral.getType(chestDir) == "ender_chest" then -- confirms ender chest peripheral
- local chest = peripheral.wrap(chestDir)
- local chestFunc = chest.pullItemIntoSlot or chest.pullIntoSlot
- for iTurtle=1,#tTurtleSlotsCopy do
- local turtleCount = turtle.getItemCount(tTurtleSlotsCopy[iTurtle])
- if turtleCount > 0 then -- only stores occupied slots
- for iChest=17,chest.getInventorySize() do
- local stack = chest.getStackInSlot(iChest)
- stack = stack and stack.qty and stack.maxSize or {["qty"] = 0,["maxSize"] = 64}
- if stack.qty < stack.maxSize then --space in enderSlot
- local pulled = chestFunc(pullDir,tTurtleSlotsCopy[iTurtle],64,iChest)
- turtleCount = turtleCount-pulled
- amount = amount+pulled
- if turtleCount < 1 then -- Ends loop if turtle slot is empty
- break
- end
- end
- end
- end
- end
- else
- for iTurtle=1,#tTurtleSlotsCopy do
- local turtleCount = turtle.getItemCount(tTurtleSlotsCopy[iTurtle])
- if turtleCount > 0 then -- only stores occupied slots
- drop(chestDir, tTurtleSlotsCopy[iTurtle], turtleCount)
- end
- end
- end
- dig(chestDir,enderSlot,true) -- retrieves the ender chest
- if amount > 0 then
- return amount
- else
- return false --no items pulled
- end
- end
- return false --chest placement failed
- end
- function move(DIRECTION,AMOUNT,DIG)
- --moves turtle in DIRECTION, AMOUNT times, digs if DIG optional slot
- if AMOUNT == 0 then
- return
- end
- DIRECTION = dirStandardize(DIRECTION)
- AMOUNT = AMOUNT or 1
- if AMOUNT < 0 then
- DIRECTION = dirStandardize("-"..DIRECTION)
- AMOUNT = -AMOUNT
- end
- --function definitions
- local moveFunc
- if DIRECTION == tTextDir.backward and not DIG then
- moveFunc = turtle.back
- else
- moveFunc = getTurtleFunc("move",DIRECTION,true)
- end
- local detectFunc = getTurtleFunc("detect",DIRECTION)
- local internalDigFunc = getTurtleFunc("dig",DIRECTION)
- local digFunc = type(DIG) == "number" and function()
- turtle.select(DIG)
- internalDigFunc()
- end or internalDigFunc
- local attackFunc = getTurtleFunc("attack",DIRECTION)
- saveData()
- local symDir = tNumDir[DIRECTION]
- local posEntry = string.lower(symDir:sub(1,1))
- local mathOp = symDir:sub(2,2)
- --movement calc function
- local calcFunc = function()
- tPos[posEntry] = tPos[posEntry] + tonumber(mathOp.."1")
- tPos.fuel = not unlimitedFuel and tPos.fuel-1 or 9999
- end
- tDest[posEntry] = tPos[posEntry] + tonumber(mathOp..AMOUNT)
- for i=1,AMOUNT do
- while DIG and detectFunc() do
- while tSettings.swarm and peripheral.getType(tNumSide[DIRECTION]) == "turtle" do -- swarm turtles check for other turtles
- sleep(0.5)
- end
- digFunc()
- if DIRECTION == 5 then
- sleep(tTimer.dig)
- end
- end
- local res = moveFunc()
- while not res or res == "cancel" do
- if res == "cancel" then
- return
- elseif not unlimitedFuel and tPos.fuel <= 1 then
- if tSettings.enderFuel then
- enderRestock(tSettings.enderFuel,true,tSettings.tEnderFuel)
- tPos.fuel = turtle.getFuelLevel()
- os.startTimer(tTimer.enderFuel)
- end
- if tSettings.autoRefuel and tPos.fuel <= 1 then
- for i=1,16 do
- turtle.refuel(64)
- end
- tPos.fuel = turtle.getFuelLevel()
- end
- if tPos.fuel <= 0 then
- if eventHandler.refuel then
- eventHandler.refuel()
- tPos.fuel = turtle.getFuelLevel()
- else
- renderBars("Fuel required! Press any key.")
- while true do
- local e = os.pullEvent()
- if e == "key" then
- turtle.refuel(64)
- tPos.fuel = turtle.getFuelLevel()
- break
- elseif e == "timer" then
- break
- end
- end
- end
- end
- else
- turtle.attack()
- if DIG then
- digFunc()
- attackFunc()
- end
- if eventHandler.moveFail then
- eventHandler.moveFail(tNumDir[DIRECTION])
- elseif tSettings.renderMove then
- renderBars("Move "..tNumDir[DIRECTION].." failed. Retry in "..tTimer.moveFail)
- end
- sleep(tTimer.moveFail)
- end
- res = moveFunc()
- end
- calcFunc()
- tPos.lastMove = DIRECTION
- saveData()
- if tSettings.renderMove then
- refreshLines()
- renderBars("Moving "..symDir)
- end
- end
- if renderMove then
- renderBars("Moved "..symDir)
- end
- end
- function moveTo(COORDS,SYM,DIG)
- SYM = SYM:lower()
- tDest[SYM] = COORDS
- local mathOp
- local amount = tPos[SYM]-COORDS
- if amount > 0 then
- mathOp = "-"
- elseif amount == 0 then
- return
- else
- mathOp = "+"
- amount = -amount
- end
- move(SYM..mathOp,amount,DIG)
- end
- function moveToXYZ(x,y,z,faceDir,DIG)
- tDest.x = x
- tDest.y = y
- tDest.z = z
- if faceDir == true then
- DIG = faceDir
- faceDir = false
- end
- moveTo(x,"x",DIG)
- moveTo(z,"z",DIG)
- moveTo(y,"y",DIG)
- if faceDir then
- turn(faceDir)
- end
- end
- function deployGPS(tSlots,x,y,z)
- --builds a GPS tower at the given coordinates or the current coordinates
- --[[tSlots = {
- diskDrive = 1,
- disk = 2,
- computer = 3,
- modem = 4
- }]]
- assert(tSlots,"Slots table missing!")
- assert(tSlots.diskDrive,"diskDrive slot missing!")
- assert(turtle.getItemCount(tSlots.diskDrive) > 0,"No disk drive in slot "..tSlots.diskDrive.."!")
- assert(tSlots.disk,"disk slot missing!")
- assert(turtle.getItemCount(tSlots.disk) > 0,"No disk in slot "..tSlots.disk.."!")
- assert(tSlots.computer,"computer slot missing!")
- assert(turtle.getItemCount(tSlots.computer) > 3,"Missing "..(4-turtle.getItemCount(tSlots.computer).." computers in slot "..tSlots.computer.."!"))
- assert(tSlots.modem,"modem slot missing!")
- assert(turtle.getItemCount(tSlots.modem) > 3,"Missing "..(4-turtle.getItemCount(tSlots.modem).." modems in slot "..tSlots.modem.."!"))
- x = x or tPos.x
- y = math.min((y or tPos.y),252)
- z = z or tPos.z
- local function setupHost(hostX,hostZ)
- place("forward",tSlots.computer)
- move"up"
- place("forward",tSlots.modem)
- place("down",tSlots.diskDrive)
- assert(peripheral.getType"bottom" == "drive","The block on slot "..tSlots.diskDrive.." was not a disk drive!")
- drop("down",tSlots.disk)
- assert(fs.exists"/disk","Missing disk drive in slot "..tSlots.disk)
- if not fs.exists"/disk/startup" then
- local diskFile = fs.open("/disk/startup", "w")
- diskFile.writeLine[[
- if not os.getComputerLabel() then
- os.setComputerLabel"GPS Host"
- end
- fs.copy("/disk/hostFile", "/startup")
- shell.run"startup"]]
- diskFile.close()
- end
- local hostFile = fs.open("/disk/hostFile", "w")
- hostFile.writeLine('shell.run"gps host '..hostX..' '..(tPos.y-1)..' '..hostZ..'"')
- hostFile.close()
- move"left"
- move"right"
- move"down"
- turn"right"
- assert(peripheral.getType"front" == "computer","The block in slot "..tSlots.computer.." was not a computer!")
- peripheral.call("front", "turnOn")
- move"right"
- suck("left",tSlots.disk)
- turtle.select(tSlots.diskDrive)
- dig("forward")
- end
- moveTo(y,"y",true)
- moveToXYZ(x+4,y,z,"x+",true)
- setupHost(tPos.x+1,tPos.z)
- moveToXYZ(x-4,y,z,"x-",true)
- setupHost(tPos.x-1,tPos.z)
- moveToXYZ(x,y,z+4,"z+",true)
- setupHost(tPos.x,tPos.z+1)
- moveToXYZ(x,y+1,z-4,"z-",true)
- setupHost(tPos.x,tPos.z-1)
- move("down",2)
- end
- function deployTurtle(tSlots,tData)
- --[[tSlots = {
- diskDrive = 1,
- disk = 2,
- turtle = 3,
- enderChest = 4 -- optional, enables enderRefuel slot 16
- }
- tData = {
- label = "the turtle label derpface",
- type = "remote" --enables remote modem control on startup
- type = "swarm" --assigns swarm ID and enables remote control, enderRefuel slot 16 and disables renderMove.
- swarm = 1 --swarm ID number
- formation = "wall" or "floor" --swarm formation
- ]]--
- tData = tData or {}
- assert(tSlots,"Slots table missing!")
- assert(tSlots.diskDrive,"diskDrive slot missing!")
- assert(tSlots.disk,"disk slot missing!")
- assert(tSlots.turtle,"turtle slot missing!")
- place("down",tSlots.diskDrive,true)
- assert(peripheral.getType"bottom" == "drive", "The block in slot "..tSlots.diskDrive.." was not a diskDrive!")
- drop("down",tSlots.disk)
- assert(fs.exists"/disk", "The block in slot "..tSlots.disk.." was not a disk!")
- --setup cTurtle
- fs.delete("/disk/"..tFile.cTurtle)
- fs.copy(tFile.cTurtle,"disk/cTurtle")
- fs.delete("/disk"..tFile.directory)
- fs.makeDir("/disk"..tFile.directory)
- --setup disk bootup file
- local file = fs.open("/disk/startup","w")
- file.writeLine([[
- os.setComputerLabel("]]..(tData.label or tData.type or "cTurtle")..[[")
- fs.copy("disk/]]..tFile.cTurtle..[[", "/]]..tFile.cTurtle..[[")
- fs.copy("disk/startupFile","/startup")
- fs.copy("disk]]..tFile.directory..[[","]]..tFile.directory..[[")]]
- )
- file.close()
- if tSlots.enderChest then
- local file = fs.open("/disk/startup","a")
- file.writeLine([[
- turtle.select(1)
- turtle.transferTo(16)]]
- )
- file.close()
- end
- local file = fs.open("/disk/startup","a") --one time actions goes here
- file.writeLine([[
- sleep(5)
- _G.restarted = false
- shell.run"/startup"
- cTurtle.move"forward"
- cTurtle.move"back"]]
- )
- file.close()
- --setup settings
- local tNewSettings = {}
- for k,v in pairs(tSettings) do
- tNewSettings[k] = v
- end
- if tSlots.enderChest then
- tNewSettings.enderFuel = 16
- end
- if tData.type == "swarm" then
- tNewSettings.renderMove = false
- end
- for k,v in pairs(tData) do
- if tNewSettings[k] ~= nil then
- tNewSettings[k] = v
- end
- end
- saveSettings("/disk"..tFile.settings,tNewSettings)
- --setup startup file
- local file = fs.open("/disk/startupFile","w")
- file.writeLine([[
- local file = fs.open("]]..tFile.restarted..[[", "w")
- file.writeLine"true"
- file.close()
- os.loadAPI"]]..tFile.cTurtle..[["]]
- )
- file.close()
- --setup remote turtles
- if tData.type == "remote" then
- local file = fs.open("/disk/startupFile","a")
- file.writeLine([[
- cTurtle.modemControl(true)]]
- )
- file.close()
- --setup swarm turtles
- elseif tData.type == "swarm" then
- local file = fs.open("/disk/startupFile","a")
- file.writeLine([[
- cTurtle.modemControl(true)]]
- )
- file.close()
- end
- --setup location info
- --locaiton offset correction
- local tOffs = {
- x = 0,
- y = -1,
- z = 0
- }
- local dir = string.lower(tNumDir[tPos.dir])
- tOffs[dir:sub(1,1)] = tOffs[dir:sub(1,1)] + tonumber(dir:sub(2,2)..1)
- --save new location
- saveData(tPos.x+tOffs.x,tPos.y+tOffs.y,tPos.z+tOffs.z,tPos.dir,0,"/disk"..tFile.data)
- --place turtle
- move"forward"
- place("down",tSlots.turtle,true)
- assert(peripheral.getType"bottom" == "turtle","The block in slot "..tSlots.turtle.." was not a turtle!")
- if tSlots.enderChest then
- drop("down",tSlots.enderChest,1)
- end
- peripheral.call("bottom","turnOn")
- --retrieve disk and drive
- move"back"
- suck("down",tSlots.disk)
- turtle.select(tSlots.diskDrive)
- dig"down"
- end
- function deploySwarm (tSlots,height,width,formation)
- --[[tSlots = {
- diskDrive = 1,
- disk = 2,
- turtle = 3,
- enderChest = 4
- }]]--
- formation = formation or "wall"
- local frontDir = dirStandardize"forward"
- local sideDir = dirStandardize"right"
- local id = 1
- for h=1,height do
- for w=1,width do
- deployTurtle(tSlots,{
- label = "swarm cTurtle "..id,
- type = "swarm", --assigns swarm ID and enables remote control, enderRefuel slot 16 and disables renderMove.
- swarm = id, --swarm ID number
- formation = formation --swarm formation
- })
- id = id+1
- if w < width then
- if formation == "wall" then
- move(sideDir)
- turn(frontDir)
- elseif formation == "floor" then
- move(sideDir)
- turn(frontDir)
- end
- end
- end
- sideDir = cTurtle.dirStandardize("-"..sideDir)
- if formation == "wall" then
- move"up"
- elseif formation == "floor" then
- move"back"
- end
- end
- end
- tCommandQueue = {} -- table of queued commands
- function modemControl(enable)
- --enables a very advanced remote control of the turtle
- if enable then
- if modem then
- if cTurtle.tSettings.swarm then
- _G.modem.open(tSettings.swarmChannel)
- else
- _G.modem.open(tSettings.controlChannel)
- end
- else
- return
- end
- oldPull = _G.os.pullEvent
- _G.os.pullEvent = function(filter) -- override original pullEvent
- while true do
- local tEvent = {oldPull()}
- if tEvent[1] == "modem_message"
- and tEvent[3] == tSettings.controlChannel
- or tEvent[3] == tSettings.swarmChannel
- and type(tEvent[5]) == "table"
- and (tEvent[5].id == "all" or tEvent[5].id == tSettings.swarm) then
- tCommandQueue[#tCommandQueue+1] = tEvent
- if not tCommandQueue[2]
- or tEvent[5] == "cancel" then
- while tCommandQueue[1] do
- local oldRenderMove = tSettings.renderMove
- tSettings.renderMove = false
- local tArg = {}
- if tEvent[5] == "cancel" then --remote cancel
- os.queueEvent("cTurtle","cancel")
- elseif type(tEvent[5]) == "table" then --table commands
- if tEvent[5][1] == "cTurtle update" then --update cTurtle through modem message
- table.remove(tEvent[5],1)
- fs.open(tFile.cTurtle,"w").writeLine(table.concat(tEvent[5],"\n"))
- os.reboot()
- else -- function command
- tArg[1] = tEvent[5][1]
- for i=2,#tEvent[5] do
- if type(tEvent[5][i]) == "table" then
- tArg[i] = "{"
- for k,v in pairs(tEvent[5][i]) do
- tArg[i] = tArg[i].." "..k.." = "..v..","
- end
- tArg[i] = tArg[i].."}"
- elseif type(tEvent[5][i]) == "string" then
- tArg[i] = '"'..tEvent[5][i]..'"' --add quotation marks to strings
- elseif tEvent[5][i] == true then
- tArg[i] = "true" --change boolean to string
- elseif tEvent[5][i] == false then
- tArg[i] = "false" --change boolean to string
- else
- tArg[i] = tEvent[5][i] --numbers
- end
- end
- end
- else --string function command
- tArg[1] = tEvent[5]:match"^%S+"
- tEvent[5] = tEvent[5]:sub(#tArg[1]+2,#tEvent[5])
- for word in tEvent[5]:gmatch"%S+" do --split message into words
- if word:match"^%d+$" then --convert numbers to number format
- word = tonumber(word)
- elseif word:match"true" then --convert booleans to string
- word = "true"
- elseif word:match"false" then
- word = "false"
- else
- word = '"'..word..'"' --add quotation marks to strings
- end
- table.insert(tArg,word)
- end
- end
- if tArg[1] then --command
- local funcString = ""
- funcString = "cTurtle."..table.remove(tArg,1).."(" --write function
- for i=1,#tArg do
- local arg = tArg[i]
- if i > 1 then
- funcString = funcString.."," --commas if multipe args
- end
- funcString = funcString..arg
- end
- funcString = funcString..")" --end function
- local func = loadstring("setfenv(1,_G) "..funcString) -- create function
- local tRes = {pcall(func)}
- local str = funcString
- if tRes[1] then -- no errors
- table.remove(tRes,1) --remove error index
- for i=1,#tRes do --convert return values to string
- if tRes[i] == true then
- str = str.."|True "
- elseif tRes[i] == false then
- str = str.."|False "
- elseif type(tRes[i]) == "table" then
- for k,v in pairs(tRes[i]) do
- str = str.."|"..k.."="..v.." "
- end
- elseif tRes[i] then
- str = str.."|"..tRes[i].." "
- end
- end
- else --function failed
- str = str.."|"..tRes[2]
- end
- if tEvent[3] == tSettings.controlChannel then
- modem.transmit(tSettings.controlResponseChannel,tSettings.controlChannel,{
- response = str,
- tPos = tPos,
- turtleId = os.getComputerID()
- }) --send return values
- end
- renderMove = oldRenderMove
- end
- table.remove(tCommandQueue,1)
- if tCommandQueue[1] then -- command in queue
- tEvent = tCommandQueue[1]
- end
- end
- end
- elseif not filter or filter == tEvent[1] then
- return unpack(tEvent) -- return event params
- end
- end
- end
- if tSettings.swarm then
- _G.modem.transmit(tSettings.controlResponseChannel,tSettings.swarmChannel,"Swarm turtle #"..tSettings.swarm.." online.")
- else
- _G.modem.transmit(tSettings.controlResponseChannel,tSettings.controlChannel,"Turtle #"..os.getComputerID().." online.")
- end
- else
- _G.modem.close(tSettings.swarmChannel)
- _G.modem.close(tSettings.controlChannel)
- _G.os.pullEvent = oldPullEvent --restore original pullEvent
- end
- end
- --API init
- if not fs.exists(tFile.directory) then
- fs.makeDir(tFile.directory)
- end
- if not fs.exists(tFile.settings) then
- saveSettings()
- end
- if not fs.exists"/startup" then
- local file = fs.open("/startup","w")
- file.writeLine([[
- local file = fs.open("]]..tFile.restarted..[[", "w")
- file.writeLine"true"
- file.close()
- _G.restarted = true
- ]])
- file.close()
- _G.restarted = true
- else
- local file = fs.open("/startup","r")
- local sFile = file.readAll()
- file.close()
- if not sFile:match([[fs%.open%("]]..tFile.restarted..[[", "w"%)]]) then
- local file = fs.open("/startup","a")
- file.writeLine([[
- local file = fs.open("]]..tFile.restarted..[[", "w")
- file.writeLine"true"
- file.close()
- _G.restarted = true
- ]])
- file.close()
- _G.restarted = true
- end
- local file = fs.open(tFile.restarted, "w")
- file.writeLine"true"
- file.close()
- end
- if not _G.restarted then
- local file = fs.open(tFile.restarted,"r")
- _G.restarted = file.readLine() == "true"
- file.close()
- end
- if not _G.modem then --auto wrap turtle modem, for ease of use
- for k,side in pairs(peripheral.getNames()) do
- if peripheral.getType(side) == "modem" then
- _G.modem = peripheral.wrap(side)
- _G.modem.open(gps.CHANNEL_GPS) --open GPS channel
- break
- end
- end
- end
- locate()
- local tArg = {...}
- if tArg[1] then
- --shell usage
- for i=2,#tArg do
- if tArg[i]:match"^%d+$" then
- tArg[i] = tonumber(tArg[i])
- else
- tArg[i] = '"'..tArg[i]..'"'
- end
- end
- local func = loadstring(table.remove(tArg,1).."("..table.concat(tArg,",")..")")
- setfenv(func,getfenv())
- term.setBackgroundColor(colors.black)
- term.clear()
- func()
- term.clear()
- term.setCursorPos(1,1)
- end
Add Comment
Please, Sign In to add comment