Advertisement
civilwargeeky

Quarry 3.5.3 New Ore Quarry Hack

Sep 28th, 2014
7,070
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 68.01 KB | None | 0 0
  1. --Civilwargeeky's Quarry Program--
  2.   VERSION = "3.5.3 OreQuarry"
  3. --[[
  4. Recent Changes:
  5.   New Ore Quarry System
  6. ]]
  7. --Defining things
  8. civilTable = nil; _G.civilTable = {}; setmetatable(civilTable, {__index = _G}); setfenv(1,civilTable)
  9. originalDay = os.day() --Used in logging
  10. numResumed = 0 --Number of times turtle has been resumed
  11. -------Defaults for Arguments----------
  12. --Arguments assignable by text
  13. x,y,z = 3,3,3 --These are just in case tonumber fails
  14. inverted = false --False goes from top down, true goes from bottom up [Default false]
  15. rednetEnabled = false --Default rednet on or off  [Default false]
  16. --Arguments assignable by tArgs
  17. dropSide = "front" --Side it will eject to when full or done [Default "front"]
  18. careAboutResources = true --Will not stop mining once inventory full if false [Default true]
  19. doCheckFuel = true --Perform fuel check [Default true]
  20. doRefuel = false --Whenever it comes to start location will attempt to refuel from inventory [Default false]
  21. keepOpen = 1 --How many inventory slots it will attempt to keep open at all times [Default 1]
  22. fuelSafety = "moderate" --How much fuel it will ask for: safe, moderate, and loose [Default moderate]
  23. saveFile = "Civil_Quarry_Restore" --Where it saves restore data [Default "Civil_Quarry_Restore"]
  24. doBackup = true --If it will keep backups for session persistence [Default true]
  25. uniqueExtras = 8 --How many different items (besides cobble) the turtle expects. [Default 8]
  26. maxTries = 50 --How many times turtle will try to dig a block before it "counts" bedrock [Default 50]
  27. gpsEnabled = false -- If option is enabled, will attempt to find position via GPS api [Default false]
  28. gpsTimeout = 3 --The number of seconds the program will wait to get GPS coords. Not in arguments [Default 3]
  29. logging = true --Whether or not the turtle will log mining runs. [Default ...still deciding]
  30. logFolder = "Quarry_Logs" --What folder the turtle will store logs in [Default "Quarry_Logs"]
  31. logExtension = "" --The extension of the file (e.g. ".txt") [Default ""]
  32. startDown = 0 --How many blocks to start down from the top of the mine [Default 0]
  33. enderChestEnabled = false --Whether or not to use an ender chest [Default false]
  34. enderChestSlot = 16 --What slot to put the ender chest in [Default 16]
  35. oreQuarry = false --Enables ore quarry functionality [Default false]
  36. oreQuarryBlacklistName = "oreQuarryBlacklist.txt" --This is the file that will be parsed for item names [Default "oreQuarryBlacklist"]
  37. dumpCompareItems = true --If ore quarry, the turtle will dump items compared to (like cobblestone) [Default true]
  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. --AVERAGE USER: YOU DON'T CARE BELOW THIS POINT
  52.  
  53. local help_paragraph = [[
  54. Welcome!: Welcome to quarry help. Below are help entries for all parameters. Examples and tips are at the bottom.
  55. -Default: This will force no prompts. If you use this and nothing else, only defaults will be used.
  56. -dim: [length] [width] [height] This sets the dimensions for the quarry
  57. -invert: [t/f] If true, quarry will be inverted (go up instead of down)
  58. -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
  59. -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
  60. -oreQuarry: [t/f] If true, the turtle will use ore quarry mode. It will not mine the blocks that are placed in the turtle initially. So if you put in stone, it will ignore stone blocks and only mine ores.
  61. -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.
  62. -doRefuel: [t/f] If true, the turtle will refuel itself with coal and planks it finds on its mining run
  63. -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...
  64. -uniqueExtras: [number] The expected number of slots filled with low-stacking items like ore. Higher numbers request more fuel.
  65. -chest: [side] This specifies what side the chest at the end will be on. You can say "top", "bottom", "front", "left", or "right"
  66. -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.
  67. -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
  68. -sendChannel: [number] This is what channel your turtle will send rednet messages on
  69. -receiveChannel: [number] This is what channel your turtle will receive rednet messages on
  70. -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
  71. -maxTries: [number] This is the number of times the turtle will try to dig before deciding its run into bedrock.
  72. -logging: [t/f] If true, will record information about its mining run in a folder at the end of the mining run
  73. -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...)
  74. -saveFile: [word] This is what the backup file will be called
  75. -logFolder: [word] The folder that quarry logs will be stored in
  76. -logExtension: [word] The extension given to each quarry log (e.g. ".txt" or ".notepad" or whatever)
  77. -keepOpen: [number] This is the number of the slots the turtle will make sure are open. It will check every time it mines
  78. -careAboutResources: [t/f] Who cares about the materials! If set to false, it will just keep mining when its inventory is full
  79. -startDown: [number] If you set this, the turtle will go down this many blocks from the start before starting its quarry
  80.   =
  81.   C _ |
  82.       |
  83.       |
  84.       |
  85.       |_ _ _ _ >
  86. -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"
  87. -help: Thats what this is :D
  88. Examples: Everything below is examples and tips for use
  89. Important Note:
  90.  None of the above parameters are necessary. They all have default values, and the above are just if you want to change them.
  91. Examples [1]:
  92.  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".
  93.   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?
  94. Examples [2]:
  95.   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.
  96. Examples [2] [cont.]:
  97.   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
  98.   "quarry -dim 40x20x9 -invert false -startDown 45 -rednet true -enderChest 12 -restore"
  99.   BAM. Now you can just let that turtle do it's thing
  100. Tips:
  101.  The order of the parameters doesn't matter. "quarry -invert false -rednet true" is the same as "quarry -rednet true -invert false"
  102.  
  103.   Capitalization doesn't matter. "quarry -iNVErt FALSe" does the same thing as "quarry -invert false"
  104. Tips [cont.]:
  105.  For [t/f] parameters, you can also use "yes" and "no" so "quarry -invert yes"
  106.  
  107.  For [t/f] parameters, it only cares about the first letter. So you can use "quarry -invert t" or "quarry -invert y"
  108. Tips [cont.]:
  109.  If you are playing with fuel turned off, the program will automatically change settings for you so you don't have to :D
  110.  
  111.   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.
  112. Internal Config:
  113.   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.
  114.  
  115.   You can also use this if there are settings that you don't like the default value of.
  116. ]]
  117.  
  118. --Parsing help for display
  119. --[[The way the help table works:
  120. All help indexes are numbered. There is a help[i].title that contains the title,
  121. and the other lines are in help[i][1] - help[i][#help[i] ]
  122. Different lines (e.g. other than first) start with a space.
  123. As of now, the words are not wrapped, fix that later]]
  124. local help = {}
  125. local i = 0
  126. local titlePattern = ".-%:" --Find the beginning of the line, then characters, then a ":"
  127. local textPattern = "%:.+" --Find a ":", then characters until the end of the line
  128. for a in help_paragraph:gmatch("\n?.-\n") do --Matches in between newlines
  129. local current = string.sub(a,1,-2).."" --Concatenate Trick
  130. if string.sub(current,1,1) ~= " " then
  131. i = i + 1
  132. help[i] = {}
  133. help[i].title = string.sub(string.match(current, titlePattern),1,-2)..""
  134. help[i][1] = string.sub(string.match(current,textPattern) or " ",3,-1)
  135. elseif string.sub(current,1,1) == " " then
  136. table.insert(help[i], string.sub(current,2, -1).."")
  137. end
  138. end
  139.  
  140. local supportsRednet
  141. if peripheral.find then
  142.  supportsRednet = peripheral.find("modem") or false
  143. else
  144.  supportsRednet = (peripheral.getType("right") == "modem") or false
  145. end
  146.  
  147. local tArgs = {...}
  148. --Pre-defining variables
  149.      xPos,yPos,zPos,facing,percent,mined,moved,relxPos, rowCheck, connected, isInPath, layersDone, attacked, startY, chestFull, gotoDest, atChest, fuelLevel, numDropOffs, allowedItems, compareSlots, dumpSlots, selectedSlot, extraDropItems
  150.    = 0,   1,   1,   0,     0,      0,    0,    1,       true   ,  false,     true,     1,          0,        0,      false,     "",       false,   0,         0,           {},             {},           {},      1,            false
  151.    
  152. for i=1, 16 do --Initializing various inventory management tables
  153.  allowedItems[i] = 0 --Number of items allowed in slot when dropping items
  154.  dumpSlots[i] = false --Does this slot contain junk items?
  155. end --compareSlots is a table of the compare slots, not all slots with a condition
  156. totals = {cobble = 0, fuel = 0, other = 0} -- Total for display (cannot go inside function), this goes up here because many functions use it
  157.  
  158. function resetDumpSlots()
  159.    for i=1, 16 do
  160.      if oldOreQuarry then
  161.        if turtle.getItemCount(i) > 0 and i~= enderChestSlot then
  162.          dumpSlots[i] = true
  163.        else
  164.          dumpSlots[i] = false
  165.        end
  166.      else
  167.        dumpSlots[i] = false
  168.      end
  169.    end
  170.    if not oldOreQuarry and enderChestSlot == 1 then
  171.      dumpSlots[2] = true
  172.    elseif not oldOreQuarry then
  173.      dumpSlots[1] = true
  174.    end
  175. end
  176.        
  177.  
  178. local function copyTable(tab) local toRet = {}; for a, b in pairs(tab) do toRet[a] = b end; return toRet end --This goes up here because it is a basic utility
  179.  
  180. --NOTE: rowCheck is a bit. true = "right", false = "left"
  181.    
  182. local foundBedrock = false
  183.  
  184. local getFuel, checkFuel
  185. if turtle then
  186.  getFuel = turtle.getFuelLevel  --This is for cleanup at the end
  187.  do --Common variable name...
  188.  local flag = turtle.getFuelLevel() == "unlimited"--Unlimited screws up my calculations
  189.  if flag then --Fuel is disabled
  190.    turtle.getFuelLevel = function() return math.huge end --Infinite Fuel
  191.  end --There is no "else" because it will already return the regular getFuel
  192.  end
  193.  checkFuel = turtle.getFuelLevel --Just an alias for backwards compat
  194.  
  195.  turtle.select(1) --To ensure this is correct
  196. end
  197.  
  198.  
  199. function select(slot)
  200.  if slot ~= selectedSlot then
  201.    selectedSlot = slot
  202.    return turtle.select(slot), selectedSlot
  203.  end
  204. end
  205.  
  206.  
  207. -----------------------------------------------------------------
  208. --Input Phase
  209. local function screen(xPos,yPos)
  210. xPos, yPos = xPos or 1, yPos or 1
  211. term.setCursorPos(xPos,yPos); term.clear(); end
  212. local function screenLine(xPos,yPos)
  213. term.setCursorPos(xPos,yPos); term.clearLine(); end
  214.  
  215. screen(1,1)
  216. print("----- Welcome to Quarry! -----")
  217. print("")
  218.  
  219. local sides = {top = "top", right = "right", left = "left", bottom = "bottom", front = "front"} --Used to whitelist sides
  220. local changedT, tArgsWithUpper = {}, {}
  221. changedT.new = function(key, value) table.insert(changedT,{key, value}) end --Numeric list of lists
  222. local function capitalize(text) return (string.upper(string.sub(text,1,1))..string.sub(text,2,-1)) end
  223. 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
  224.  
  225. local restoreFound, restoreFoundSwitch = false --Initializing so they are in scope
  226. 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.
  227.   if trigger == nil then trigger = true end --Defaults to being able to run
  228.   if not trigger then return end --This is what the trigger is for. Will not run if trigger not there
  229.   if restoreFoundSwitch or tArgs["-default"] then forcePrompt = false end --Don't want to prompt if these
  230.   local toGetText = name:lower() --Because all params are now lowered
  231.   local formatType = formatString:match("^%a+"):lower() or error("Format String Unknown: "..formatString) --Type of format string
  232.   local args = formatString:sub(({formatString:find(formatType)})[2] + 2).."" --Everything in formatString but the type and space
  233.   local variable = variableOverride or name --Goes first to the override for name
  234.   local func = loadstring("return "..variable)
  235.   setfenv(func,getfenv(1))
  236.   local originalValue = assert(func)() --This is the default value, for checking to add to changed table
  237.   if originalValue == nil then error("From addParam, \""..variable.."\" returned nil",2) end --I may have gotten a wrong variable name
  238.   local givenValue, toRet --Initializing for use
  239.   if tArgs["-"..toGetText] then
  240.     givenValue = tArgsWithUpper[tArgs["-"..toGetText]+1] --This is the value after the desired parameter
  241.   elseif forcePrompt then
  242.     write(displayText.."? ")
  243.     givenValue = io.read()
  244.   end
  245.   if formatType == "force" then --This is the one exception. Should return true if givenValue is nothing
  246.     toRet = (tArgs["-"..toGetText] and true) or false --Will return true if param exists, otherwise false
  247.   end
  248.   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"
  249.   if formatType == "boolean" then --All the format strings will be basically be put through a switch statement
  250.     toRet = givenValue:sub(1,1):lower() == "y" or givenValue:sub(1,1):lower() == "t" --Accepts true or yes
  251.     if formatString == "boolean special" then
  252.       toRet = givenValue:sub(1,1):lower() ~= "n" and givenValue:sub(1,1):lower() ~= "f" --Accepts anything but false or no
  253.     end
  254.   elseif formatType == "string" then
  255.     toRet = givenValue:match("^[%w%.]+") --Basically anything not a space or control character etc
  256.   elseif formatType == "number" then
  257.     toRet = tonumber(givenValue) --Note this is a local, not the above so we don't change anything
  258.     if not toRet then return end --We need a number... Otherwise compare errors
  259.     toRet = math.abs(math.floor(toRet)) --Get proper integers
  260.     local startNum, endNum = formatString:match("(%d+)%-(%d+)") --Gets range of numbers
  261.     startNum, endNum = tonumber(startNum), tonumber(endNum)
  262.     if not ((toRet >= startNum) and (toRet <= endNum)) then return end --Can't use these
  263.   elseif formatType == "side" then
  264.     local exclusionTab = {} --Ignore the wizardry here. Just getting arguments without format string
  265.     for a in args:gmatch("%S+") do exclusionTab[a] = true end --This makes a list of the sides to not include
  266.     if not exclusionTab[givenValue] then toRet = sides[givenValue] end --If side is not excluded
  267.   elseif formatType == "list" then
  268.     toRet = {}
  269.     for a in args:gmatch("[^,]") do
  270.       table.insert(toRet,a)
  271.     end
  272.   elseif formatType == "force" then --Do nothing, everything is already done
  273.   else error("Improper formatType",2)
  274.   end
  275.   if toRet == nil then return end --Don't want to set variables to nil... That's bad
  276.   tempParam = toRet --This is what loadstring will see :D
  277.   local func = loadstring(variable.." = tempParam")
  278.   setfenv(func, getfenv(1))
  279.   func()
  280.   tempParam = nil --Cleanup of global
  281.   if toRet ~= originalValue and displayText ~= "" then
  282.     changedT.new(displayText, tostring(toRet))
  283.   end
  284.   return toRet
  285. end
  286.  
  287. --Check if it is a turtle
  288. if not(turtle or tArgs["help"] or tArgs["-help"] or tArgs["-?"] or tArgs["?"]) then --If all of these are false then
  289.   print("This is not a turtle, you might be looking for the \"Companion Rednet Program\" \nCheck My forum thread for that")
  290.   print("Press 'q' to quit, or any other key to start help ")
  291.   if ({os.pullEvent("char")})[2] ~= "q" then tArgs.help = true else error("",0) end
  292. end
  293.  
  294. if tArgs["help"] or tArgs["-help"] or tArgs["-?"] or tArgs["?"] then
  295.   print("You have selected help, press any key to continue"); print("Use arrow keys to navigate, q to quit"); os.pullEvent("key")
  296.   local pos = 1
  297.   local key = 0
  298.   while pos <= #help and key ~= keys.q do
  299.     if pos < 1 then pos = 1 end
  300.     screen(1,1)
  301.     print(help[pos].title)
  302.     for a=1, #help[pos] do print(help[pos][a]) end
  303.     repeat
  304.       _, key = os.pullEvent("key")
  305.     until key == 200 or key == 208 or key == keys.q
  306.     if key == 200 then pos = pos - 1 end
  307.     if key == 208 then pos = pos + 1 end
  308.   end
  309.   error("",0)
  310. end
  311.  
  312. --Saving
  313. addParam("doBackup", "Backup Save File", "boolean")
  314. addParam("saveFile", "Save File Name", "string")
  315.  
  316. restoreFound = fs.exists(saveFile)
  317. restoreFoundSwitch = (tArgs["-restore"] or tArgs["-resume"] or tArgs["-atchest"]) and restoreFound
  318. if restoreFoundSwitch then
  319.   local file = fs.open(saveFile,"r")
  320.   local test = file.readAll() ~= ""
  321.   file.close()
  322.   if test then
  323.     os.run(getfenv(1),saveFile) --This is where the actual magic happens
  324.     numResumed = numResumed + 1
  325.     if turtle.getFuelLevel() ~= math.huge then --If turtle uses fuel
  326.       if fuelLevel - turtle.getFuelLevel() == 1 then
  327.         if facing == 0 then xPos = xPos + 1
  328.         elseif facing == 2 then xPos = xPos - 1
  329.         elseif facing == 1 then zPos = zPos + 1
  330.         elseif facing == 3 then zPos = zPos - 1 end
  331.       elseif fuelLevel - turtle.getFuelLevel() ~= 0 then
  332.         print("Very Strange Fuel in Restore Section...")
  333.         print("Current: ",turtle.getFuelLevel())
  334.         print("Saved: ",fuelLevel)
  335.         print("Difference: ",fuelLevel - turtle.getFuelLevel())
  336.         os.pullEvent("char")
  337.       end
  338.      end
  339.     if gpsEnabled then --If it had saved gps coordinates
  340.       print("Found GPS Start Coordinates")
  341.       local currLoc = {gps.locate(gpsTimeout)} or {}
  342.       local backupPos = {xPos, yPos, zPos} --This is for comparing to later
  343.       if #currLoc > 0 and #gpsStartPos > 0 and #gpsSecondPos > 0 then --Cover all the different positions I'm using
  344.         print("GPS Position Successfully Read")
  345.         if currLoc[1] == gpsStartPos[1] and currLoc[3] == gpsStartPos[3] then --X coord, y coord, z coord in that order
  346.           xPos, yPos, zPos = 0,1,1
  347.           if facing ~= 0 then turnTo(0) end
  348.           print("Is at start")
  349.         else
  350.           if inverted then --yPos setting
  351.           ------------------------------------------------FIX THIS
  352.           end
  353.           local a, b = copyTable(gpsStartPos), copyTable(gpsSecondPos) --For convenience
  354.           if b[3] - a[3] == -1 then--If went north (-Z)
  355.             a[1] = a[1] - 1 --Shift x one to west to create a "zero"
  356.             xPos, zPos = -currLoc[3] + a[3], currLoc[1] + -a[1]
  357.           elseif b[1] - a[1] == 1 then--If went east (+X)
  358.             a[3] = a[3] - 1 --Shift z up one to north to create a "zero"
  359.             xPos, zPos = currLoc[1] + -a[1], currLoc[3] + -a[3]
  360.           elseif b[3] - a[3] == 1 then--If went south (+Z)
  361.             a[1] = a[1] + 1 --Shift x one to east to create a "zero"
  362.             xPos, zPos = currLoc[3] + a[3], -currLoc[1] + a[3]
  363.           elseif b[1] - a[1] == -1 then--If went west (-X)
  364.             a[3] = a[3] + 1 --Shift z down one to south to create a "zero"
  365.             xPos, zPos = -currLoc[1] + a[1], -currLoc[3] + a[3]
  366.           else
  367.             print("Improper Coordinates")
  368.             print("GPS Locate Failed, Using Standard Methods")        ----Maybe clean this up a bit to use flags instead.
  369.           end  
  370.         end
  371.         print("X Pos: ",xPos)
  372.         print("Y Pos: ",yPos)
  373.         print("Z Pos: ",zPos)
  374.         print("Facing: ",facing)
  375.         for i=1, 3, 2 do --We want 1 and 3, but 2 could be coming back to start.
  376.           if backupPos[i] ~= currLoc[i] then
  377.             events = {} --We want to remove event queue if not in proper place, so won't turn at end of row or things.
  378.           end
  379.         end
  380.       else
  381.         print("GPS Locate Failed, Using Standard Methods")
  382.       end    
  383.     print("Restore File read successfully. Starting in 3"); sleep(3)
  384.     end
  385.   else
  386.     fs.delete(saveFile)
  387.     print("Restore file was empty, sorry, aborting")
  388.     error("",0)
  389.   end
  390. else --If turtle is just starting
  391.   events = {} --This is the event queue :D
  392.   originalFuel = checkFuel() --For use in logging. To see how much fuel is REALLY used
  393. end
  394.  
  395. --Dimensions
  396. if tArgs["-dim"] then
  397.   local a,b,c = x,y,z
  398.   local num = tArgs["-dim"]
  399.   x = tonumber(tArgs[num + 1]) or x; z = tonumber(tArgs[num + 2]) or z; y = tonumber(tArgs[num + 3]) or y
  400.   if a ~= x then changedT.new("Length", x) end
  401.   if c ~= z then changedT.new("Width", z) end
  402.   if b ~= y then changedT.new("Height", y) end
  403. elseif not (tArgs["-default"] or restoreFoundSwitch) then
  404.   print("What dimensions?")
  405.   print("")
  406.   --This will protect from negatives, letters, and decimals
  407.   term.write("Length? ")
  408.   x = math.floor(math.abs(tonumber(io.read()) or x))
  409.   term.write("Width? ")
  410.   z = math.floor(math.abs(tonumber(io.read()) or z))
  411.   term.write("Height? ")
  412.   y = math.floor(math.abs(tonumber(io.read()) or y))
  413.   changedT.new("Length",x); changedT.new("Width",z); changedT.new("Height",y)
  414. end
  415. --Params: parameter/variable name, display name, type, force prompt, boolean condition, variable name override
  416. --Invert
  417. addParam("invert", "Inverted","boolean", true, nil, "inverted")
  418. addParam("startDown","Start Down","number 1-256")
  419. --Inventory
  420. addParam("chest", "Chest Drop Side", "side front", nil, nil, "dropSide")
  421. addParam("enderChest","Ender Chest Enabled","boolean special", nil, nil, "enderChestEnabled") --This will accept anything (including numbers) thats not "f" or "n"
  422. addParam("enderChest", "Ender Chest Slot", "number 1-16", nil, nil, "enderChestSlot") --This will get the number slot if given
  423. if not enderChestEnabled then enderChestSlot = 0 end --This makes everything better
  424. --Rednet
  425. addParam("rednet", "Rednet Enabled","boolean",true, supportsRednet, "rednetEnabled")
  426. addParam("gps", "GPS Location Services", "force", nil, (not restoreFoundSwitch) and supportsRednet, "gpsEnabled" ) --Has these triggers so that does not record position if restarted.
  427. if gpsEnabled and not restoreFoundSwitch then
  428.   gpsStartPos = {gps.locate(gpsTimeout)} --Stores position in array
  429.   gpsEnabled = #gpsStartPos > 0 --Checks if location received properly. If not, position is not saved
  430. end
  431. addParam("sendChannel", "Rednet Send Channel", "number 1-65535", false, supportsRednet, "channels.send")
  432. addParam("receiveChannel","Rednet Receive Channel", "number 1-65535", false, supportsRednet, "channels.receive")
  433. --Fuel
  434. addParam("uniqueExtras","Unique Items", "number 0-15")
  435. addParam("doRefuel", "Refuel from Inventory","boolean", nil, turtle.getFuelLevel() ~= math.huge) --math.huge due to my changes
  436. addParam("doCheckFuel", "Check Fuel", "boolean", nil, turtle.getFuelLevel() ~= math.huge)
  437. --Logging
  438. addParam("logging", "Logging", "boolean")
  439. addParam("logFolder", "Log Folder", "string")
  440. addParam("logExtension","Log Extension", "string")
  441. --Misc
  442. addParam("startY", "Start Y","number 1-256")
  443. addParam("keepOpen", "Slots to Keep Open", "number 1-15")
  444. addParam("careAboutResources", "Care About Resources","boolean")
  445. addParam("maxTries","Tries Before Bedrock", "number 1-9001")
  446. --Ore Quarry
  447. addParam("oreQuarry", "Ore Quarry", "boolean" )
  448. addParam("dumpCompareItems", "Dump Compare Items", "boolean", nil, oreQuarry) --Do not dump compare items if not oreQuarry
  449.  
  450. if oreQuarry and not turtle.inspect then
  451.   print("You are not using the latest computercraft. You can not use 'Super Ore Quarry'.\nPlease get the other version of quarry from my forum thread until you update.")
  452.   error("You can still use regular quarry with no issues",0)
  453. end
  454.  
  455. --Manual Position
  456. if tArgs["-manualpos"] then --Gives current coordinates in xPos,zPos,yPos, facing
  457.   local a = tArgs["-manualpos"]
  458.   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
  459.   changedT.new("xPos",xPos); changedT.new("zPos",zPos); changedT.new("yPos",yPos); changedT.new("facing",facing)
  460.   restoreFoundSwitch = true --So it doesn't do beginning of quarry behavior
  461.   for i=0,4 do tArgs[a+i] = "" end --Get rid of this argument from future restores
  462. end
  463. 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.
  464.   local neededLayer = math.floor((yPos+1)/3)*3-1 --Make it a proper layer, +- because mining rows are 2, 5, etc.
  465.   if neededLayer > 2 and neededLayer%3 ~= 2 then --If turtle was not on a proper mining layer
  466.     print("Last known pos was not in proper layer, restarting quarry")
  467.     sleep(4)
  468.     neededLayer = 2
  469.   end
  470.   xPos, zPos, yPos, facing, rowCheck, layersDone = 0,1,1, 0, true, math.ceil(neededLayer/3)
  471.   events = {{"goto",1,1,neededLayer, 0}}
  472. end
  473.  
  474. local blacklist = { "minecraft:air",  "minecraft:bedrock", "minecraft:cobblestone", "minecraft:dirt", "minecraft:ice", "minecraft:ladder", "minecraft:netherrack", "minecraft:sand", "minecraft:sandstone",
  475.   "minecraft:snow", "minecraft:snow_layer", "minecraft:stone", "minecraft:gravel", "minecraft:grass" }
  476. for a,b in pairs(blacklist) do
  477.   blacklist[b], blacklist[b] = true, nil --Switch
  478. end
  479. if fs.exists(oreQuarryBlacklistName) then --Loading user-defined blacklist
  480.   local file = fs.open(oreQuarryBlacklistName, "r")
  481.   blacklist = {}
  482.   for a in file:readAll():gmatch("[^,]+") do
  483.     blacklist[a:match("%S+:%S+")] = true --Grab only the actual characters, not whitespaces
  484.   end
  485.   file:close()
  486. end
  487.  
  488.  
  489. local function saveProgress(extras) --Session persistence
  490. exclusions = { modem = true, }
  491. if doBackup then
  492. local toWrite = ""
  493. for a,b in pairs(getfenv(1)) do
  494.   if not exclusions[a] then
  495.       --print(a ,"   ", b, "   ", type(b)) --Debug
  496.     if type(b) == "string" then b = "\""..b.."\"" end
  497.     if type(b) == "table" then b = textutils.serialize(b) end
  498.     if type(b) ~= "function" then
  499.       toWrite = toWrite..a.." = "..tostring(b).."\n"
  500.     end
  501.   end
  502. end
  503. toWrite = toWrite.."doCheckFuel = false\n" --It has already used fuel, so calculation unnecessary
  504. local file
  505. repeat
  506.   file = fs.open(saveFile,"w")
  507. until file
  508. file.write(toWrite)
  509. if type(extras) == "table" then
  510.   for a, b in pairs(extras) do
  511.     file.write(a.." = "..tostring(b).."\n")
  512.   end
  513. end
  514. if turtle.getFuelLevel() ~= math.huge then --Used for location comparing
  515.   file.write("fuelLevel = "..tostring(turtle.getFuelLevel()).."\n")
  516. end
  517. file.close()
  518. end
  519. end
  520.  
  521. local area = x*z
  522. local volume = x*y*z
  523. local lastHeight = y%3
  524. layers = math.ceil(y/3)
  525. local yMult = layers --This is basically a smart y/3 for movement
  526. local moveVolume = (area * yMult) --Kept for display percent
  527. --Calculating Needed Fuel--
  528. do --Because many local variables unneeded elsewhere
  529.   local changeYFuel = 2*(y + startDown)
  530.   local dropOffSupplies = 2*(x + z + y + startDown) --Assumes turtle as far away as possible, and coming back
  531.   local frequency = math.ceil(((moveVolume/(64*(15-uniqueExtras) + uniqueExtras)) ) ) --This is complicated: volume / inventory space of turtle, defined as 64*full stacks + 1 * unique stacks.
  532.                                                                                      --max of 15 full stacks because once one item is picked up, slot is "full". Ceil to count for initial back and forth
  533.   if enderChestEnabled then frequency = 0 end --Never goes back to start
  534.   neededFuel = moveVolume + changeYFuel + (frequency * dropOffSupplies) + ((x + z) * layers) --x + z *layers because turtle has to come back from far corner every layer
  535.   neededFuel = neededFuel + fuelTable[fuelSafety] --For safety
  536. end
  537.  
  538. if turtle.getFuelLimit and neededFuel+checkFuel() > turtle.getFuelLimit() then--Checks for if refueling goes over turtle fuel limit
  539.   if not doRefuel then
  540.     screen()
  541.     print("Turtle cannot hold enough fuel\n")
  542.     print("Options: \n1. Select a smaller size (press q) \n2. Enable Mid-Run Refueling (any other key)")
  543.     if ({os.pullEvent("char")})[2] == "q" then
  544.       screen(); print("Okay"); error("",0)
  545.     else
  546.       doRefuel = true
  547.     end
  548.   end
  549.   neededFuel = turtle.getFuelLimit()-checkFuel()-1
  550. end
  551.    
  552.    
  553. --Getting Fuel
  554. local hasRefueled --This is for oreQuarry prompting
  555. if doCheckFuel and checkFuel() < neededFuel then
  556.   hasRefueled = true
  557.   print("Not enough fuel")
  558.   print("Current: ",checkFuel()," Needed: ",neededFuel)
  559.   print("Starting SmartFuel...")
  560.   sleep(2) --So they can read everything.
  561.   term.clear()
  562.   local oneFuel, neededFuelItems
  563.   local currSlot = 0
  564.   local function output(text, x, y) --For displaying fuel
  565.     local currX, currY = term.getCursorPos()
  566.     term.setCursorPos(x,y)
  567.     term.clearLine()
  568.     term.write(text)
  569.     term.setCursorPos(currX,currY)
  570.     end
  571.   local function roundTo(num, target) --For stacks of fuel
  572.     if num >= target then return target elseif num < 0 then return 0 else return num end
  573.   end
  574.   local function updateScreen()
  575.     output("Welcome to SmartFuel! Now Refueling...", 1,1)
  576.     output("Currently taking fuel from slot "..currSlot,1,2)
  577.     output("Current single fuel: "..tostring(oneFuel or 0),1,3)
  578.     output("Current estimate of needed fuel: ",1,4)
  579.     output("Single Items: "..math.ceil(neededFuelItems or 0),4,5)
  580.     output("Stacks:       "..math.ceil((neededFuelItems or 0) / 64),4,6)
  581.     output("Needed Fuel: "..tostring(neededFuel),1,12)
  582.     output("Current Fuel: "..tostring(checkFuel()),1,13)
  583.   end
  584.   while checkFuel() <= neededFuel do
  585.     currSlot = currSlot + 1
  586.     select(currSlot)
  587.     if currSlot ~= 1 and not turtle.refuel(0) then --If its not the first slot, and not fuel, go back to start
  588.       currSlot = 1; select(currSlot)
  589.     end
  590.     updateScreen()
  591.     while turtle.getItemCount(currSlot) == 0 do
  592.       sleep(1.5)
  593.     end
  594.     repeat
  595.       local previous = checkFuel()
  596.       turtle.refuel(1)
  597.       oneFuel = checkFuel() - previous
  598.       updateScreen()
  599.     until (oneFuel or 0) > 0 --Not an if to prevent errors if fuel taken out prematurely.
  600.     neededFuelItems = (neededFuel - checkFuel()) / oneFuel
  601.     turtle.refuel(math.ceil(roundTo(neededFuelItems, 64))) --Change because can only think about 64 at once.
  602.     if turtle.getItemCount(roundTo(currSlot + 1, 16)) == 0 then --Resets if no more fuel
  603.       currSlot = 0
  604.     end
  605.     neededFuelItems = (neededFuel - checkFuel()) / oneFuel
  606.   end
  607. end
  608. --Ender Chest Obtaining
  609. function promptEnderChest()
  610.   while turtle.getItemCount(enderChestSlot) ~= 1 do
  611.     screen(1,1)
  612.     print("You have decided to use an Ender Chest!")
  613.     print("Please place one Ender Chest in slot ",enderChestSlot)
  614.     sleep(1)
  615.   end
  616.   print("Ender Chest in slot ",enderChestSlot, " checks out")
  617. end
  618. if enderChestEnabled then
  619.     if restoreFoundSwitch and turtle.getItemCount(enderChestSlot) == 0 then --If the turtle was stopped while dropping off items.
  620.       select(enderChestSlot)
  621.       turtle.dig()
  622.       select(1)
  623.     end
  624.   promptEnderChest()
  625.   allowedItems[enderChestSlot] = 64
  626.   sleep(2)
  627. end
  628. --Setting which slots are marked as compare slots
  629. if oldOreQuarry then
  630.   if not restoreFoundSwitch then --We don't want to reset compare blocks every restart
  631.     local counter = 0
  632.     for i=1, 16 do if turtle.getItemCount(i) > 0 and i ~= enderChestSlot then counter = counter+1 end end --If the slot has items, but isn't enderChest slot if it is enabled
  633.  
  634.     screen(1,1)
  635.     print("You have selected an Ore Quarry!")
  636.     if counter == 0 or hasRefueled then --If there are no compare slots, or the turtle has refueled, and probably has fuel in inventory
  637.       print("Please place your compare blocks in the first slots\n")
  638.      
  639.       print("Press Enter when done")
  640.       repeat until ({os.pullEvent("key")})[2] == 28 --Should wait for enter key to be pressed
  641.     else
  642.       print("Registering slots as compare slots")
  643.       sleep(1)
  644.     end
  645.     for i=1, 16 do
  646.       if turtle.getItemCount(i) > 0 then
  647.         if i ~= enderChestSlot then
  648.           table.insert(compareSlots, i) --Compare slots are ones compared to while mining. Conditions are because we Don't want to compare to enderChest
  649.           allowedItems[i] = 1 --Blacklist is for dropping off items. The number is maximum items allowed in slot when dropping off
  650.           dumpSlots[i] = true --We also want to ignore all excess of these items, like dirt
  651.         end
  652.       end
  653.     end
  654.     if extraDropItems then
  655.       screen(1,1)
  656.       print("Put in extra drop items now\n")
  657.       print("Press Enter when done")
  658.       repeat until ({os.pullEvent("key")})[2] == 28 --Should wait for enter key to be pressed
  659.       for i=1,16 do
  660.         if not dumpSlots[i] and turtle.getItemCount(i) > 0 then --I don't want to modify from above, so I check it hasn't been assigned.
  661.           dumpSlots[i] = true
  662.           allowedItems[i] = 1
  663.         end
  664.       end
  665.     end
  666.     --This is could go very wrong if this isn't here
  667.     if #compareSlots >= 16-keepOpen then screen(1,1); error("You have more quarry compare items than keep open slots, the turtle will continuously come back to start. Please fix.",0) end
  668.   end
  669.   local counter = 0
  670.   for a, b in pairs(compareSlots) do if  turtle.getItemCount(b) > 0 then counter = counter + 1 end end
  671.   if counter == 0 then
  672.     screen(1,1)
  673.     print("You have an ore quarry without any compare slots. Continue? y/n")
  674.     if ({os.pullEvent("char")})[2] ~= "y" then error("",0) end
  675.   end
  676. else
  677.   dumpCompareItems = false --If not an ore quarry, this should definitely be false
  678.   if enderChestSlot == 1 then
  679.     dumpSlots[2] = true
  680.   else
  681.     dumpSlots[1] = true
  682.   end
  683. end
  684.  
  685. --Initial Rednet Handshake
  686. if rednetEnabled then
  687.   screen(1,1)
  688.   print("Rednet is Enabled")
  689.   print("The Channel to open is "..channels.send)
  690.   if peripheral.find then
  691.     modem = peripheral.find("modem")
  692.   else
  693.     modem = peripheral.wrap("right")
  694.   end
  695.   modem.open(channels.receive)
  696.   local i = 0
  697.     repeat
  698.       local id = os.startTimer(3)
  699.       i=i+1
  700.       print("Sending Initial Message "..i)
  701.       modem.transmit(channels.send, channels.receive, channels.message)
  702.       local message
  703.       repeat
  704.         local event, idCheck, channel,_,locMessage, distance = os.pullEvent()
  705.         message = locMessage
  706.       until (event == "timer" and idCheck == id) or (event == "modem_message" and channel == channels.receive and message == channels.confirm)
  707.     until message == channels.confirm
  708.   connected = true
  709.   print("Connection Confirmed!")
  710.   sleep(1.5)
  711. end
  712. function biometrics(isAtBedrock)
  713.   if not rednetEnabled then return end --This function won't work if rednet not enabled :P
  714.   local toSend = { label = os.getComputerLabel() or "No Label", id = os.getComputerID(),
  715.     percent = percent, relxPos = relxPos, zPos = zPos, xPos = xPos, yPos = yPos,
  716.     layersDone = layersDone, x = x, z = z, layers = layers,
  717.     openSlots = getNumOpenSlots(), mined = mined, moved = moved,
  718.     chestFull = chestFull, isAtChest = (xPos == 0 and yPos == 1 and zPos == 1),
  719.     isGoingToNextLayer = (gotoDest == "layerStart"), foundBedrock = foundBedrock,
  720.     fuel = turtle.getFuelLevel(), volume = volume,
  721.     }
  722.   modem.transmit(channels.send, channels.receive, textutils.serialize(toSend))
  723.   id = os.startTimer(0.1)
  724.   local event, message
  725.   repeat
  726.     local locEvent, idCheck, confirm, _, locMessage, distance = os.pullEvent()
  727.     event, message = locEvent, locMessage or ""
  728.   until (event == "timer" and idCheck == id) or (event == "modem_message" and confirm == channels.receive)
  729.   if event == "modem_message" then connected = true else connected = false end
  730.   message = message:lower()
  731.   if message == "stop" then error("Rednet said to stop...",0) end
  732.   if message == "return" then
  733.     endingProcedure()
  734.     error('Rednet said go back to start...',0)
  735.   end
  736.   if message == "drop" then
  737.     dropOff()
  738.   end
  739.   if message == "pause" then
  740.     print("\nTurtle is paused. Send 'resume' or press any character to resume")
  741.     repeat
  742.       local event, idCheck, confirm, _, message, distance = os.pullEvent()
  743.     until (event == "modem_message" and confirm == channels.receive and message == "resume") or (event == "char")
  744.   end
  745.  
  746. end
  747. --Showing changes to settings
  748. screen(1,1)
  749. print("Your selected settings:")
  750. if #changedT == 0 then
  751. print("Completely Default")
  752. else
  753. for i=1, #changedT do
  754. print(changedT[i][1],": ",changedT[i][2]) --Name and Value
  755. end
  756. end
  757. print("\nStarting in 3"); sleep(1); print("2"); sleep(1); print("1"); sleep(1.5) --Dramatic pause at end
  758.  
  759.  
  760.  
  761. ----------------------------------------------------------------
  762. --Define ALL THE FUNCTIONS
  763. --Event System Functions
  764. function eventAddAt(pos, ...)
  765.   return table.insert(events,pos, {...}) or true
  766. end
  767. function eventAdd(...) --Just a wrapper
  768.   return eventAddAt(1, ...)
  769. end
  770. function eventGet(pos)
  771.   return events[tonumber(pos) or #events]
  772. end
  773. function eventPop(pos)
  774.   return table.remove(events,tonumber(pos) or #events) or false --This will return value popped, tonumber returns nil if fail, so default to end
  775. end
  776. function eventRun(value, ...)
  777.   local argsList = {...}
  778.   if type(value) == "string" then
  779.     if value:sub(-1) ~= ")" then --So supports both "up()" and "up"
  780.       value = value .. "("
  781.       for a, b in pairs(argsList) do --Appending arguments
  782.         local toAppend
  783.         if type(b) == "table" then toAppend = textutils.serialize(b)
  784.         elseif type(b) == "string" then toAppend = "\""..tostring(b).."\"" --They weren't getting strings around them
  785.         else toAppend = tostring(b) end
  786.         value = value .. (toAppend or "true") .. ", "
  787.       end
  788.       if value:sub(-1) ~= "(" then --If no args, do not want to cut off
  789.         value = value:sub(1,-3)..""
  790.       end
  791.       value = value .. ")"
  792.     end
  793.     --print(value) --Debug
  794.     local func = loadstring(value)
  795.     setfenv(func, getfenv(1))
  796.     return func()
  797.   end
  798. end
  799. function eventClear(pos)
  800.   if pos then events[pos] = nil else events = {} end
  801. end  
  802. function runAllEvents()
  803.   while #events > 0 do
  804.     local toRun = eventGet()
  805.     --print(toRun[1]) --Debug
  806.     eventRun(unpack(toRun))
  807.     eventPop()
  808.   end
  809. end
  810.  
  811. --Display Related Functions
  812. function display() --This is just the last screen that displays at the end
  813.   screen(1,1)
  814.   print("Total Blocks Mined: "..mined)
  815.   print("Current Fuel Level: "..turtle.getFuelLevel())
  816.   print("Cobble: "..totals.cobble)
  817.   print("Usable Fuel: "..totals.fuel)
  818.   print("Other: "..totals.other)
  819.   if rednetEnabled then
  820.     print("")
  821.     print("Sent Stop Message")
  822.     local finalTable = {mined = mined, cobble = totals.cobble, fuelblocks = totals.fuel,
  823.         other = totals.other, fuel = checkFuel() }
  824.     modem.transmit(channels.send,channels.receive,"stop")
  825.     sleep(0.5)
  826.     modem.transmit(channels.send,channels.receive,textutils.serialize(finalTable))
  827.     modem.close(channels.receive)
  828.   end
  829.   if doBackup then fs.delete(saveFile) end
  830. end
  831. function updateDisplay() --Runs in Mine(), display information to the screen in a certain place
  832. screen(1,1)
  833. print("Blocks Mined")
  834. print(mined)
  835. print("Percent Complete")
  836. print(percent.."%")
  837. print("Fuel")
  838. print(checkFuel())
  839.   -- screen(1,1)
  840.   -- print("Xpos: ")
  841.   -- print(xPos)
  842.   -- print("RelXPos: ")
  843.   -- print(relxPos)
  844.   -- print("Z Pos: ")
  845.   -- print(zPos)
  846.   -- print("Y pos: ")
  847.   -- print(yPos)
  848. if rednetEnabled then
  849. screenLine(1,7)
  850. print("Connected: "..tostring(connected))
  851. end
  852. end
  853. --Utility functions
  854. function logMiningRun(textExtension, extras) --Logging mining runs
  855.   if not logging then return end
  856.   local number, name = 0
  857.   if not fs.isDir(logFolder) then
  858.     fs.delete(logFolder)
  859.     fs.makeDir(logFolder)
  860.   end
  861.   repeat
  862.     number = number + 1 --Number will be at least 2
  863.     name = logFolder.."/Quarry_Log_"..tostring(number)..(textExtension or "")
  864.   until not fs.exists(name)
  865.   local handle = fs.open(name,"w")
  866.   local function write(...)
  867.     for a, b in ipairs({...}) do
  868.       handle.write(tostring(b))
  869.     end
  870.     handle.write("\n")
  871.   end
  872.   local function boolToText(bool) if bool then return "Yes" else return "No" end end
  873.   write("Welcome to the Quarry Logs!")
  874.   write("Entry Number: ",number)
  875.   write("Quarry Version: ",VERSION)
  876.   write("Dimensions (X Z Y): ",x," ",z," ", y)
  877.   write("Blocks Mined: ", mined)
  878.   write("  Cobble: ", totals.cobble)
  879.   write("  Usable Fuel: ", totals.fuel)
  880.   write("  Other: ",totals.other)
  881.   write("Total Fuel Used: ",  (originalFuel or (neededFuel + checkFuel()))- checkFuel()) --Protect against errors with some precision
  882.   write("Expected Fuel Use: ", neededFuel)
  883.   write("Days to complete mining run: ",os.day()-originalDay)
  884.   write("Day Started: ", originalDay)
  885.   write("Number of times resumed: ", numResumed)
  886.   write("Was an ore quarry? ",boolToText(oreQuarry))
  887.   write("Was inverted? ",boolToText(invert))
  888.   write("Was using rednet? ",boolToText(rednetEnabled))
  889.   write("Chest was on the ",dropSide," side")
  890.   if startDown > 0 then write("Started ",startDown," blocks down") end
  891.   handle.close()
  892. end
  893. --Inventory related functions
  894. function isFull(slots) --Checks if there are more than "slots" used inventory slots.
  895.   slots = slots or 16
  896.   local numUsed = 0
  897.   sleep(0)
  898.   for i=1, 16 do
  899.     if turtle.getItemCount(i) > 0 then numUsed = numUsed + 1 end
  900.   end
  901.   if numUsed > slots then
  902.     return true
  903.   end
  904.   return false
  905. end
  906. function countUsedSlots() --Returns number of slots with items in them, as well as a table of item counts
  907.   local toRet, toRetTab = 0, {}
  908.   for i=1, 16 do
  909.     local a = turtle.getItemCount(i)
  910.     if a > 0 then toRet = toRet + 1 end
  911.     table.insert(toRetTab, a)
  912.   end
  913.   return toRet, toRetTab
  914. end
  915. function getSlotsTable() --Just get the table from above
  916.   local _, toRet = countUsedSlots()
  917.   return toRet
  918. end
  919. function getChangedSlots(tab1, tab2) --Returns a table of changed slots. Format is {slotNumber, numberChanged}
  920.   local toRet = {}
  921.   for i=1, min(#tab1, #tab2) do
  922.     diff = math.abs(tab2[i]-tab1[i])
  923.     if diff > 0 then
  924.       table.insert(toRet, {i, diff})
  925.     end
  926.   end
  927.   return toRet
  928. end
  929. function getFirstChanged(tab1, tab2) --Just a wrapper. Probably not needed
  930.   local a = getChangedSlots(tab1,tab2)
  931.   return a[1][1]
  932. end
  933.  
  934. function getRep(which, list) --Gets a representative slot of a type. Expectation is a sequential table of types
  935.   for a,b in pairs(list) do
  936.     if b == which then return a end
  937.   end
  938.   return false
  939. end
  940. function assignTypes(types, count) --The parameters allow a preexisting table to be used, like a table from the original compareSlots...
  941.   types, count = types or {1}, count or 1 --Table of types and current highest type
  942.   for i=1, 16 do
  943.     if turtle.getItemCount(i) > 0 then
  944.       select(i)
  945.       for k=1, count do
  946.         if turtle.compareTo(getRep(k, types)) then types[i] = k end
  947.       end
  948.       if not types[i] then
  949.         count = count + 1
  950.         types[i] = count
  951.       end
  952.      
  953.     end
  954.   end
  955.   select(1)
  956.   return types, count
  957. end
  958. function getTableOfType(which, list) --Returns a table of all the slots of which type
  959.   local toRet = {}
  960.   for a, b in pairs(list) do
  961.     if b == which then
  962.       table.insert(toRet, a)
  963.     end
  964.   end
  965.   return toRet
  966. end
  967.  
  968. --This is so the turtle will properly get types, otherwise getRep of a type might not be a dumpSlot, even though it should be.
  969. if not restoreFoundSwitch then --We only want this to happen once
  970.   if oldOreQuarry then --If its not ore quarry, this screws up type assigning
  971.     initialTypes, initialCount = assignTypes()
  972.   else
  973.     initialTypes, initialCount = {1}, 1
  974.   end
  975. end
  976.  
  977. function count(add) --Done any time inventory dropped and at end, true=add, false=nothing, nil=subtract
  978.   local mod = -1
  979.   if add then mod = 1 end
  980.   if add == false then mod = 0 end
  981.   slot = {}        --1: Filler 2: Fuel 3:Other --[1] is type, [2] is number
  982.   for i=1, 16 do  
  983.     slot[i] = {}
  984.     slot[i][2] = turtle.getItemCount(i)
  985.   end
  986.  
  987.   local function iterate(toSet , rawTypes, set)
  988.     for _, a in pairs(getTableOfType(toSet, rawTypes)) do --Get all slots matching type
  989.       slot[a][1] = set --Set official type to "set"
  990.     end
  991.   end
  992.  
  993.   --This assigns "dumb" types to all slots based on comparing, then based on knowledge of dump type slots, changes all slots matching a dump type to one. Otherwise, if the slot contains fuel, it is 2, else 3
  994.   local rawTypes, numTypes = assignTypes(copyTable(initialTypes), initialCount) --This gets increasingly numbered types, copyTable because assignTypes will modify it
  995.  
  996.   for i=1, numTypes do
  997.     if (select(getRep(i, rawTypes)) or true) and turtle.refuel(0) then --Selects the rep slot, checks if it is fuel
  998.       iterate(i, rawTypes, 2) --This type is fuel
  999.     elseif dumpSlots[getRep(i,initialTypes)] then --If the rep of this slot is a dump item. This is initial types so that the rep is in dump slots
  1000.       iterate(i, rawTypes, 1) --This type is cobble/filler
  1001.     else
  1002.       iterate(i, rawTypes, 3) --This type is other
  1003.     end
  1004.   end
  1005.    
  1006.     for i=1,16 do
  1007.       if i == enderChestSlot then --Do nothing!
  1008.       elseif slot[i][1] == 1 then totals.cobble = totals.cobble + (slot[i][2] * mod)
  1009.       elseif slot[i][1] == 2 then totals.fuel = totals.fuel + (slot[i][2] * mod)
  1010.       elseif slot[i][1] == 3 then totals.other = totals.other + (slot[i][2] * mod) end
  1011.     end
  1012.  
  1013.   select(1)
  1014. end
  1015.  
  1016. --Mining functions
  1017. function dig(doAdd, func, inspectFunc)
  1018.   if doAdd == nil then doAdd = true end
  1019.   func = func or turtle.dig
  1020.   local function retTab(tab) if type(tab) == "table" then return tab end end --Please ignore the stupid one-line trickery. I felt special writing that. (Unless it breaks, then its cool)
  1021.   if not oreQuarry or not inspectFunc or not blacklist[(retTab(({inspectFunc()})[2]) or {name = "none"}).name] then --Will stop at first false, last part won't run if one of first are false
  1022.    if func() then
  1023.      if doAdd then
  1024.        mined = mined + 1
  1025.      end
  1026.      return true
  1027.    else
  1028.      return false
  1029.    end
  1030.   end
  1031.   return true --This only runs if oreQuarry but item not in blacklist
  1032. end
  1033.  
  1034.  
  1035.  
  1036. function digUp(doAdd)--Regular functions :) I switch definitions for optimization (I think)
  1037.   return dig(doAdd, turtle.digUp, turtle.inspectUp)
  1038. end
  1039. function digDown(doAdd)
  1040.   return dig(doAdd, turtle.digDown, turtle.inspectDown)
  1041. end
  1042. if inverted then --If inverted, switch the options
  1043.   digUp, digDown = digDown, digUp
  1044. end
  1045.  
  1046. function smartDig(digUp, digDown) --This function is used only in mine when oreQuarry
  1047.   local blockAbove, blockBelow = digUp and turtle.detectUp(), digDown and turtle.detectDown() --These control whether or not the turtle digs
  1048.   local index = 1
  1049.   for i=1, #compareSlots do
  1050.     if not (blockAbove or blockBelow) then break end --We don't want to go selecting if there is nothing to dig
  1051.     index = i --To access out of scope
  1052.     select(compareSlots[i])
  1053.     if blockAbove and turtle.compareUp() then blockAbove = false end
  1054.     if blockBelow and turtle.compareDown() then blockBelow = false end
  1055.   end
  1056.   table.insert(compareSlots, 1, table.remove(compareSlots, index)) --This is so the last selected slot is the first slot checked, saving a turtle.select call
  1057.   if blockAbove then dig(true, turtle.digUp) end
  1058.   if blockBelow then dig(true, turtle.digDown) end
  1059. end
  1060.  
  1061. function setRowCheckFromPos()
  1062.   rowCheck = (zPos % 2 == 1) --It will turn right at odd rows
  1063. end
  1064. function relxCalc()
  1065.   if rowCheck then relxPos = xPos else relxPos = (x-xPos)+1 end
  1066. end
  1067. function forward(doAdd)
  1068.   if doAdd == nil then doAdd = true end
  1069.   if turtle.forward() then
  1070.     if doAdd then
  1071.       moved = moved + 1
  1072.     end
  1073.     if facing == 0 then
  1074.       xPos = xPos + 1
  1075.     elseif facing == 1 then
  1076.       zPos = zPos + 1
  1077.     elseif facing == 2 then
  1078.       xPos = xPos - 1
  1079.     elseif facing == 3 then
  1080.       zPos = zPos - 1
  1081.     else
  1082.       error("Function forward, facing should be 0 - 3, got "..tostring(facing),2)
  1083.     end
  1084.     relxCalc()
  1085.     return true
  1086.   end
  1087.   return false
  1088. end
  1089. function up(sneak)
  1090.   sneak = sneak or 1
  1091.   if inverted and sneak == 1 then
  1092.     down(-1)
  1093.   else
  1094.     while not turtle.up() do --Absolute dig, not relative
  1095.       if not dig(true, turtle.digUp) then
  1096.         attackUp()
  1097.         sleep(0.5)
  1098.       end
  1099.     end
  1100.     yPos = yPos - sneak --Oh! I feel so clever
  1101.   end                   --This works because inverted :)
  1102.   saveProgress()
  1103.   biometrics()
  1104. end
  1105. function down(sneak)
  1106.   sneak = sneak or 1
  1107.   local count = 0
  1108.   if inverted and sneak == 1 then
  1109.     up(-1)
  1110.   else
  1111.     while not turtle.down() do
  1112.       count = count + 1
  1113.       if not dig(true, turtle.digDown) then --This is absolute dig down, not relative
  1114.         attackDown()
  1115.         sleep(0.2)
  1116.       end
  1117.       if count > 20 then bedrock() end
  1118.     end
  1119.     yPos = yPos + sneak
  1120.   end
  1121.   saveProgress()
  1122.   biometrics()
  1123. end
  1124. function right(num)
  1125.   num = num or 1
  1126.   for i=1, num do facing = coterminal(facing+1); saveProgress(); turtle.turnRight() end
  1127. end
  1128. function left(num)
  1129.   num = num or 1
  1130.   for i=1, num do facing = coterminal(facing-1); saveProgress(); turtle.turnLeft() end
  1131. end
  1132. function attack(doAdd, func)
  1133.   doAdd = doAdd or true
  1134.   func = func or turtle.attack
  1135.   if func() then
  1136.     if doAdd then
  1137.       attacked = attacked + 1
  1138.     end
  1139.     return true
  1140.   end
  1141.   return false
  1142. end
  1143. function attackUp(doAdd)
  1144.   if inverted then
  1145.     return attack(doAdd, turtle.attackDown)
  1146.   else
  1147.     return attack(doAdd, turtle.attackUp)
  1148.   end
  1149. end
  1150. function attackDown(doAdd)
  1151.   if inverted then
  1152.     return attack(doAdd, turtle.attackUp)
  1153.   else
  1154.     return attack(doAdd, turtle.attackDown)
  1155.   end
  1156. end
  1157.  
  1158. function detect(func)
  1159.   func = func or turtle.detect
  1160.   return func()
  1161. end
  1162. function detectUp()
  1163.   if inverted then return detect(turtle.detectDown)
  1164.   else return detect(turtle.detectUp) end
  1165. end
  1166. function detectDown()
  1167.   if inverted then return detect(turtle.detectUp)
  1168.   else return detect(turtle.detectDown) end
  1169. end
  1170.  
  1171.  
  1172.  
  1173. function mine(doDigDown, doDigUp, outOfPath,doCheckInv) -- Basic Move Forward
  1174.   if doCheckInv == nil then doCheckInv = true end
  1175.   if doDigDown == nil then doDigDown = true end
  1176.   if doDigUp == nil then doDigUp = true end
  1177.   if outOfPath == nil then outOfPath = false end
  1178.   isInPath = (not outOfPath) --For rednet
  1179.   if not outOfPath and (checkFuel() <= xPos + zPos + yPos + 5) then --If the turtle can just barely get back to the start, we need to get it there. We don't want this to activate coming back though...
  1180.     local continueEvac = true --This turns false if more fuel is acquired
  1181.     if doRefuel then --Attempt an emergency refueling
  1182.       screen()
  1183.       print("Attempting an emergency refuel")
  1184.       print("Fuel Level:    ",checkFuel())
  1185.       print("Distance Back: ",(xPos+zPos+yPos+1))
  1186.       print("Categorizing Items")
  1187.       count(false) --Do not add count, but categorize
  1188.       local fuelSwitch, initialFuel = false, checkFuel() --Fuel switch so we don't go over limit (in emergency...)
  1189.       print("Going through available fuel slots")
  1190.       for i=1, 16 do
  1191.         if fuelSwitch then break end
  1192.         if turtle.getItemCount(i) > 0 and slot[i][1] == 2 then --If there are items and type 2 (fuel)
  1193.           turtle.select(i)
  1194.           fuelSwitch = midRunRefuel(i) --See above "function drop" for usage
  1195.         end
  1196.       end
  1197.       turtle.select(1) --Cleanup
  1198.       print("Done fueling")
  1199.       if checkFuel() > initialFuel then
  1200.         continueEvac = false
  1201.         print("Evac Aborted")
  1202.       else
  1203.         print("Evac is a go, returning to base")
  1204.         sleep(1.5) --Pause for reading
  1205.       end
  1206.     end
  1207.     if continueEvac then
  1208.       eventClear() --Clear any annoying events for evac
  1209.       endingProcedure("Turtle ran low on fuel so was brought back to start for you :)\n\nTo resume where you left off, use '-startDown "..tostring(y-2).."' when you start") --Finish the program
  1210.     end
  1211.   end
  1212.   local count = 0
  1213.   while not forward(not outOfPath) do
  1214.     sleep(0) --Calls coroutine.yield to prevent errors
  1215.     count = count + 1
  1216.     if not dig() then
  1217.       attack()
  1218.     end
  1219.     if count > 10 then
  1220.       attack()
  1221.       sleep(0.2)
  1222.     end
  1223.     if count > maxTries then
  1224.       if turtle.getFuelLevel() == 0 then --Don't worry about inf fuel because I modified this function
  1225.         saveProgress({doCheckFuel = true})
  1226.         error("No more fuel",0)
  1227.       elseif yPos > (startY-7) and turtle.detect() then --If it is near bedrock
  1228.         bedrock()
  1229.       else --Otherwise just sleep for a bit to avoid sheeps
  1230.         sleep(1)
  1231.       end
  1232.     end
  1233.   end
  1234.   checkSanity() --Not kidding... This is necessary
  1235.   saveProgress(tab)
  1236.  
  1237.   if doDigUp then--The digging up and down part
  1238.     sleep(0) --Calls coroutine.yield
  1239.     if not digUp(true) and detectUp() then --This is relative: will dig down first on invert
  1240.       if not attackUp() then
  1241.         if yPos > (startY-7) then bedrock() end --Checking for bedrock, but respecting user wishes
  1242.       end
  1243.     end
  1244.   end
  1245.   if doDigDown then
  1246.    digDown(true) --This needs to be absolute as well
  1247.   end
  1248.   percent = math.ceil(moved/moveVolume*100)
  1249.   updateDisplay()
  1250.   if doCheckInv and careAboutResources then
  1251.     if isFull(16-keepOpen) then dropOff() end
  1252.   end
  1253.   biometrics()
  1254. end
  1255. --Insanity Checking
  1256. function checkSanity()
  1257.   if not isInPath then --I don't really care if its not in the path.
  1258.     return true
  1259.   end
  1260.   if not (facing == 0 or facing == 2) and #events == 0 then --If mining and not facing proper direction and not in a turn
  1261.     turnTo(0)
  1262.     rowCheck = true
  1263.   end
  1264.   if xPos < 0 or xPos > x or zPos < 0 or zPos > z or yPos < 0 then
  1265.     saveProgress()
  1266.     print("I have gone outside boundaries, attempting to fix (maybe)")
  1267.     if xPos > x then goto(x, zPos, yPos, 2) end --I could do this with some fancy math, but this is much easier
  1268.     if xPos < 0 then goto(1, zPos, yPos, 0) end
  1269.     if zPos > z then goto(xPos, z, yPos, 3) end
  1270.     if zPos < 0 then goto(xPos, 1, yPos, 1) end
  1271.     setRowCheckFromPos() --Row check right (maybe left later)
  1272.     relxCalc() --Get relxPos properly
  1273.     eventClear()
  1274.    
  1275.     --[[
  1276.     print("Oops. Detected that quarry was outside of predefined boundaries.")
  1277.     print("Please go to my forum thread and report this with a short description of what happened")
  1278.     print("If you could also run \"pastebin put Civil_Quarry_Restore\" and give me that code it would be great")
  1279.     error("",0)]]
  1280.   end
  1281. end
  1282.  
  1283. local function fromBoolean(input) --Like a calculator
  1284. if input then return 1 end
  1285. return 0
  1286. end
  1287. local function multBoolean(first,second) --Boolean multiplication
  1288. return (fromBoolean(first) * fromBoolean(second)) == 1
  1289. end
  1290. function coterminal(num, limit) --I knew this would come in handy :D
  1291. limit = limit or 4 --This is for facing
  1292. return math.abs((limit*fromBoolean(num < 0))-(math.abs(num)%limit))
  1293. end
  1294. if tArgs["-manualpos"] then
  1295.   facing = coterminal(facing) --Done to improve support for "-manualPos"
  1296.   if facing == 0 then rowCheck = true elseif facing == 2 then rowCheck = false end --Ditto
  1297.   relxCalc() --Ditto
  1298. end
  1299.  
  1300. --Direction: Front = 0, Right = 1, Back = 2, Left = 3
  1301. function turnTo(num)
  1302.   num = num or facing
  1303.   num = coterminal(num) --Prevent errors
  1304.   local turnRight = true
  1305.   if facing-num == 1 or facing-num == -3 then turnRight = false end --0 - 1 = -3, 1 - 0 = 1, 2 - 1 = 1
  1306.   while facing ~= num do          --The above is used to smartly turn
  1307.     if turnRight then
  1308.       right()
  1309.     else
  1310.       left()
  1311.     end
  1312.   end
  1313. end
  1314. function goto(x,z,y, toFace, destination)
  1315.   --Will first go to desired z pos, then x pos, y pos varies
  1316.   x = x or 1; y = y or 1; z = z or 1; toFace = toFace or facing
  1317.   gotoDest = destination or "" --This is used by biometrics
  1318.   --Possible destinations: layerStart, quarryStart
  1319.   if yPos > y then --Will go up first if below position
  1320.     while yPos~=y do up() end
  1321.   end
  1322.   if zPos > z then
  1323.     turnTo(3)
  1324.   elseif zPos < z then
  1325.     turnTo(1)
  1326.   end
  1327.   while zPos ~= z do mine(false,false,true,false) end
  1328.   if xPos > x then
  1329.     turnTo(2)
  1330.   elseif xPos < x then
  1331.     turnTo(0)
  1332.   end
  1333.   while xPos ~= x do mine(false,false,true,false) end
  1334.   if yPos < y then --Will go down after if above position
  1335.     while yPos~=y do down() end
  1336.   end
  1337.   turnTo(toFace)
  1338.   saveProgress()
  1339.   gotoDest = ""
  1340. end
  1341. function getNumOpenSlots()
  1342.   local toRet = 0
  1343.   for i=1, 16 do
  1344.     if turtle.getItemCount(i) == 0 then
  1345.       toRet = toRet + 1
  1346.     end
  1347.   end
  1348.   return toRet
  1349. end
  1350.  
  1351. --Ideas: Bring in inventory change-checking functions, count blocks that have been put in, so it will wait until all blocks have been put in.
  1352. local function waitDrop(slot, allowed, whereDrop) --This will just drop, but wait if it can't
  1353.   allowed = allowed or 0
  1354.   while turtle.getItemCount(slot) > allowed do --No more half items stuck in slot!
  1355.     local tries = 1
  1356.     while not whereDrop(turtle.getItemCount(slot)-allowed) do --Drop off only the amount needed
  1357.       screen(1,1)
  1358.       print("Chest Full, Try "..tries)
  1359.       chestFull = true
  1360.       biometrics()--To send that the chest is full
  1361.       tries = tries + 1
  1362.       sleep(2)
  1363.     end
  1364.     chestFull = false
  1365.   end
  1366. end
  1367.  
  1368. function midRunRefuel(i)
  1369.   local numToRefuel = turtle.getItemCount(i)-allowedItems[i]
  1370.   if checkFuel() >= turtle.getFuelLimit() then return true end --If it doesn't need fuel, then signal to not take more
  1371.   local firstCheck = checkFuel()
  1372.   if numToRefuel > 0 then turtle.refuel(1) end --This is so we can see how many fuel we need.
  1373.   local singleFuel
  1374.   if checkFuel() - firstCheck > 0 then singleFuel = checkFuel() - firstCheck else singleFuel = math.huge end --If fuel is 0, we want it to be huge so the below will result in 0 being taken
  1375.   --Refuel      The lesser of   max allowable or         remaining fuel space         /    either inf or a single fuel (which can be 0)
  1376.   turtle.refuel(math.min(numToRefuel-1, math.ceil((turtle.getFuelLimit()-checkFuel()) / singleFuel))) --The refueling part of the the doRefuel option
  1377.   return false --Turtle can still be fueled
  1378. end
  1379.  
  1380. function drop(side, final)
  1381.   side = sides[side] or "front"
  1382.   local dropFunc, detectFunc, dropFacing = turtle.drop, turtle.detect, facing+2
  1383.   if side == "top" then dropFunc, detectFunc = turtle.dropUp, turtle.detectUp end
  1384.   if side == "bottom" then dropFunc, detectFunc = turtle.dropDown, turtle.detectDown end
  1385.   if side == "right" then turnTo(1); dropFacing = 0 end
  1386.   if side == "left" then turnTo(3); dropFacing = 0 end
  1387.   local properFacing = facing --Capture the proper direction to be facing
  1388.  
  1389.   count(true) --Count number of items before drop. True means add. This is before chest detect, because could be final
  1390.  
  1391.   while not detectFunc() do
  1392.     if final then return end --If final, we don't need a chest to be placed, but there can be
  1393.     chestFull = true
  1394.     biometrics() --Let the user know there is a problem with chest
  1395.     screen(1,1) --Clear screen
  1396.     print("Waiting for chest placement on ",side," side (when facing quarry)")
  1397.     sleep(2)
  1398.   end
  1399.   chestFull = false
  1400.  
  1401.   local fuelSwitch = false --If doRefuel, this can switch so it won't overfuel
  1402.   for i=1,16 do
  1403.     --if final then allowedItems[i] = 0 end --0 items allowed in all slots if final ----It is already set to 1, so just remove comment if want change
  1404.     if turtle.getItemCount(i) > 0 then --Saves time, stops bugs
  1405.       if slot[i][1] == 1 and dumpCompareItems then turnTo(dropFacing) --Turn around to drop junk, not store it. dumpComapareItems is global config
  1406.       else turnTo(properFacing) --Turn back to proper position... or do nothing if already there
  1407.       end
  1408.       select(i)
  1409.       if doRefuel and slot[i][1] == 2 then --Intelligently refuels to fuel limit
  1410.         if not fuelSwitch then --Not in the conditional because we don't want to waitDrop excess fuel. Not a break so we can drop junk
  1411.           fuelSwitch = midRunRefuel(i)
  1412.         end
  1413.       else
  1414.         waitDrop(i, allowedItems[i], dropFunc)
  1415.       end
  1416.     end
  1417.   end
  1418.  
  1419.   if oldOreQuarry then count(nil) end--Subtract the items still there if oreQuarry
  1420.   resetDumpSlots() --So that slots gone aren't counted as dump slots next
  1421.  
  1422.   select(1) --For fanciness sake
  1423.  
  1424. end
  1425.  
  1426. function dropOff() --Not local because called in mine()
  1427.   local currX,currZ,currY,currFacing = xPos, zPos, yPos, facing
  1428.   if careAboutResources then
  1429.     if not enderChestEnabled then --Regularly
  1430.       eventAdd("goto", 1,1,currY,2) --Need this step for "-startDown"
  1431.       eventAdd("goto(0,1,1,2)")
  1432.       eventAdd("drop", dropSide,false)
  1433.       eventAdd("turnTo(0)")
  1434.       eventAdd("mine",false,false,true,false)
  1435.       eventAdd("goto(1,1,1, 0)")
  1436.       eventAdd("goto", 1, 1, currY, 0)
  1437.       eventAdd("goto", currX,currZ,currY,currFacing)
  1438.     else --If using an enderChest
  1439.       if turtle.getItemCount(enderChestSlot) ~= 1 then eventAdd("promptEnderChest()") end
  1440.       eventAdd("turnTo",currFacing-2)
  1441.       eventAdd("dig",false)
  1442.       eventAdd("select",enderChestSlot)
  1443.       eventAdd("turtle.place")
  1444.       eventAdd("drop","front",false)
  1445.       eventAdd("turnTo",currFacing-2)
  1446.       eventAdd("select", enderChestSlot)
  1447.       eventAdd("dig",false)
  1448.       eventAdd("turnTo",currFacing)
  1449.       eventAdd("select(1)")
  1450.     end
  1451.     runAllEvents()
  1452.     numDropOffs = numDropOffs + 1 --Analytics tracking
  1453.   end
  1454.   return true
  1455. end
  1456. function endingProcedure(endingMessage) --Used both at the end and in "biometrics"
  1457.   eventAdd("goto",1,1,yPos,2,"quarryStart") --Allows for startDown variable
  1458.   eventAdd("goto",0,1,1,2, "quarryStart") --Go back to base
  1459.   runAllEvents()
  1460.   --Output to a chest or sit there
  1461.   if enderChestEnabled then
  1462.     if dropSide == "right" then eventAdd("turnTo(1)") end --Turn to proper drop side
  1463.     if dropSide == "left" then eventAdd("turnTo(3)") end
  1464.     eventAdd("dig(false)") --This gets rid of a block in front of the turtle.
  1465.     eventAdd("select",enderChestSlot)
  1466.     eventAdd("turtle.place")
  1467.     eventAdd("select(1)")
  1468.   end
  1469.   eventAdd("drop",dropSide, true)
  1470.   eventAdd("turnTo(0)")
  1471.  
  1472.   --Display was moved above to be used in bedrock function
  1473.   eventAdd("display")
  1474.   --Log current mining run
  1475.   eventAdd("logMiningRun",logExtension)
  1476.   eventAdd("error",endingMessage or "",0)
  1477.   toQuit = true --I'll use this flag to clean up (legacy)
  1478.   runAllEvents()
  1479.   --Cleanup
  1480.   turtle.getFuelLevel = getFuel
  1481. end
  1482. function bedrock()
  1483.   foundBedrock = true --Let everyone know
  1484.   if rednetEnabled then biometrics() end
  1485.   if checkFuel() == 0 then error("No Fuel",0) end
  1486.   local origin = {x = xPos, y = yPos, z = zPos}
  1487.   print("Bedrock Detected")
  1488.   if turtle.detectUp() then
  1489.     print("Block Above")
  1490.     local var
  1491.     if facing == 0 then var = 2 elseif facing == 2 then var = 0 else error("Was facing left or right on bedrock") end
  1492.     goto(xPos,zPos,yPos,var)
  1493.     for i=1, relxPos do mine(false, false); end
  1494.   end
  1495.   eventClear() --Get rid of any excess events that may be run. Don't want that.
  1496.   endingProcedure()
  1497.   print("\nFound bedrock at these coordinates: ")
  1498.   print(origin.x," Was position in row\n",origin.z," Was row in layer\n",origin.y," Blocks down from start")
  1499.   error("",0)
  1500. end
  1501.  
  1502. function endOfRowTurn(startZ, wasFacing, mineFunctionTable)
  1503. local halfFacing = 1
  1504. local toFace = coterminal(wasFacing + 2) --Opposite side
  1505. if zPos == startZ then
  1506.   if facing ~= halfFacing then turnTo(halfFacing) end
  1507.   mine(unpack(mineFunctionTable or {}))
  1508. end
  1509. if facing ~= toFace then
  1510.   turnTo(toFace)
  1511. end
  1512. end
  1513.  
  1514.  
  1515. -------------------------------------------------------------------------------------
  1516. --Pre-Mining Stuff dealing with session persistence
  1517. runAllEvents()
  1518. if toQuit then error("",0) end --This means that it was stopped coming for its last drop
  1519.  
  1520. local doDigDown, doDigUp = (lastHeight ~= 1), (lastHeight == 0) --Used in lastHeight
  1521. if not restoreFoundSwitch then --Regularly
  1522.   --Check if it is a mining turtle
  1523.   if not isMiningTurtle then
  1524.     local a, b = turtle.dig()
  1525.     if a then mined = mined + 1; isMiningTurtle = true
  1526.     elseif b == "Nothing to dig with" then
  1527.       print("This is not a mining turtle. To make a mining turtle, craft me together with a diamond pickaxe")
  1528.       error("",0)
  1529.     end
  1530.   end
  1531.   mine(false,false,true) --Get into quarry by going forward one
  1532.   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.
  1533.     gpsSecondPos = {gps.locate(gpsTimeout)} --Note: Does not run this if it has already been restarted.
  1534.   end
  1535.   for i = 1, startDown do
  1536.     eventAdd("down") --Add a bunch of down events to get to where it needs to be.
  1537.   end
  1538.   runAllEvents()
  1539.   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.
  1540. else --restore found
  1541.   if not(layersDone == layers and not doDigDown) then digDown() end
  1542.   if not(layersDone == layers and not doDigUp) then digUp() end  --Get blocks missed before stopped
  1543. end
  1544. --Mining Loops--------------------------------------------------------------------------
  1545. select(1)
  1546. while layersDone <= layers do -------------Height---------
  1547. local lastLayer = layersDone == layers --If this is the last layer
  1548. local secondToLastLayer = (layersDone + 1) == layers --This is a check for going down at the end of a layer.
  1549. moved = moved + 1 --To account for the first position in row as "moved"
  1550. if not(layersDone == layers and not doDigDown) then digDown() end --This is because it doesn't mine first block in layer
  1551. if not restoreFoundSwitch then rowCheck = true end
  1552. relxCalc()
  1553. while zPos <= z do -------------Width----------
  1554. while relxPos < x do ------------Length---------
  1555. 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
  1556. end ---------------Length End-------
  1557. if zPos ~= z then --If not on last row of section
  1558.   local func
  1559.   if rowCheck == true then --Switching to next row
  1560.   func = "right"; rowCheck = false; else func = false; rowCheck = true end --Which way to turn
  1561.     eventAdd("endOfRowTurn", zPos, facing , {not lastLayer or (doDigDown and lastLayer), not lastLayer or (doDigUp and lastLayer)}) --The table is passed to the mine function
  1562.     runAllEvents()
  1563. else break
  1564. end
  1565. end ---------------Width End--------
  1566. eventAdd("goto",1,1,yPos,0, "layerStart") --Goto start of layer
  1567. if not lastLayer then --If there is another layer
  1568.   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
  1569. end
  1570. eventAdd("setRowCheckFromPos")
  1571. eventAdd("relxCalc")
  1572. layersDone = layersDone + 1
  1573. restoreFoundSwitch = false --This is done so that rowCheck works properly upon restore
  1574. runAllEvents()
  1575. end ---------------Height End-------
  1576.  
  1577. endingProcedure() --This takes care of getting to start, dropping in chest, and displaying ending screen
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement