civilwargeeky

Quarry 3.4.3

Feb 25th, 2014
1,830
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. --[[
  2. Version 3.4.3
  3. Recent Changes:
  4.   Added New Rednet Support
  5.   New Arguments!
  6.     -atChest [force] Using this with -resume will tell the turtle that it is at its chest, and needs to go back to where it was
  7.     -maxTries [number 1-9000] This is the number of times the turtle will try to mine something before it checks for bedrock
  8.   Arguments are no longer ignored if you use "-default", you just won't be prompted for anything.
  9.   Boolean (t/f) arguments now accept "yes" as well as "true"
  10. ]]
  11. --Defining things
  12. civilTable = nil; _G.civilTable = {}; setmetatable(civilTable, {__index = _G}); setfenv(1,civilTable)
  13. -------Defaults for Arguments----------
  14. --Arguments assignable by text
  15. x,y,z = 3,3,3 --These are just in case tonumber fails
  16. inverted = false --False goes from top down, true goes from bottom up [Default false]
  17. rednetEnabled = false --Default rednet on or off  [Default false]
  18. --Arguments assignable by tArgs
  19. dropSide = "front" --Side it will eject to when full or done [Default "front"]
  20. careAboutResources = true --Will not stop mining once inventory full if false [Default true]
  21. doCheckFuel = true --Perform fuel check [Default true]
  22. doRefuel = false --Whenever it comes to start location will attempt to refuel from inventory [Default false]
  23. invCheckFreq = 10 --Will check for inventory full every <-- moved spaces [Default 10]
  24. keepOpen = 1 --How many inventory slots it will attempt to keep open at all times [Default 1]
  25. fuelSafety = "moderate" --How much fuel it will ask for: safe, moderate, and loose [Default moderate]
  26. saveFile = "Civil_Quarry_Restore" --Where it saves restore data [Default "Civil_Quarry_Restore"]
  27. doBackup = true --If it will keep backups for session persistence [Default true]
  28. uniqueExtras = 8 --How many different items (besides cobble) the turtle expects. [Default 8]
  29. maxTries = 50 --How many times turtle will try to dig a block before it "counts" bedrock [Default 50]
  30. gpsEnabled = false -- If option is enabled, will attempt to find position via GPS api [Default false]
  31. gpsTimeout = 3 --The number of seconds the program will wait to get GPS coords. Not in arguments [Default 3]
  32. logging = true --Whether or not the turtle will log mining runs. [Default ...still deciding]
  33. logFolder = "Quarry_Logs" --What folder the turtle will store logs in [Default "Quarry_Logs"]
  34. logExtension = "" --The extension of the file (e.g. ".txt") [Default ""]
  35. startDown = 0 --How many blocks to start down from the top of the mine [Default 0]
  36. enderChestEnabled = false --Whether or not to use an ender chest [Default false]
  37. enderChestSlot = 16 --What slot to put the ender chest in [Default 16]
  38. --Standard number slots for fuel (you shouldn't care)
  39. fuelTable = { --Will add in this amount of fuel to requirement.
  40. safe = 1000,
  41. moderate = 200,
  42. loose = 0 } --Default 1000, 200, 0
  43. --Standard rednet channels
  44. channels = {
  45. send = os.getComputerID() + 1  ,
  46. receive = os.getComputerID() + 101 ,
  47. confirm = "Turtle Quarry Receiver",
  48. message = "Civil's Quarry",
  49. }
  50.  
  51. local help_paragraph = [[
  52. Welcome!: Welcome to quarry help. Below are help entries for all parameters. Examples and tips are at the bottom.
  53. -Default: This will force no prompts. If you use this and nothing else, only defaults will be used.
  54. -dim: [length] [width] [height] This sets the dimensions for the quarry
  55. -invert: [t/f] If true, quarry will be inverted (go up instead of down)
  56. -rednet: [t/f] If true and you have a wireless modem on the turtle, will attempt to make a rednet connection for sending important information to a screen
  57. -restore / -resume: If your quarry stopped in the middle of its run, use this to resume at the point where the turtle was. Not guarenteed to work properly. For more accurate location finding, check out the -GPS parameter
  58. -atChest: [force] This is for use with "-restore," this will tell the restarting turtle that it is at its home chest, so that if it had gotten lost, it now knows where it is.
  59. -doRefuel: [t/f] If true, the turtle will refuel itself with coal and planks it finds on its mining run
  60. -doCheckFuel: [t/f] If you for some reason don't want the program to check fuel usage, set to false. This is honestly a hold-over from when the refueling algorithm was awful...
  61. -uniqueExtras: [number] The expected number of slots filled with low-stacking items like ore. Higher numbers request more fuel.
  62. -chest: [side] This specifies what side the chest at the end will be on. You can say "top", "bottom", "front", "left", or "right"
  63. -enderChest: This one is special. If you use "-enderChest true" then it will use an enderChest in the default slot. However, you can also do "-enderChest [slot]" then it will take the ender chest from whatever slot you tell it to. Like 7... or 14... or whatever.
  64. -GPS: [force] If you use "-GPS" and there is a GPS network, then the turtle will record its first two positions to precisly calculate its position if it has to restart. This will only take two GPS readings
  65. -sendChannel: [number] This is what channel your turtle will send rednet messages on
  66. -receiveChannel: [number] This is what channel your turtle will receive rednet messages on
  67. -startY: [current Y coord] Randomly encountering bedrock? This is the parameter for you! Just give it what y coordinate you are at right now. If it is not within bedrock range, it will never say it found bedrock
  68. -maxTries: [number] This is the number of times the turtle will try to dig before deciding its run into bedrock.
  69. -logging: [t/f] If true, will record information about its mining run in a folder at the end of the mining run
  70. -doBackup: [t/f] If false, will not back up important information and cannot restore, but will not make an annoying file (Actually I don't really know why anyone would use this...)
  71. -saveFile: [word] This is what the backup file will be called
  72. -logFolder: [word] The folder that quarry logs will be stored in
  73. -logExtension: [word] The extension given to each quarry log (e.g. ".txt" or ".notepad" or whatever)
  74. -invCheckFreq: [number] This is how often the turtle will check if it has the proper amount of slots open
  75. -keepOpen: [number] This is the number of the slots the turtle will make sure are open. It will check every invCheckFreq blocks
  76. -careAboutResources: [t/f] Who cares about the materials! If set to false, it will just keep mining when its inventory is full
  77. -startDown: [number] If you set this, the turtle will go down this many blocks from the start before starting its quarry
  78.   =
  79.   C _ |
  80.       |
  81.       |
  82.       |
  83.       |_ _ _ _ >
  84. -manualPos: [xPos] [zPos] [yPos] [facing] This is for advanced use. If the server reset when the turtle was in the middle of a 100x100x100 quarry, fear not, you can now manually set the position of the turtle. yPos is always positive. The turtle's starting position is 0, 1, 1, 0. Facing is measured 0 - 3. 0 is forward, and it progresses clockwise. Example- "-manualPos 65 30 30 2"
  85. -help: Thats what this is :D
  86. Examples: Everything below is examples and tips for use
  87. Important Note:
  88.  None of the above parameters are necessary. They all have default values, and the above are just if you want to change them.
  89. Examples [1]:
  90.  Want to just start a quarry from the interface, without going through menus? It's easy! Just use some parameters. Assume you called the program "quarry." To start a 10x6x3 quarry, you just type in "quarry -dim 10 6 3 -default".
  91.   You just told it to start a quarry with dimensions 10x6x3, and "-default" means it won't prompt you about invert or rednet. Wasn't that easy?
  92. Examples [2]:
  93.   Okay, so you've got the basics of this now, so if you want, you can type in really long strings of stuff to make the quarry do exactly what you want. Now, say you want a 40x20x9, but you want it to go down to diamond level, and you're on the surface (at y = 64). You also want it to send rednet messages to your computer so you can see how its doing.
  94. Examples [2] [cont.]:
  95.   Oh yeah! You also want it to use an ender chest in slot 12 and restart if the server crashes. Yeah, you can do that. You would type
  96.   "quarry -dim 40x20x9 -invert false -startDown 45 -rednet true -enderChest 12 -restore"
  97.   BAM. Now you can just let that turtle do it's thing
  98. Tips:
  99.  The order of the parameters doesn't matter. "quarry -invert false -rednet true" is the same as "quarry -rednet true -invert false"
  100.  
  101.   Capitalization doesn't matter. "quarry -iNVErt FALSe" does the same thing as "quarry -invert false"
  102. Tips [cont.]:
  103.  For [t/f] parameters, you can also use "yes" and "no" so "quarry -invert yes"
  104.  
  105.  For [t/f] parameters, it only cares about the first letter. So you can use "quarry -invert t" or "quarry -invert y"
  106. Tips [cont.]:
  107.  If you are playing with fuel turned off, the program will automatically change settings for you so you don't have to :D
  108.  
  109.   If you want, you can load this program onto a computer, and use "quarry -help" so you can have help with the parameters whenever you want.
  110. Internal Config:
  111.   At the top of this program is an internal configuration file. If there is some setup that you use all the time, you can just change the config value at the top and run "quarry -default" for a quick setup.
  112.  
  113.   You can also use this if there are settings that you don't like the default value of.
  114. ]]
  115.  
  116. --Parsing help for display
  117. --[[The way the help table works:
  118. All help indexes are numbered. There is a help[i].title that contains the title,
  119. and the other lines are in help[i][1] - help[i][#help[i] ]
  120. Different lines (e.g. other than first) start with a space.
  121. As of now, the words are not wrapped, fix that later]]
  122. local help = {}
  123. local i = 0
  124. local titlePattern = ".-%:" --Find the beginning of the line, then characters, then a ":"
  125. local textPattern = "%:.+" --Find a ":", then characters until the end of the line
  126. for a in help_paragraph:gmatch("\n?.-\n") do --Matches in between newlines
  127. local current = string.sub(a,1,-2).."" --Concatenate Trick
  128. if string.sub(current,1,1) ~= " " then
  129. i = i + 1
  130. help[i] = {}
  131. help[i].title = string.sub(string.match(current, titlePattern),1,-2)..""
  132. help[i][1] = string.sub(string.match(current,textPattern) or " ",3,-1)
  133. elseif string.sub(current,1,1) == " " then
  134. table.insert(help[i], string.sub(current,2, -1).."")
  135. end
  136. end
  137.  
  138.  
  139. local supportsRednet = (peripheral.wrap("right") ~= nil)
  140.  
  141. local tArgs = {...}
  142. --You don't care about these
  143.       xPos,yPos,zPos,facing,percent,mined,moved,relxPos, rowCheck, connected, isInPath, layersDone, attacked, startY, chestFull, gotoDest, atChest, fuelLevel, numDropOffs
  144.     = 0,   1,   1,   0,     0,      0,    0,    1,       true   ,  false,     true,     1,          0,        0,      false,     "",       false,   0,         0
  145.    
  146. --NOTE: rowCheck is a bit. true = "right", false = "left"
  147.    
  148. local foundBedrock = false
  149.  
  150. local totals = {cobble = 0, fuel = 0, other = 0} -- Total for display (cannot go inside function)
  151. local function count() --Done any time inventory dropped and at end
  152. slot = {}        --1: Cobble 2: Fuel 3:Other
  153. for i=1, 16 do   --[1] is type, [2] is number
  154. slot[i] = {}
  155. slot[i][2] = turtle.getItemCount(i)
  156. end
  157. slot[1][1] = 1   -- = Assumes Cobble/Main
  158. for i=1, 16 do   --Cobble Check
  159. turtle.select(i)
  160. if turtle.compareTo(1)  then
  161. slot[i][1] = 1
  162. totals.cobble = totals.cobble + slot[i][2]
  163. elseif turtle.refuel(0) then
  164. slot[i][1] = 2
  165. totals.fuel = totals.fuel + slot[i][2]
  166. else
  167. slot[i][1] = 3
  168. totals.other = totals.other + slot[i][2]
  169. end
  170. end
  171. turtle.select(1)
  172. end
  173.  
  174. local getFuel, checkFuel
  175. if turtle then
  176.   getFuel = turtle.getFuelLevel  --This is for cleanup at the end
  177.   do --Common variable name...
  178.   local flag = turtle.getFuelLevel() == "unlimited"--Unlimited screws up my calculations
  179.   if flag then --Fuel is disabled
  180.     turtle.getFuelLevel = function() return math.huge end --Infinite Fuel
  181.   end --There is no "else" because it will already return the regular getFuel
  182.   end
  183.   checkFuel = turtle.getFuelLevel --Just an alias for backwards compat
  184. end
  185.  
  186.  -----------------------------------------------------------------
  187. --Input Phase
  188. local function screen(xPos,yPos)
  189. xPos, yPos = xPos or 1, yPos or 1
  190. term.setCursorPos(xPos,yPos); term.clear(); end
  191. local function screenLine(xPos,yPos)
  192. term.setCursorPos(xPos,yPos); term.clearLine(); end
  193.  
  194. screen(1,1)
  195. print("----- Welcome to Quarry! -----")
  196. print("")
  197.  
  198. local sides = {top = "top", right = "right", left = "left", bottom = "bottom", front = "front"} --Used to whitelist sides
  199. local changedT, tArgsWithUpper = {}, {}
  200. changedT.new = function(key, value) table.insert(changedT,{key, value}) end --Numeric list of lists
  201. local function capitalize(text) return (string.upper(string.sub(text,1,1))..string.sub(text,2,-1)) end
  202. for i=1, #tArgs do tArgsWithUpper[i] = tArgs[i]; tArgsWithUpper[tArgsWithUpper[i]] = i; tArgs[i] = tArgs[i]:lower(); tArgs[tArgs[i]] = i end --My signature key-value pair system, now with upper
  203.  
  204. local restoreFound, restoreFoundSwitch = false --Initializing so they are in scope
  205. function addParam(name, displayText, formatString, forcePrompt, trigger, variableOverride) --To anyone that doesn't understand this very well, probably not your best idea to go in here.
  206.   if trigger == nil then trigger = true end --Defaults to being able to run
  207.   if not trigger then return end --This is what the trigger is for. Will not run if trigger not there
  208.   if restoreFoundSwitch or tArgs["-default"] then forcePrompt = false end --Don't want to prompt if these
  209.   local toGetText = name:lower() --Because all params are now lowered
  210.   local formatType = formatString:match("^%a+"):lower() or error("Format String Unknown: "..formatString) --Type of format string
  211.   local args = formatString:sub(({formatString:find(formatType)})[2] + 2).."" --Everything in formatString but the type and space
  212.   local variable = variableOverride or name --Goes first to the override for name
  213.   local func = loadstring("return "..variable)
  214.   setfenv(func,getfenv(1))
  215.   local originalValue = assert(func)() --This is the default value, for checking to add to changed table
  216.   if originalValue == nil then error("From addParam, \""..variable.."\" returned nil",2) end --I may have gotten a wrong variable name
  217.   local givenValue, toRet --Initializing for use
  218.   if tArgs["-"..toGetText] then
  219.     givenValue = tArgsWithUpper[tArgs["-"..toGetText]+1] --This is the value after the desired parameter
  220.   elseif forcePrompt then
  221.     write(displayText.."? ")
  222.     givenValue = io.read()
  223.   end
  224.   if formatType == "force" then --This is the one exception. Should return true if givenValue is nothing
  225.     toRet = (tArgs["-"..toGetText] and true) or false --Will return true if param exists, otherwise false
  226.   end
  227.   if not (givenValue or toRet) then return end --Don't do anything if you aren't given anything. Leave it as default, except for "force"
  228.   if formatType == "boolean" then --All the format strings will be basically be put through a switch statement
  229.     toRet = givenValue:sub(1,1):lower() == "y" or givenValue:sub(1,1):lower() == "t" --Accepts true or yes
  230.     if formatString == "boolean special" then
  231.       toRet = givenValue:sub(1,1):lower() ~= "n" and givenValue:sub(1,1):lower() ~= "f" --Accepts anything but false or no
  232.     end
  233.   elseif formatType == "string" then
  234.     toRet = givenValue:match("^[%w%.]+") --Basically anything not a space or control character etc
  235.   elseif formatType == "number" then
  236.     toRet = tonumber(givenValue) --Note this is a local, not the above so we don't change anything
  237.     if not toRet then return end --We need a number... Otherwise compare errors
  238.     toRet = math.abs(math.floor(toRet)) --Get proper integers
  239.     local startNum, endNum = formatString:match("(%d+)%-(%d+)") --Gets range of numbers
  240.     startNum, endNum = tonumber(startNum), tonumber(endNum)
  241.     if not ((toRet >= startNum) and (toRet <= endNum)) then return end --Can't use these
  242.   elseif formatType == "side" then
  243.     local exclusionTab = {} --Ignore the wizardry here. Just getting arguments without format string
  244.     for a in args:gmatch("%S+") do exclusionTab[a] = true end --This makes a list of the sides to not include
  245.     if not exclusionTab[givenValue] then toRet = sides[givenValue] end --If side is not excluded
  246.   elseif formatType == "list" then
  247.     toRet = {}
  248.     for a in args:gmatch("[^,]") do
  249.       table.insert(toRet,a)
  250.     end
  251.   elseif formatType == "force" then --Do nothing, everything is already done
  252.   else error("Improper formatType",2)
  253.   end
  254.   if toRet == nil then return end --Don't want to set variables to nil... That's bad
  255.   tempParam = toRet --This is what loadstring will see :D
  256.   local func = loadstring(variable.." = tempParam")
  257.   setfenv(func, getfenv(1))
  258.   func()
  259.   tempParam = nil --Cleanup of global
  260.   if toRet ~= originalValue then
  261.     changedT.new(displayText, tostring(toRet))
  262.   end
  263.   return toRet
  264. end
  265.  
  266. --Check if it is a turtle
  267. if not(turtle or tArgs["help"] or tArgs["-help"] or tArgs["-?"] or tArgs["?"]) then --If all of these are false then
  268.   print("This is not a turtle, you might be looking for the \"Companion Rednet Program\" \nCheck My forum thread for that")
  269.   print("Press 'q' to quit, or any other key to start help ")
  270.   if ({os.pullEvent("char")})[2] ~= "q" then tArgs.help = true else error("",0) end
  271. end
  272.  
  273. if tArgs["help"] or tArgs["-help"] or tArgs["-?"] or tArgs["?"] then
  274. print("You have selected help, press any key to continue"); print("Use arrow keys to naviate, q to quit"); os.pullEvent("key")
  275. local pos = 1
  276. local key = 0
  277. while pos <= #help and key ~= keys.q do
  278. if pos < 1 then pos = 1 end
  279. screen(1,1)
  280. print(help[pos].title)
  281. for a=1, #help[pos] do print(help[pos][a]) end
  282. repeat
  283. _, key = os.pullEvent("key")
  284. until key == 200 or key == 208 or key == keys.q
  285. if key == 200 then pos = pos - 1 end
  286. if key == 208 then pos = pos + 1 end
  287. end
  288. error("",0)
  289. end
  290.  
  291. --Saving
  292. addParam("doBackup", "Backup Save File", "boolean")
  293. addParam("saveFile", "Save File Name", "string")
  294.  
  295. restoreFound = fs.exists(saveFile)
  296. restoreFoundSwitch = (tArgs["-restore"] or tArgs["-resume"] or tArgs["-atchest"]) and restoreFound
  297. if restoreFoundSwitch then
  298.   local file = fs.open(saveFile,"r")
  299.   local test = file.readAll() ~= ""
  300.   file.close()
  301.   if test then
  302.     os.run(getfenv(1),saveFile) --This is where the actual magic happens
  303.     if turtle.getFuelLevel ~= math.huge then --If turtle uses fuel
  304.       if fuelLevel - turtle.getFuelLevel() == 1 then
  305.         if facing == 0 then xPos = xPos + 1
  306.         elseif facing == 2 then xPos = xPos - 1
  307.         elseif facing == 1 then zPos = zPos + 1
  308.         elseif facing == 3 then zPos = zPos - 1 end
  309.       elseif fuelLevel - turtle.getFuelLevel() ~= 0 then
  310.         print("Very Strange Fuel in Restore Section...")
  311.         print("Current: ",turtle.getFuelLevel())
  312.         print("Saved: ",fuelLevel)
  313.         print("Difference: ",fuelLevel - turtle.getFuelLevel())
  314.         os.pullEvent("char")
  315.       end
  316.      end
  317.     if gpsEnabled then --If it had saved gps coordinates
  318.       print("Found GPS Start Coordinates")
  319.       local currLoc = {gps.locate(gpsTimeout)} or {}
  320.       local backupPos = {xPos, yPos, zPos} --This is for comparing to later
  321.       if #currLoc > 0 and #gpsStartPos > 0 and #gpsSecondPos > 0 then --Cover all the different positions I'm using
  322.         print("GPS Position Successfully Read")
  323.         if currLoc[1] == gpsStartPos[1] and currLoc[3] == gpsStartPos[3] then --X coord, y coord, z coord in that order
  324.           xPos, yPos, zPos = 0,1,1
  325.           if facing ~= 0 then turnTo(0) end
  326.           print("Is at start")
  327.         else
  328.           if inverted then --yPos setting
  329.           ------------------------------------------------FIX THIS
  330.           end
  331.           local function copyTable(tab) local toRet = {}; for a, b in pairs(tab) do toRet[a] = b end; return toRet end
  332.           local a, b = copyTable(gpsStartPos), copyTable(gpsSecondPos) --For convenience
  333.           if b[3] - a[3] == -1 then--If went north (-Z)
  334.             a[1] = a[1] - 1 --Shift x one to west to create a "zero"
  335.             xPos, zPos = -currLoc[3] + a[3], currLoc[1] + -a[1]
  336.           elseif b[1] - a[1] == 1 then--If went east (+X)
  337.             a[3] = a[3] - 1 --Shift z up one to north to create a "zero"
  338.             xPos, zPos = currLoc[1] + -a[1], currLoc[3] + -a[3]
  339.           elseif b[3] - a[3] == 1 then--If went south (+Z)
  340.             a[1] = a[1] + 1 --Shift x one to east to create a "zero"
  341.             xPos, zPos = currLoc[3] + a[3], -currLoc[1] + a[3]
  342.           elseif b[1] - a[1] == -1 then--If went west (-X)
  343.             a[3] = a[3] + 1 --Shift z down one to south to create a "zero"
  344.             xPos, zPos = -currLoc[1] + a[1], -currLoc[3] + a[3]
  345.           else
  346.             print("Improper Coordinates")
  347.             print("GPS Locate Failed, Using Standard Methods")        ----Maybe clean this up a bit to use flags instead.
  348.           end  
  349.         end
  350.         print("X Pos: ",xPos)
  351.         print("Y Pos: ",yPos)
  352.         print("Z Pos: ",zPos)
  353.         print("Facing: ",facing)
  354.         for i=1, 3, 2 do --We want 1 and 3, but 2 could be coming back to start.
  355.           if backupPos[i] ~= currLoc[i] then
  356.             events = {} --We want to remove event queue if not in proper place, so won't turn at end of row or things.
  357.           end
  358.         end
  359.       else
  360.         print("GPS Locate Failed, Using Standard Methods")
  361.       end    
  362.     print("Restore File read successfully. Starting in 3"); sleep(3)
  363.     end
  364.   else
  365.     fs.delete(saveFile)
  366.     print("Restore file was empty, sorry, aborting")
  367.     error("",0)
  368.   end
  369. else --If turtle is just starting
  370.   events = {} --This is the event queue :D
  371.   originalFuel = checkFuel() --For use in logging. To see how much fuel is REALLY used
  372. end
  373.  
  374. --Dimensions
  375. if tArgs["-dim"] then
  376.   local a,b,c = x,y,z
  377.   local num = tArgs["-dim"]
  378.   x = tonumber(tArgs[num + 1]) or x; z = tonumber(tArgs[num + 2]) or z; y = tonumber(tArgs[num + 3]) or y
  379.   if a ~= x then changedT.new("Length", x) end
  380.   if c ~= z then changedT.new("Width", z) end
  381.   if b ~= y then changedT.new("Height", y) end
  382. elseif not (tArgs["-default"] or restoreFoundSwitch) then
  383.   print("What dimensions?")
  384.   print("")
  385.   --This will protect from negatives, letters, and decimals
  386.   term.write("Length? ")
  387.   x = math.floor(math.abs(tonumber(io.read()) or x))
  388.   term.write("Width? ")
  389.   z = math.floor(math.abs(tonumber(io.read()) or z))
  390.   term.write("Height? ")
  391.   y = math.floor(math.abs(tonumber(io.read()) or y))
  392.   changedT.new("Length",x); changedT.new("Width",z); changedT.new("Height",y)
  393. end
  394. --Invert
  395. addParam("invert", "Inverted","boolean", true, nil, "inverted")
  396. addParam("startDown","Start Down","number 1-256")
  397. --Inventory
  398. addParam("chest", "Chest Drop Side", "side front", nil, nil, "dropSide")
  399. addParam("enderChest","Ender Chest Enabled","boolean special", nil, nil, "enderChestEnabled") --This will accept anything (including numbers) thats not "f" or "n"
  400. addParam("enderChest", "Ender Chest Slot", "number 1-16", nil, nil, "enderChestSlot") --This will get the number slot if given
  401. --Rednet
  402. addParam("rednet", "Rednet Enabled","boolean",true, supportsRednet, "rednetEnabled")
  403. addParam("gps", "GPS Location Services", "force", nil, (not restoreFoundSwitch) and supportsRednet, "gpsEnabled" ) --Has these triggers so that does not record position if restarted.
  404. if gpsEnabled and not restoreFoundSwitch then
  405.   gpsStartPos = {gps.locate(gpsTimeout)} --Stores position in array
  406.   gpsEnabled = #gpsStartPos > 0 --Checks if location received properly. If not, position is not saved
  407. end
  408. addParam("sendChannel", "Rednet Send Channel", "number 1-65535", false, supportsRednet, "channels.send")
  409. addParam("receiveChannel","Rednet Receive Channel", "number 1-65535", false, supportsRednet, "channels.receive")
  410. --Fuel
  411. addParam("uniqueExtras","Unique Items", "number 0-15")
  412. addParam("doRefuel", "Refuel from Inventory","boolean", nil, turtle.getFuelLevel() ~= math.huge) --math.huge due to my changes
  413. addParam("doCheckFuel", "Check Fuel", "boolean", nil, turtle.getFuelLevel() ~= math.huge)
  414. --Logging
  415. addParam("logging", "Logging", "boolean")
  416. addParam("logFolder", "Log Folder", "string")
  417. addParam("logExtension","Log Extension", "string")
  418. --Misc
  419. addParam("startY", "Start Y","number 1-256")
  420. addParam("invCheckFreq","Inventory Check Frequency","number 1-342")
  421. addParam("keepOpen", "Slots to Keep Open", "number 1-15")
  422. addParam("careAboutResources", "Care About Resources","boolean")
  423. addParam("maxTries","Tries Before Bedrock", "number 1-9001")
  424. --Manual Position
  425. if tArgs["-manualpos"] then --Gives current coordinates in xPos,zPos,yPos, facing
  426.   local a = tArgs["-manualpos"]
  427.   xPos, zPos, yPos, facing = tonumber(tArgs[a+1]) or xPos, tonumber(tArgs[a+2]) or zPos, tonumber(tArgs[a+3]) or yPos, tonumber(tArgs[a+4]) or facing
  428.   changedT.new("xPos",xPos); changedT.new("zPos",zPos); changedT.new("yPos",yPos); changedT.new("facing",facing)
  429.   restoreFoundSwitch = true --So it doesn't do beginning of quarry behavior
  430. end
  431. if addParam("atChest", "Is at Chest", "force") then --This sets position to 0,1,1, facing forward, and queues the turtle to go back to proper row.
  432.   local neededLayer = math.floor((yPos+1)/3)*3-1 --Make it a proper layer, +- because mining rows are 2, 5, etc.
  433.   if neededLayer > 2 and neededLayer%3 ~= 2 then --If turtle was not on a proper mining layer
  434.     print("Last known pos was not in proper layer, restarting quarry")
  435.     sleep(4)
  436.     neededLayer = 2
  437.   end
  438.   xPos, zPos, yPos, facing, rowCheck, layersDone = 0,1,1, 0, true, math.ceil(neededLayer/3)
  439.   events = {{"goto",1,1,neededLayer, 0}}
  440. end
  441.  
  442.  
  443. local function saveProgress(extras) --Session persistence
  444. exclusions = { modem = true, }
  445. if doBackup then
  446. local toWrite = ""
  447. for a,b in pairs(getfenv(1)) do
  448.   if not exclusions[a] then
  449.       --print(a ,"   ", b, "   ", type(b)) --Debug
  450.     if type(b) == "string" then b = "\""..b.."\"" end
  451.     if type(b) == "table" then b = textutils.serialize(b) end
  452.     if type(b) ~= "function" then
  453.       toWrite = toWrite..a.." = "..tostring(b).."\n"
  454.     end
  455.   end
  456. end
  457. toWrite = toWrite.."doCheckFuel = false\n" --It has already used fuel, so calculation unnesesary
  458. local file
  459. repeat
  460.   file = fs.open(saveFile,"w")
  461. until file --WHY DOES IT SAY ATTEMPT TO INDEX NIL!!!
  462. file.write(toWrite)
  463. if type(extras) == "table" then
  464.   for a, b in pairs(extras) do
  465.     file.write(a.." = "..tostring(b))
  466.   end
  467. end
  468. if turtle.getFuelLevel() ~= math.huge then --Used for location comparing
  469.   file.write("fuelLevel = "..tostring(turtle.getFuelLevel()))
  470. end
  471. file.close()
  472. end
  473. end
  474.  
  475. local area = x*z
  476. local volume = x*y*z
  477. local lastHeight = y%3
  478. layers = math.ceil(y/3)
  479. local yMult = layers --This is basically a smart y/3 for movement
  480. local moveVolume = (area * yMult) --Kept for display percent
  481. --Calculating Needed Fuel--
  482. do --Because many local variables unneeded elsewhere
  483.   local numItems = uniqueExtras --Convenience
  484.   local itemSize = extrasStackSize
  485.   local changeYFuel = 2*(y + startDown)
  486.   local dropOffSupplies = 2*(x + z + y + startDown) --Assumes turtle as far away as possible, and coming back
  487.   local frequency = math.floor(((volume/(64*(16-numItems))) ) --This is complicated: volume / inventory space of turtle, defined as (16-num unique stacks)
  488.                                  * (layers/y)) --This is the ratio of height to actual height mined. Close to 1/3 usually, so divide above by 3
  489.   if enderChestEnabled then frequency = 0 end
  490.   neededFuel = moveVolume + changeYFuel + frequency * dropOffSupplies
  491. end
  492.  
  493.  
  494. --[[
  495. local exStack = numberOfStacksPerRun --Expected stacks of items before full
  496. neededFuel = yMult * x * z + --This is volume it will run through
  497.       (startDown + y)*(2+1/(64*exStack)) + --This is simplified and includes the y to get up times up and down + how many times it will drop stuff off
  498.       (x+z)*(yMult + 1/(64*exStack))  --Simplified as well: It is getting to start of row plus getting to start of row how many times will drop off stuff
  499.       --Original equation: x*z*y/3 + y * 2 + (x+z) * y/3 + (x + z + y) * (1/64*8)
  500. neededFuel = math.ceil(neededFuel)
  501. ]]
  502. --Getting Fuel
  503. if doCheckFuel and checkFuel() < neededFuel then
  504. neededFuel = neededFuel + fuelTable[fuelSafety] --For safety
  505.   print("Not enough fuel")
  506.   print("Current: ",checkFuel()," Needed: ",neededFuel)
  507.   print("Starting SmartFuel...")
  508.   sleep(2) --So they can read everything.
  509.   term.clear()
  510.   local oneFuel, neededFuelItems
  511.   local currSlot = 0
  512.   local function output(text, x, y) --For displaying fuel
  513.     local currX, currY = term.getCursorPos()
  514.     term.setCursorPos(x,y)
  515.     term.clearLine()
  516.     term.write(text)
  517.     term.setCursorPos(currX,currY)
  518.     end
  519.   local function roundTo(num, target) --For stacks of fuel
  520.     if num >= target then return target elseif num < 0 then return 0 else return num end
  521.   end
  522.   local function updateScreen()
  523.     output("Welcome to SmartFuel! Now Refueling...", 1,1)
  524.     output("Currently taking fuel from slot "..currSlot,1,2)
  525.     output("Current single fuel: "..tostring(oneFuel or 0),1,3)
  526.     output("Current estimate of needed fuel: ",1,4)
  527.     output("Single Items: "..math.ceil(neededFuelItems or 0),4,5)
  528.     output("Stacks:       "..math.ceil((neededFuelItems or 0) / 64),4,6)
  529.     output("Needed Fuel: "..tostring(neededFuel),1,12)
  530.     output("Current Fuel: "..tostring(checkFuel()),1,13)
  531.   end
  532.   while checkFuel() <= neededFuel do
  533.     currSlot = currSlot + 1
  534.     turtle.select(currSlot)
  535.     updateScreen()
  536.     while turtle.getItemCount(currSlot) == 0 do sleep(1.5) end
  537.     repeat
  538.       local previous = checkFuel()
  539.       turtle.refuel(1)
  540.       oneFuel = checkFuel() - previous
  541.       updateScreen()
  542.     until (oneFuel or 0) > 0 --Not an if to prevent errors if fuel taken out prematurely.
  543.     neededFuelItems = (neededFuel - checkFuel()) / oneFuel
  544.     turtle.refuel(math.ceil(roundTo(neededFuelItems, 64))) --Change because can only think about 64 at once.
  545.     if turtle.getItemCount(roundTo(currSlot + 1, 16)) == 0 then --Resets if no more fuel
  546.       currSlot = 0
  547.     end
  548.     neededFuelItems = (neededFuel - checkFuel()) / oneFuel
  549.   end
  550. end
  551. --Ender Chest Obtaining
  552. function promptEnderChest()
  553.   while turtle.getItemCount(enderChestSlot) ~= 1 do
  554.     screen(1,1)
  555.     print("You have decided to use an Ender Chest!")
  556.     print("Please place one Ender Chest in slot ",enderChestSlot)
  557.     sleep(1)
  558.   end
  559.   print("Ender Chest in slot ",enderChestSlot, " checks out")
  560. end
  561. if enderChestEnabled then
  562.     if restoreFoundSwitch and turtle.getItemCount(enderChestSlot) == 0 then --If the turtle was stopped while dropping off items.
  563.       turtle.select(enderChestSlot)
  564.       turtle.dig()
  565.       turtle.select(1)
  566.     end
  567.   promptEnderChest()
  568.   sleep(2)
  569. end
  570. --Initial Rednet Handshake
  571. if rednetEnabled then
  572. screen(1,1)
  573. print("Rednet is Enabled")
  574. print("The Channel to open is "..channels.send)
  575. modem = peripheral.wrap("right")
  576. modem.open(channels.receive)
  577. local i = 0
  578.   repeat
  579.     local id = os.startTimer(3)
  580.     i=i+1
  581.     print("Sending Initial Message "..i)
  582.     modem.transmit(channels.send, channels.receive, channels.message)
  583.     local message
  584.     repeat
  585.       local event, idCheck, channel,_,locMessage, distance = os.pullEvent()
  586.       message = locMessage
  587.     until (event == "timer" and idCheck == id) or (event == "modem_message" and channel == channels.receive and message == channels.confirm)
  588.   until message == channels.confirm
  589. connected = true
  590. print("Connection Confirmed!")
  591. sleep(1.5)
  592. end
  593. function biometrics(isAtBedrock)
  594.   local toSend = { label = os.getComputerLabel() or "No Label", id = os.getComputerID(),
  595.     percent = percent, relxPos = relxPos, zPos = zPos, xPos = xPos, yPos = yPos,
  596.     layersDone = layersDone, x = x, z = z, layers = layers,
  597.     openSlots = getNumOpenSlots(), mined = mined, moved = moved,
  598.     chestFull = chestFull, isAtChest = (xPos == 0 and yPos == 1 and zPos == 1),
  599.     isGoingToNextLayer = (gotoDest == "layerStart"), foundBedrock = foundBedrock,
  600.     fuel = turtle.getFuelLevel(), volume = volume,
  601.     }
  602.   modem.transmit(channels.send, channels.receive, textutils.serialize(toSend))
  603.   id = os.startTimer(0.1)
  604.   local event, message
  605.   repeat
  606.     local locEvent, idCheck, confirm, _, locMessage, distance = os.pullEvent()
  607.     event, message = locEvent, locMessage
  608.   until (event == "timer" and idCheck == id) or (event == "modem_message" and confirm == channels.receive)
  609.   if event == "modem_message" then connected = true else connected = false end
  610.   message = message or ""
  611.   message = message:lower()
  612.   if message == "stop" then error("Rednet said to stop...",0) end
  613.   if message == "return" then
  614.     endingProcedure()
  615.     error('Rednet said go back to start...',0)
  616.   end
  617.   if message == "drop" then
  618.     dropOff()
  619.   end
  620. end
  621. --Showing changes to settings
  622. screen(1,1)
  623. print("Your selected settings:")
  624. if #changedT == 0 then
  625. print("Completely Default")
  626. else
  627. for i=1, #changedT do
  628. print(changedT[i][1],": ",changedT[i][2]) --Name and Value
  629. end
  630. end
  631. print("\nStarting in 3"); sleep(1); print("2"); sleep(1); print("1"); sleep(1.5) --Dramatic pause at end
  632.  
  633.  
  634.  
  635. ----------------------------------------------------------------
  636. --Define ALL THE FUNCTIONS
  637. function eventAdd(...)
  638.   return table.insert(events,1, {...}) or true
  639. end
  640. function eventGet(pos)
  641.   return events[tonumber(pos) or #events]
  642. end
  643. function eventPop(pos)
  644.   return table.remove(events,tonumber(pos) or #events) or false --This will return value popped, tonumber returns nil if fail, so default to end
  645. end
  646. function eventRun(value, ...)
  647.   local argsList = {...}
  648.   if type(value) == "string" then
  649.     if value:sub(-1) ~= ")" then --So supports both "up()" and "up"
  650.       value = value .. "("
  651.       for a, b in pairs(argsList) do --Appending arguments
  652.         local toAppend
  653.         if type(b) == "table" then toAppend = textutils.serialize(b)
  654.         elseif type(b) == "string" then toAppend = "\""..tostring(b).."\"" --They weren't getting strings around them
  655.         else toAppend = tostring(b) end
  656.         value = value .. (toAppend or "true") .. ", "
  657.       end
  658.       if value:sub(-1) ~= "(" then --If no args, do not want to cut off
  659.         value = value:sub(1,-3)..""
  660.       end
  661.       value = value .. ")"
  662.     end
  663.     --print(value) --Debug
  664.     local func = loadstring(value)
  665.     setfenv(func, getfenv(1))
  666.     return func()
  667.   end
  668. end
  669.  
  670. function eventClear(pos)
  671.   if pos then events[pos] = nil else events = {} end
  672. end
  673.      
  674. function runAllEvents()
  675.   while #events > 0 do
  676.     local toRun = eventGet()
  677.     --print(toRun[1]) --Debug
  678.     eventRun(unpack(toRun))
  679.     eventPop()
  680.   end
  681. end
  682.  
  683. function display() --This is just the last screen that displays at the end
  684.   screen(1,1)
  685.   print("Total Blocks Mined: "..mined)
  686.   print("Current Fuel Level: "..turtle.getFuelLevel())
  687.   print("Cobble: "..totals.cobble)
  688.   print("Usable Fuel: "..totals.fuel)
  689.   print("Other: "..totals.other)
  690.   if rednetEnabled then
  691.     print("")
  692.     print("Sent Stop Message")
  693.     local finalTable = {mined = mined, cobble = totals.cobble, fuelblocks = totals.fuel,
  694.         other = totals.other, fuel = checkFuel() }
  695.     modem.transmit(channels.send,channels.receive,"stop")
  696.     sleep(0.5)
  697.     modem.transmit(channels.send,channels.receive,textutils.serialize(finalTable))
  698.     modem.close(channels.receive)
  699.   end
  700.   if doBackup then fs.delete(saveFile) end
  701. end
  702. function updateDisplay() --Runs in Mine(), display information to the screen in a certain place
  703. screen(1,1)
  704. print("Blocks Mined")
  705. print(mined)
  706. print("Percent Complete")
  707. print(percent.."%")
  708. print("Fuel")
  709. print(checkFuel())
  710.   -- screen(1,1)
  711.   -- print("Xpos: ")
  712.   -- print(xPos)
  713.   -- print("RelXPos: ")
  714.   -- print(relxPos)
  715.   -- print("Z Pos: ")
  716.   -- print(zPos)
  717.   -- print("Y pos: ")
  718.   -- print(yPos)
  719. if rednetEnabled then
  720. screenLine(1,7)
  721. print("Connected: "..tostring(connected))
  722. end
  723. end
  724. function logMiningRun(textExtension, extras) --Logging mining runs
  725. if logging then
  726. local number
  727. if not fs.isDir(logFolder) then
  728.   fs.delete(logFolder)
  729.   fs.makeDir(logFolder)
  730.   number = 1
  731. else
  732.   local i = 0
  733.   repeat
  734.     i = i + 1
  735.   until not fs.exists(logFolder.."/Quarry_Log_"..tostring(i)..(textExtension or ""))
  736.   number = i
  737. end
  738. handle = fs.open(logFolder.."/Quarry_Log_"..tostring(number)..(textExtension or ""),"w")
  739. local function write(...)
  740.   for a, b in ipairs({...}) do
  741.     handle.write(tostring(b))
  742.   end
  743.   handle.write("\n")
  744. end
  745. write("Welcome to the Quarry Logs!")
  746. write("Entry Number: ",number)
  747. write("Dimensions (X Z Y): ",x," ",z," ", y)
  748. write("Blocks Mined: ", mined)
  749. write("  Cobble: ", totals.cobble)
  750. write("  Usable Fuel: ", totals.fuel)
  751. write("  Other: ",totals.other)
  752. write("Total Fuel Used: ",  (originalFuel or (neededFuel + checkFuel()))- checkFuel()) --Protect against errors with some precision
  753. write("Expected Fuel Use: ", neededFuel)
  754. handle.close()
  755. end
  756. end
  757. function isFull(slots)
  758.   slots = slots or 16
  759.   local numUsed = 0
  760.   sleep(0)
  761.   for i=1, 16 do
  762.     if turtle.getItemCount(i) > 0 then numUsed = numUsed + 1 end
  763.   end
  764.   if numUsed > slots then
  765.     return true
  766.   end
  767.   return false
  768. end
  769. function dig(doAdd, func)
  770.   doAdd = doAdd or true
  771.   func = func or turtle.dig
  772.   if func() then
  773.     if doAdd then
  774.       mined = mined + 1
  775.     end
  776.     return true
  777.   end
  778.   return false
  779. end
  780. if not inverted then --Regular functions :) I switch definitions for optimizatoin (I thinK)
  781.   function digUp(doAdd)
  782.     return dig(doAdd,turtle.digUp)
  783.   end
  784.   function digDown(doAdd)
  785.     return dig(doAdd,turtle.digDown)
  786.   end
  787. else
  788.   function digDown(doAdd)
  789.     return dig(doAdd,turtle.digUp)
  790.   end
  791.   function digUp(doAdd)
  792.     return dig(doAdd,turtle.digDown)
  793.   end
  794. end
  795. function setRowCheckFromPos()
  796.   rowCheck = (zPos % 2 == 1) --It will turn right at odd rows
  797. end
  798. function relxCalc()
  799.   if rowCheck then relxPos = xPos else relxPos = (x-xPos)+1 end
  800. end
  801. function forward(doAdd)
  802.   if doAdd == nil then doAdd = true end
  803.   if turtle.forward() then
  804.     if doAdd then
  805.       moved = moved + 1
  806.     end
  807.     if facing == 0 then
  808.       xPos = xPos + 1
  809.     elseif facing == 1 then
  810.       zPos = zPos + 1
  811.     elseif facing == 2 then
  812.       xPos = xPos - 1
  813.     elseif facing == 3 then
  814.       zPos = zPos - 1
  815.     else
  816.       error("Function forward, facing should be 0 - 3, got "..tostring(facing),2)
  817.     end
  818.     relxCalc()
  819.     return true
  820.   end
  821.   return false
  822. end
  823. function up(sneak)
  824.   sneak = sneak or 1
  825.   if inverted and sneak == 1 then
  826.     down(-1)
  827.   else
  828.     while not turtle.up() do --Absolute dig, not relative
  829.       if not dig(true, turtle.digUp) then
  830.         attackUp()
  831.         sleep(0.5)
  832.       end
  833.     end
  834.     yPos = yPos - sneak --Oh! I feel so clever
  835.   end                   --This works because inverted :)
  836.   saveProgress()
  837.   if rednetEnabled then biometrics() end
  838. end
  839. function down(sneak)
  840.   sneak = sneak or 1
  841.   local count = 0
  842.   if inverted and sneak == 1 then
  843.     up(-1)
  844.   else
  845.     while not turtle.down() do
  846.       count = count + 1
  847.       if not dig(true, turtle.digDown) then --This is absolute dig down, not relative
  848.         attackDown()
  849.         sleep(0.2)
  850.       end
  851.       if count > 20 then bedrock() end
  852.     end
  853.     yPos = yPos + sneak
  854.   end
  855.   saveProgress()
  856.   if rednetEnabled then biometrics() end
  857. end
  858. function right(num)
  859.   num = num or 1
  860.   for i=1, num do facing = coterminal(facing+1); saveProgress(); turtle.turnRight() end
  861. end
  862. function left(num)
  863.   num = num or 1
  864.   for i=1, num do facing = coterminal(facing-1); saveProgress(); turtle.turnLeft() end
  865. end
  866. function attack(doAdd, func)
  867.   doAdd = doAdd or true
  868.   func = func or turtle.attack
  869.   if func() then
  870.     if doAdd then
  871.       attacked = attacked + 1
  872.     end
  873.     return true
  874.   end
  875.   return false
  876. end
  877. function attackUp(doAdd)
  878.   if inverted then
  879.     return attack(doAdd, turtle.attackDown)
  880.   else
  881.     return attack(doAdd, turtle.attackUp)
  882.   end
  883. end
  884. function attackDown(doAdd)
  885.   if inverted then
  886.     return attack(doAdd, turtle.attackUp)
  887.   else
  888.     return attack(doAdd, turtle.attackDown)
  889.   end
  890. end
  891.  
  892.  
  893. function mine(doDigDown, doDigUp, outOfPath,doCheckInv) -- Basic Move Forward
  894.   if doCheckInv == nil then doCheckInv = true end
  895.   if doDigDown == nil then doDigDown = true end
  896.   if doDigUp == nil then doDigUp = true end
  897.   if outOfPath == nil then outOfPath = false end
  898.   isInPath = (not outOfPath) --For rednet
  899.   if inverted then
  900.     doDigUp, doDigDown = doDigDown, doDigUp --Just Switch the two if inverted
  901.   end
  902.   if doRefuel and checkFuel() <= fuelTable[fuelSafety]/2 then
  903.     for i=1, 16 do
  904.     if turtle.getItemCount(i) > 0 then
  905.       turtle.select(i)
  906.       if checkFuel() < 200 + fuelTable[fuelSafety] then
  907.         turtle.refuel()
  908.       end
  909.     end
  910.     end
  911.     turtle.select(1)
  912.   end
  913.   local count = 0
  914.   while not forward(not outOfPath) do
  915.     sleep(0) --Calls coroutine.yield to prevent errors
  916.     count = count + 1
  917.     if not dig() then
  918.       attack()
  919.     end
  920.     if count > 10 then
  921.       attack()
  922.       sleep(0.2)
  923.     end
  924.     if count > maxTries then
  925.       if turtle.getFuelLevel() == 0 then --Don't worry about inf fuel because I modified this function
  926.         saveProgress({doCheckFuel = true})
  927.         error("No more fuel",0)
  928.       elseif yPos > (startY-7) and turtle.detect() then --If it is near bedrock
  929.         bedrock()
  930.       else --Otherwise just sleep for a bit to avoid sheeps
  931.         sleep(1)
  932.       end
  933.     end
  934.   end
  935.   checkSanity() --Not kidding... This is necessary
  936.   saveProgress(tab)
  937.   if doDigUp then
  938.   while turtle.detectUp() do
  939.     sleep(0) --Calls coroutine.yield
  940.     if not dig(true,turtle.digUp) then --This needs to be an absolute, because we are switching doDigUp/Down
  941.       attackUp()
  942.       count = count + 1
  943.     end
  944.     if count > 50 and yPos > (startY-7) then --Same deal with bedrock as above
  945.       bedrock()
  946.     end
  947.     end
  948.   end
  949.   if doDigDown then
  950.    dig(true,turtle.digDown) --This needs to be absolute as well
  951.   end
  952.   percent = math.ceil(moved/moveVolume*100)
  953.   updateDisplay()
  954.   if doCheckInv and careAboutResources then
  955.     if moved%invCheckFreq == 0 then
  956.      if isFull(16-keepOpen) then dropOff() end
  957.     end
  958.   end
  959.   if rednetEnabled then biometrics() end
  960. end
  961. --Insanity Checking
  962. function checkSanity()
  963.   if not isInPath then --I don't really care if its not in the path.
  964.     return true
  965.   end
  966.   if not (facing == 0 or facing == 2) and #events == 0 then --If mining and not facing proper direction and not in a turn
  967.     turnTo(0)
  968.     rowCheck = true
  969.   end
  970.   if xPos < 0 or xPos > x or zPos < 0 or zPos > z or yPos < 0 then
  971.     saveProgress()
  972.     print("I have gone outside boundaries, attempting to fix (maybe)")
  973.     if xPos > x then goto(x, zPos, yPos, 2) end --I could do this with some fancy math, but this is much easier
  974.     if xPos < 0 then goto(1, zPos, yPos, 0) end
  975.     if zPos > z then goto(xPos, z, yPos, 3) end
  976.     if zPos < 0 then goto(xPos, 1, yPos, 1) end
  977.     setRowCheckFromPos() --Row check right (maybe left later)
  978.     relxCalc() --Get relxPos properly
  979.     eventClear()
  980.    
  981.     --[[
  982.     print("Oops. Detected that quarry was outside of predefined boundaries.")
  983.     print("Please go to my forum thread and report this with a short description of what happened")
  984.     print("If you could also run \"pastebin put Civil_Quarry_Restore\" and give me that code it would be great")
  985.     error("",0)]]
  986.   end
  987. end
  988.  
  989. local function fromBoolean(input) --Like a calculator
  990. if input then return 1 end
  991. return 0
  992. end
  993. local function multBoolean(first,second) --Boolean multiplication
  994. return (fromBoolean(first) * fromBoolean(second)) == 1
  995. end
  996. function coterminal(num, limit) --I knew this would come in handy :D
  997. limit = limit or 4 --This is for facing
  998. return math.abs((limit*fromBoolean(num < 0))-(math.abs(num)%limit))
  999. end
  1000. if tArgs["-manualpos"] then
  1001.   facing = coterminal(facing) --Done to improve support for "-manualPos"
  1002.   if facing == 0 then rowCheck = true elseif facing == 2 then rowCheck = false end --Ditto
  1003.   relxCalc() --Ditto
  1004. end
  1005.  
  1006. --Direction: Front = 0, Right = 1, Back = 2, Left = 3
  1007.  
  1008. function turnTo(num)
  1009.   num = num or facing
  1010.   num = coterminal(num) --Prevent errors
  1011.   local turnRight = true
  1012.   if facing-num == 1 or facing-num == -3 then turnRight = false end --0 - 1 = -3, 1 - 0 = 1, 2 - 1 = 1
  1013.   while facing ~= num do          --The above is used to smartly turn
  1014.     if turnRight then
  1015.       right()
  1016.     else
  1017.       left()
  1018.     end
  1019.   end
  1020. end
  1021. function goto(x,z,y, toFace, destination)
  1022.   --Will first go to desired z pos, then x pos, y pos varies
  1023.   x = x or 1; y = y or 1; z = z or 1; toFace = toFace or facing
  1024.   gotoDest = destination or "" --This is used by biometrics
  1025.   --Possible destinations: layerStart, quarryStart
  1026.   if yPos > y then --Will go up first if below position
  1027.     while yPos~=y do up() end
  1028.   end
  1029.   if zPos > z then
  1030.     turnTo(3)
  1031.   elseif zPos < z then
  1032.     turnTo(1)
  1033.   end
  1034.   while zPos ~= z do mine(false,false,true,false) end
  1035.   if xPos > x then
  1036.     turnTo(2)
  1037.   elseif xPos < x then
  1038.     turnTo(0)
  1039.   end
  1040.   while xPos ~= x do mine(false,false,true,false) end
  1041.   if yPos < y then --Will go down after if above position
  1042.     while yPos~=y do down() end
  1043.   end
  1044.   turnTo(toFace)
  1045.   saveProgress()
  1046.   gotoDest = ""
  1047. end
  1048. function getNumOpenSlots()
  1049.   local toRet = 0
  1050.   for i=1, 16 do
  1051.     if turtle.getItemCount(i) == 0 then
  1052.       toRet = toRet + 1
  1053.     end
  1054.   end
  1055.   return toRet
  1056. end
  1057. function drop(side, final, allowSkip)
  1058. side = sides[side] or "front"    --The final number means that it will
  1059. if final then final = 0 else final = 1 end --drop a whole stack at the end
  1060. local allowSkip = allowSkip or (final == 0) --This will allow drop(side,t/f, rednetConnected)
  1061. count()
  1062. if doRefuel then
  1063.   for i=1, 16 do
  1064.     if slot[i][1] == 2 then
  1065.       turtle.select(i); turtle.refuel()
  1066.     end
  1067.   end
  1068.   turtle.select(1)
  1069. end
  1070. if side == "right" then turnTo(1) end
  1071. if side == "left" then turnTo(3) end
  1072. local whereDetect, whereDrop1, whereDropAll
  1073. local _1 = slot[1][2] - final --All but one if final, all if not final
  1074. if side == "top" then
  1075. whereDetect = turtle.detectUp ; whereDrop = turtle.dropUp
  1076. elseif side == "bottom" then
  1077. whereDetect = turtle.detectDown ; whereDrop = turtle.dropDown
  1078. else
  1079. whereDetect = turtle.detect; whereDrop = turtle.drop
  1080. end
  1081. local function waitDrop(val) --This will just drop, but wait if it can't
  1082.   val = val or 64
  1083.   local try = 1
  1084.   while not whereDrop(val) do
  1085.     print("Chest Full, Try "..try)
  1086.     chestFull = true
  1087.     if rednetEnabled then --To send that the chest is full
  1088.       biometrics()
  1089.     end
  1090.     try = try + 1
  1091.     sleep(2)
  1092.   end
  1093.   chestFull = false
  1094. end
  1095. repeat
  1096. local detected = whereDetect()
  1097. if detected then
  1098.   waitDrop(_1)
  1099.   for i=1, 2 do --This is so I quit flipping missing items when chests are partially filled
  1100.     for i=2, 16 do
  1101.       if turtle.getItemCount(i) > 0 then
  1102.         turtle.select(i)
  1103.         waitDrop(nil, i)
  1104.       end
  1105.     end
  1106.   end
  1107. elseif not allowSkip then
  1108.   print("Waiting for chest placement place a chest to continue")
  1109.   while not whereDetect() do
  1110.     sleep(1)
  1111.   end
  1112. end
  1113. until detected or allowSkip
  1114. if not allowSkip then totals.cobble = totals.cobble - 1 end
  1115. turtle.select(1)
  1116. end
  1117. function dropOff() --Not local because called in mine()
  1118.   local currX,currZ,currY,currFacing = xPos, zPos, yPos, facing
  1119.   if careAboutResources then
  1120.     if not enderChestEnabled then --Regularly
  1121.       eventAdd("goto", 1,1,currY,2) --Need this step for "-startDown"
  1122.       eventAdd("goto(0,1,1,2)")
  1123.       eventAdd("drop", dropSide,false)
  1124.       eventAdd("turnTo(0)")
  1125.       eventAdd("mine",false,false,true,false)
  1126.       eventAdd("goto(1,1,1, 0)")
  1127.       eventAdd("goto", 1, 1, currY, 0)
  1128.       eventAdd("goto", currX,currZ,currY,currFacing)
  1129.     else --If using an enderChest
  1130.       if turtle.getItemCount(enderChestSlot) ~= 1 then eventAdd("promptEnderChest()") end
  1131.       eventAdd("turnTo",currFacing-2)
  1132.       eventAdd("dig",false)
  1133.       eventAdd("turtle.select",enderChestSlot)
  1134.       eventAdd("turtle.place")
  1135.       eventAdd("drop","front",false)
  1136.       eventAdd("turtle.select", enderChestSlot)
  1137.       eventAdd("dig",false)
  1138.       eventAdd("turnTo",currFacing)
  1139.       eventAdd("turtle.select(1)")
  1140.     end
  1141.   runAllEvents()
  1142.   numDropOffs = numDropOffs + 1 --Analytics tracking
  1143.   end
  1144. return true
  1145. end
  1146. function endingProcedure() --Used both at the end and in "biometrics"
  1147.   eventAdd("goto",1,1,yPos,2,"quarryStart") --Allows for startDown variable
  1148.   eventAdd("goto",0,1,1,2, "quarryStart") --Go back to base
  1149.   runAllEvents()
  1150.   --Output to a chest or sit there
  1151.   if enderChestEnabled then
  1152.     while turtle.detect() do dig(false) end --This gets rid of blocks in front of the turtle.
  1153.     eventAdd("turtle.select",enderChestSlot)
  1154.     eventAdd("turtle.place")
  1155.     eventAdd("turtle.select(1)")
  1156.   end
  1157.   eventAdd("drop",dropSide, true)
  1158.   eventAdd("turnTo(0)")
  1159.  
  1160.   --Display was moved above to be used in bedrock function
  1161.   eventAdd("display")
  1162.   --Log current mining run
  1163.   eventAdd("logMiningRun",logExtension)
  1164.   toQuit = true --I'll use this flag to clean up
  1165.   runAllEvents()
  1166.   --Cleanup
  1167.   turtle.getFuelLevel = getFuel
  1168. end
  1169. function bedrock()
  1170. foundBedrock = true --Let everyone know
  1171. if rednetEnabled then biometrics() end
  1172. if checkFuel() == 0 then error("No Fuel",0) end
  1173. local origin = {x = xPos, y = yPos, z = zPos}
  1174. print("Bedrock Detected")
  1175. if turtle.detectUp() then
  1176. print("Block Above")
  1177. local var
  1178. if facing == 0 then var = 2 elseif facing == 2 then var = 0 else error("Was facing left or right on bedrock") end
  1179. goto(xPos,zPos,yPos,var)
  1180. for i=1, relxPos do mine(true,true); end
  1181. end
  1182. endingProcedure()
  1183. print("\nFound bedrock at these coordinates: ")
  1184. print(origin.x," Was position in row\n",origin.z," Was row in layer\n",origin.y," Blocks down from start")
  1185. error("",0)
  1186. end
  1187.  
  1188. function endOfRowTurn(startZ, wasFacing, mineFunctionTable)
  1189. local halfFacing = 1
  1190. local toFace = coterminal(wasFacing + 2) --Opposite side
  1191. if zPos == startZ then
  1192.   if facing ~= halfFacing then turnTo(halfFacing) end
  1193.   mine(unpack(mineFunctionTable or {}))
  1194. end
  1195. if facing ~= toFace then
  1196.   turnTo(toFace)
  1197. end
  1198. end
  1199.  
  1200. -------------------------------------------------------------------------------------
  1201. --Pre-Mining Stuff dealing with session persistence
  1202. runAllEvents()
  1203. if toQuit then error("",0) end --This means that it was stopped coming for its last drop
  1204.  
  1205. local doDigDown, doDigUp = (lastHeight ~= 1), (lastHeight == 0) --Used in lastHeight
  1206. if not restoreFoundSwitch then --Regularly
  1207.   --Check if it is a mining turtle
  1208.   if not isMiningTurtle then
  1209.     local a, b = turtle.dig()
  1210.     if a then mined = mined + 1; isMiningTurtle = true
  1211.     elseif b == "Nothing to dig with" then
  1212.       print("This is not a mining turtle. To make a mining turtle, craft me together with a diamond pickaxe")
  1213.       error("",0)
  1214.     end
  1215.   end
  1216.   mine(false,false,true) --Get into quarry by going forward one
  1217.   if gpsEnabled and not restoreFoundSwitch then --The initial locate is done in the arguments. This is so I can figure out what quadrant the turtle is in.
  1218.     gpsSecondPos = {gps.locate(gpsTimeout)} --Note: Does not run this if it has already been restarted.
  1219.   end
  1220.   for i = 1, startDown do
  1221.     eventAdd("down") --Add a bunch of down events to get to where it needs to be.
  1222.   end
  1223.   runAllEvents()
  1224.   if not(y == 1 or y == 2) then down() end --Go down. If y is one or two, it doesn't need to do this.
  1225. else --restore found
  1226.   if not(layersDone == layers and not doDigDown) then digDown() end
  1227.   if not(layersDone == layers and not doDigUp) then digUp() end  --Get blocks missed before stopped
  1228. end
  1229. --Mining Loops--------------------------------------------------------------------------
  1230. turtle.select(1)
  1231. while layersDone <= layers do -------------Height---------
  1232. local lastLayer = layersDone == layers --If this is the last layer
  1233. local secondToLastLayer = (layersDone + 1) == layers --This is for the going down at the end of a layer.
  1234. moved = moved + 1 --To account for the first position in row as "moved"
  1235. if doDigDown then digDown() end --This is because it doesn't mine first block in layer
  1236. if not restoreFoundSwitch then rowCheck = true end
  1237. relxCalc()
  1238. while zPos <= z do -------------Width----------
  1239. while relxPos < x do ------------Length---------
  1240. mine(not lastLayer or (doDigDown and lastLayer), not lastLayer or (doDigUp and lastLayer)) --This will be the idiom that I use for the mine function
  1241. end ---------------Length End-------
  1242. if zPos ~= z then --If not on last row of section
  1243.   local func
  1244.   if rowCheck == true then --Swithcing to next row
  1245.   func = "right"; rowCheck = false; else func = false; rowCheck = true end --Which way to turn
  1246.     eventAdd("endOfRowTurn", zPos, facing , {not lastLayer or (doDigDown and lastLayer), not lastLayer or (doDigUp and lastLayer)}) --The table is passed to the mine function
  1247.     runAllEvents()
  1248. else break
  1249. end
  1250. end ---------------Width End--------
  1251. eventAdd("goto",1,1,yPos,0, "layerStart") --Goto start of layer
  1252. if not lastLayer then --If there is another layer
  1253.   for i=1, 2+fromBoolean(not(lastHeight~=0 and secondToLastLayer)) do eventAdd("down()") end --The fromBoolean stuff means that if lastheight is 1 and last and layer, will only go down two
  1254. end
  1255. eventAdd("setRowCheckFromPos")
  1256. eventAdd("relxCalc")
  1257. layersDone = layersDone + 1
  1258. restoreFoundSwitch = false --This is done so that rowCheck works properly upon restore
  1259. runAllEvents()
  1260. end ---------------Height End-------
  1261.  
  1262. endingProcedure() --This takes care of getting to start, dropping in chest, and displaying ending screen
RAW Paste Data