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