· 5 years ago · Jul 04, 2020, 08:02 PM
1--[[
2Version 3.2.1
3Recent Changes:
41. Now has session persistence! Just type "quarry -restore"
5 and your turtle will pick up where it left off
62. New Argument: startY to help stop it from getting stuck on those nasty sheep!
73. Most directional functions take care of invert. Exception is turtle.detect
8]]
9--[[ToDo:
101. Actually get the rednet send back and forth to work
113. Send basic commands from receiver program e.g. Stop
126. Add in rednet stuff
137. Massive update for rednet program
14]]
15--Defining things
16_G.civilTable = {}; civilTable = nil; setmetatable(civilTable, {__index = _G}); setfenv(1,civilTable)
17-------Defaults for Arguments----------
18--Arguments assignable by text
19x,y,z = 3,3,3 --These are just in case tonumber fails
20inverted = false --False goes from top down, true goes from bottom up [Default false]
21rednetEnabled = false --Default rednet on or off [Default false]
22--Arguments assignable by tArgs
23dropSide = "front" --Side it will eject to when full or done [Default "front"]
24careAboutResources = true --Will not stop mining once inventory full if false [Default true]
25doCheckFuel = true --Perform fuel check [Default true]
26doRefuel = false --Whenever it comes to start location will attempt to refuel from inventory [Default false]
27invCheckFreq = 10 --Will check for inventory full every <-- moved spaces [Default 10]
28keepOpen = 1 --How many inventory slots it will attempt to keep open at all times [Default 1]
29fuelSafety = "moderate" --How much fuel it will ask for: safe, moderate, and loose [Default moderate]
30saveFile = "Civil_Quarry_Restore" --Where it saves restore data [Default "Civil_Quarry_Restore"]
31doBackup = true --If it will keep backups for session persistence [Default true]
32numberOfStacksPerRun = 8 --How many stacks (number of items) the turtle expects (on average) to have before it must dump off. Not in arguments. [Default 8]
33gpsEnabled = false -- If option is enabled, will attempt to find position via GPS api [Default false]
34gpsTimeout = 3 --The number of seconds the program will wait to get GPS coords. Not in arguments [Default 3]
35logging = true --Whether or not the turtle will log mining runs. [Default ...still deciding]
36logFolder = "Quarry_Logs" --What folder the turtle will store logs in [Default "Quarry_Logs"]
37logExtension = "" --The extension of the file (e.g. ".txt") [Default ""]
38--Standard number slots for fuel (you shouldn't care)
39fuelTable = { --Will add in this amount of fuel to requirement.
40safe = 1000,
41moderate = 200,
42loose = 0 } --Default 1000, 200, 0
43--Standard rednet channels
44channels = {
45send = os.getComputerID() ,
46receive = os.getComputerID() + 100 ,
47confirm = "Confirm"
48}
49
50local help_paragraph = [[
51-DEFAULT: This will ignore all arguments and prompts and use defaults
52-vanilla: This will ignore all arguments except for dimensions
53-dim: [num] [num] [num] This sets the dimensions of the quarry
54-invert: [t/f] This sets whether invert is true or false
55-rednet: [t/f] This sets whether it will attempt to make a rednet connection
56-sendChannel: [num] This sets the channel the turtle will attempt to send on
57-receiveChannel: [num] This sets the channel the turtle will attempt to receive on
58-doRefuel: Changes whether or not the turtle will refuel itself with coal when fuel is low (opposite of written config)
59-doCheckFuel: Changes whether or not the turtle will check its fuel level before running (opposite of written config)
60-chest: [chest side] Changes what side turtle will output to
61-startY: [num] Tells the turtle what y coordinate it starts at, to make bedrock checking more accurate (hopefully)
62-keepOpen: [num] How many slots of the inventory turtle will try to keep open (Will then auto-empty)
63-invCheckFreq: [num] How many blocks before full inventory checks
64-saveFile: [word] Changes where the turtle saves its backup to.
65-doBackup: [t/f] Whether or not the turtle will backup its current position to a file.
66-restore: Turtle will check for a save file. If found will ignore all other arguments.
67-fuelSafety: [safe/moderate/loose] How much extra fuel the turtle will request at startup
68-GPS: Will toggle whether gps is on or not.
69 You must have a valid GPS network set up for this to work. It will take its starting location from this and its first position.
70 It will then store these values in its progress file in case your turtle stops for any reason.
71 On startup, the turtle will calculate its current position based on a new gps locate.
72-log: Turns logging on if not already on.
73 Will publish reports of mining runs to its own folder for later reading
74Smart Fueling System: As of 3.2.0, the turtle uses a new smart fueling system
75 With this new system you can shift click in as many stacks of fuel as you want, and it will take stacks of fuel at a time
76 This makes fueling for large jobs on new turtles much, much faster.
77Examples [1]:
78 The minimum amount necessary to start a turtle automatically would be one of these two
79 ---------
80 quarry -dim 3 3 3 -invert false -rednet false
81 ---------
82 quarry -dim 3 3 3 -vanilla
83 ---------
84 or, if you actually wanted a 3x3x3 then
85 ---------
86 quarry -DEFAULT
87Examples [2]:
88 If you wanted start a quarry that has
89 rednet on channels 500 and 501, outputs
90 to a chest below itself, is inverted,
91 and has the dimesions 5x5x21, then here
92 is what you would type: (Remember that
93 order does not matter)
94 ----------
95 quarry -receiveChannel 501 -sendChannel 500 -invert true -dim 5 5 21 -chest bottom -rednet true
96Examples [2] (cont.):
97 Now, this may be very long, but it is meant for people who want to make automated quarries with
98 the same settings every time (or with variable setting)
99Examples [3]:
100 If you are playing softcore then you
101 can do
102 ---------
103 quarry -doCheckFuel false
104 ---------
105 Followed by any other arguments
106Tips:
107 You don't actually have to type out "false" or "true" if you don't want. It actaully just checks if the first
108 letter is "t", so you (usually) don't have to put anything at all. Putting the whole word just helps with clarity
109Internal Config:
110 At the top of the program, right below the changelog is a written config. Anything not specified by arguments
111 will be taken from here. If you have a quarry setup you use a lot, you could just edit the config and then
112 type in the following:
113 ----------
114 quarry -DEFAULT
115]]
116
117--Parsing help for display
118--[[The way the help table works:
119All help indexes are numbered. There is a help[i].title that contains the title,
120and the other lines are in help[i][1] - help[i][#help[i] ]
121Different lines (e.g. other than first) start with a space.
122As of now, the words are not wrapped, fix that later]]
123local help = {}
124local i = 0
125local titlePattern = ".-%:" --Find the beginning of the line, then characters, then a ":"
126local textPattern = "%:.+" --Find a ":", then characters until the end of the line
127for a in help_paragraph:gmatch("\n?.-\n") do --Matches in between newlines
128local current = string.sub(a,1,-2).."" --Concatenate Trick
129if string.sub(current,1,1) ~= " " then
130i = i + 1
131help[i] = {}
132help[i].title = string.sub(string.match(current, titlePattern),1,-2)..""
133help[i][1] = string.sub(string.match(current,textPattern) or " ",3,-1)
134elseif string.sub(current,1,1) == " " then
135table.insert(help[i], string.sub(current,2, -1).."")
136end
137end
138
139
140local supportsRednet = (peripheral.wrap("right") ~= nil)
141
142local tArgs = {...}
143--You don't care about these
144 xPos,yPos,zPos,facing,percent,mined,moved,relxPos, rowCheck, connected, isInPath, layersDone, attacked, endRow, startY
145 = 0, 1, 1, 0, 0, 0, 0, 1, "right", false, true, 1, 0, 0, 0
146
147local totals = {cobble = 0, fuel = 0, other = 0} -- Total for display (cannot go inside function)
148local function count() --Done any time inventory dropped and at end
149slot = {} --1: Cobble 2: Fuel 3:Other
150for i=1, 16 do --[1] is type, [2] is number
151slot[i] = {}
152slot[i][2] = turtle.getItemCount(i)
153end
154slot[1][1] = 1 -- = Assumes Cobble/Main
155for i=1, 16 do --Cobble Check
156turtle.select(i)
157if turtle.compareTo(1) then
158slot[i][1] = 1
159totals.cobble = totals.cobble + slot[i][2]
160elseif turtle.refuel(0) then
161slot[i][1] = 2
162totals.fuel = totals.fuel + slot[i][2]
163else
164slot[i][1] = 3
165totals.other = totals.other + slot[i][2]
166end
167end
168turtle.select(1)
169end
170
171local getFuel = turtle.getFuelLevel
172do --Common variable name...
173local flag = turtle.getFuelLevel() == "Unlimited"
174turtle.getFuelLevel = function() --Unlimited screws up my calculations
175if not flag then --Also, this may or may not screw it up for other programs that run...
176 return getFuel()
177else
178 return math.huge --Lol... Should work for my purposes
179end
180end
181end
182local checkFuel = turtle.getFuelLevel --Just an alias for backwards compat
183
184 -----------------------------------------------------------------
185--Input Phase
186local function screen(xPos,yPos)
187xPos, yPos = xPos or 1, yPos or 1
188term.setCursorPos(xPos,yPos); term.clear(); end
189local function screenLine(xPos,yPos)
190term.setCursorPos(xPos,yPos); term.clearLine(); end
191
192screen(1,1)
193print("----- Welcome to Quarry! -----")
194print("")
195
196local sides = {top = "top", right = "right", left = "left", bottom = "bottom", front = "front"} --Used to whitelist sides
197local errorT = {num = "Numbers not recognized", zero = "Variable is out of range", word = "String failed assertion" }
198local changedT = {}
199changedT.new = function(key, value) changedT[#changedT+1] = {[key] = value} end
200changedT.getPair = function(i) for a, b in pairs(changedT[i]) do return a, b end end
201local function capitalize(text) return (string.upper(string.sub(text,1,1))..string.sub(text,2,-1)) end
202local function assert(condition, message, section) section = section or "[Blank]"; if condition then return condition else error("Error: "..message.."\nin section "..section, 0) end end
203local function checkNum(number, section) return assert(tonumber(number),errorT.num, section) end
204tArgs.checkStart = function(num) tArgs[tArgs[num]] = num end
205for i=1, #tArgs do tArgs.checkStart(i) end
206
207--Check if it is a turtle
208if not turtle then
209 print("This is not a turtle, you must be looking for the \"Companion Rednet Program\" \nCheck My forum thread for that")
210 print("Press 'q' to quit, or any other key to start help ")
211 if ({os.pullEvent("char")})[2] ~= "q" then tArgs.help = true else error("",0) end
212end
213
214
215if tArgs["help"] or tArgs["-help"] or tArgs["-?"] or tArgs["?"] then
216print("You have selected help, press any key to continue"); print("Use arrow keys to naviate, q to quit"); os.pullEvent("key")
217local pos = 1
218local key = 0
219while pos <= #help and key ~= keys.q do
220if pos < 1 then pos = 1 end
221screen(1,1)
222print(help[pos].title)
223for a=1, #help[pos] do print(help[pos][a]) end
224repeat
225_, key = os.pullEvent("key")
226until key == 200 or key == 208 or key == keys.q
227if key == 200 then pos = pos - 1 end
228if key == 208 then pos = pos + 1 end
229end
230error("",0)
231end
232
233--Saving
234if tArgs["doBackup"] then doBackup = (string.lower(string.sub(tArgs[tArgs["doBackup"]+1],1,1)) ~= "f") end
235if tArgs["saveFile"] then saveFile = tArgs[tArgs["saveFile"]+1] or saveFile end
236
237local restoreFound = false
238if tArgs["-restore"] or tArgs["-resume"] then
239restoreFound = fs.exists(saveFile)
240if restoreFound then
241os.run(getfenv(1),saveFile)
242if gpsEnabled then --If it had saved gps coordinates
243 print("Found GPS Start Coordinates")
244 local currLoc = {gps.locate(gpsTimeout)}
245 if #currLoc > 0 and #gpsStartPos > 0 and #gpsSecondPos > 0 then --Cover all the different positions I'm using
246 print("GPS Position Successfully Read")
247 if currLoc[1] == gpsStartPos[1] and currLoc[3] == gpsStartPos[3] then --X coord, y coord, z coord in that order
248 xPos, yPos, zPos = 0,1,1
249 if facing ~= 0 then turnTo(0) end
250 print("Is at start")
251 else
252 if inverted then --yPos setting
253 ------------------------------------------------FIX THIS
254 end
255 local function copyTable(tab) local toRet = {}; for a, b in pairs(tab) do toRet[a] = b end; return toRet end
256 local a, b = copyTable(gpsStartPos), copyTable(gpsSecondPos) --For convenience
257 if b[3] - a[3] == -1 then--If went north (-Z)
258 a[1] = a[1] - 1 --Shift x one to west to create a "zero"
259 xPos, zPos = -currLoc[3] + a[3], currLoc[1] + -a[1]
260 elseif b[1] - a[1] == 1 then--If went east (+X)
261 a[3] = a[3] - 1 --Shift z up one to north to create a "zero"
262 xPos, zPos = currLoc[1] + -a[1], currLoc[3] + -a[3]
263 elseif b[3] - a[3] == 1 then--If went south (+Z)
264 a[1] = a[1] + 1 --Shift x one to east to create a "zero"
265 xPos, zPos = currLoc[3] + a[3], -currLoc[1] + a[3]
266 elseif b[1] - a[1] == -1 then--If went west (-X)
267 a[3] = a[3] + 1 --Shift z down one to south to create a "zero"
268 xPos, zPos = -currLoc[1] + a[1], -currLoc[3] + a[3]
269 else
270 print("Improper Coordinates")
271 print("GPS Locate Failed, Using Standard Methods") ----Maybe clean this up a bit to use flags instead.
272 end
273 end
274 print("X Pos: ",xPos)
275 print("Y Pos: ",yPos)
276 print("Z Pos: ",zPos)
277 print("Facing: ",facing)
278 else
279 print("GPS Locate Failed, Using Standard Methods")
280 end
281print("Restore File read successfully. Starting in 3"); sleep(3)
282end
283end
284else
285 originalFuel = checkFuel() --For use in logging. To see how much fuel is REALLY used
286end
287
288if not (tArgs["-DEFAULT"] or restoreFound) then
289 --Just a note, the whole error checking section here was more of an
290 --experiment than anything else. If its ever changed in the future,
291 --it would probably be for the better.
292local section = "Dimensions"
293--Dimesnions
294if tArgs["-dim"] then local num = tArgs["-dim"];
295x = checkNum(tArgs[num + 1],section); z = checkNum(tArgs[num + 2],section); y = checkNum(tArgs[num + 3],section)
296else
297print("What dimensions?")
298print("")
299--This will protect from negatives, letters, and decimals
300term.write("Length: ")
301x = math.floor(math.abs(tonumber(io.read()) or x))
302term.write("Width: ")
303z = math.floor(math.abs(tonumber(io.read()) or z))
304term.write("Height: ")
305y = math.floor(math.abs(tonumber(io.read()) or y))
306end
307changedT.new("x",x); changedT.new("z",z); changedT.new("y",y)
308assert(x~=0, errorT.zero, section); assert(z~=0, errorT.zero, section); assert(y~=0, errorT.zero, section)
309assert(not(x == 1 and y == 1 and z == 1) ,"1, 1, 1 dosen't work well at all, try again", section)
310if not tArgs["-vanilla"] then
311--Invert
312if tArgs["-invert"] then
313inverted = (string.lower(string.sub(tArgs[tArgs["-invert"]+1] or "",1,1)) == "t") else
314term.write("Inverted? ")
315inverted = (string.lower(string.sub(io.read(),1,1)) == "y")
316end
317changedT.new("Inverted", inverted)
318--Rednet
319if supportsRednet then
320if tArgs["-rednet"] then
321rednetEnabled = (string.lower(string.sub(tArgs[tArgs["-rednet"]+1] or "",1,1)) == "t")
322else term.write("Rednet? "); rednetEnabled = (string.lower(string.sub(io.read(),1,1)) == "y")
323if (tArgs["-GPS"] or tArgs["-gps"]) and not restoreFound and not gpsEnabled then --The not gps enabled makes it so it is toggled
324gpsStartPos = {gps.locate(gpsTimeout)} --Stores position in array
325gpsEnabled = #gpsStartPos > 0 --Checks if location received properly
326changedT.new("GPS Location Services", gpsEnabled)
327end
328changedT.new("Rednet Enabled", rednetEnabled)
329end
330if tArgs["-sendChannel"] then
331channels.send = assert(tonumber(tArgs[tArgs["-sendChannel"]+1]), errorT.num)
332assert(channels.send > 0 and channels.send < 65535, errorT.zero)
333changedT.new("Send Channel",channels.send) end
334if tArgs["-receiveChannel"] then
335channels.receive = assert(tonumber(tArgs[tArgs["-receiveChannel"]+1]), errorT.num)
336assert(channels.receive > 0 and channels.receive < 65535 and channels.receive ~= channels.send, errorT.zero)
337changedT.new("Receive Channel",channels.receive) end
338end
339--Fuel
340if tArgs["-doRefuel"] then doRefuel = not doRefuel; changedT.new("Do Refuel",doRefuel) end
341if turtle.getFuelLevel() == "unlimited" then
342 doCheckFuel = false
343else
344 if tArgs["-doCheckFuel"] then
345 doCheckFuel = (string.lower(string.sub(tArgs[tArgs["-doCheckFuel"]+1] or "",1,1)) == "t"); changedT.new("Do Check Fuel", doCheckFuel) end
346end
347if tArgs["-chest"] then
348dropSide = sides[tArgs[tArgs["-chest"]+1]] or dropSide; changedT.new("Chest Side",dropSide) end
349if tArgs["-fuelSafety"] then local loc = tArgs[tArgs["-fuelSafety"]+1]
350 if fuelTable[loc] then
351 fuelSafety = loc; changedT.new("Fuel Check Safety", fuelSafety)
352 end
353end
354--Logging
355logging = (tArgs["-log"] and true) or logging --The and will set it to true if value, or its original value if nil
356if logging then changedT.new("Logging",logging) end
357if tArgs["-logFolder"] then logFolder = tArgs[tArgs["-logFolder"]+1] or logFolder; changedT.new("Log Folder",logFolder) end
358if tArgs["-logExtension"] then logExtension = tArgs[tArgs["-logExtension"]+1] or logExtension; changedT.new("Log Extension",logExtension) end
359--Misc
360if tArgs["-startY"] then
361startY = math.abs(math.floor(checkNum(tArgs[tArgs["-startY"]+1],"Start Y")))
362changedT.new("Start Y Position",startY) end
363assert(startY >= 0, errorT.zero, "StartY")
364if tArgs["-invCheckFreq"] then
365invCheckFreq = math.abs(math.floor(checkNum(tArgs[tArgs["-invCheckFreq"]+1],"Inventory Check Frequency")))
366changedT.new("Inventory Check Frequency",invCheckFreq) end
367assert(invCheckFreq ~= 0, errorT.zero, "Inventory Check Frequency")
368if tArgs["-keepOpen"] then
369keepOpen = math.abs(math.floor(checkNum(tArgs[tArgs["-keepOpen"]+1],"Open Slots")))
370changedT.new("Slots to keep open", keepOpen) end
371assert(keepOpen ~= 0 and keepOpen < 16, errorT.zero, "Open Slots")
372if tArgs["-ignoreResources"] then careAboutResources = false; changedT.new("Ignore Resources?", not careAboutResources) end
373if tArgs["-saveFile"] then saveFile = tArgs[tArgs["-saveFile"]+1] changedT.new("Save File", saveFile) end
374assert(#saveFile >= 2,errorT.word, "Save File")
375end; end --First end is for vanilla, second is for DEFAULT
376
377local function saveProgress(extras) --Session persistence
378if doBackup then
379local file = fs.open(saveFile,"w")
380for a,b in pairs(getfenv(1)) do
381if type(b) == "string" then b = "\""..b.."\"" end
382if type(b) == "table" and a~="modem" then b = textutils.serialize(b) end
383if type(b) ~= "function" then
384file.write(a.." = "..tostring(b).."\n")
385end
386end
387file.write("doCheckFuel = false\n") --It has already used fuel, so calculation unnesesary
388if type(extras) == "table" then
389 for a, b in pairs(extras) do
390 file.write(a.." = "..tostring(b))
391 end
392end
393file.close()
394end
395end
396
397local area = x*z
398local volume = x*y*z
399local lastHeight = y%3
400local dispY = y
401y = math.floor(y/3)*3
402local yMult = y/3 + math.ceil(lastHeight/2) --This is basically a smart y/3 for movement
403local moveVolume = (area * yMult) --Kept for display percent
404--Calculating Needed Fuel--
405local exStack = numberOfStacksPerRun --Expected stacks of items before full
406neededFuel = yMult * x * z + --This is volume it will run through
407 dispY*(2+1/(64*exStack)) + --This is simplified and includes the y to get up times up and down + how many times it will drop stuff off
408 (x+z)*(yMult + 1/(64*exStack)) --Simplified as well: It is getting to start of row plus getting to start of row how many times will drop off stuff
409 --Original equation: x*z*y/3 + y * 2 + (x+z) * y/3 + (x + z + y) * (1/64*8)
410neededFuel = math.ceil(neededFuel)
411
412--Getting Fuel
413if doCheckFuel and checkFuel() < neededFuel then
414neededFuel = neededFuel + fuelTable[fuelSafety] --For safety
415 print("Not enough fuel")
416 print("Current: ",checkFuel()," Needed: ",neededFuel)
417 print("Starting SmartFuel...")
418 sleep(2) --So they can read everything.
419 term.clear()
420 local oneFuel, neededFuelItems
421 local currSlot = 0
422 local function output(text, x, y) --For displaying fuel
423 currX, currY = term.getCursorPos()
424 term.setCursorPos(x,y)
425 term.clearLine()
426 term.write(text)
427 term.setCursorPos(currX,currY)
428 end
429 local function roundTo(num, target) --For stacks of fuel
430 if num >= target then return target elseif num < 0 then return 0 else return num end
431 end
432 local function updateScreen()
433 output("Welcome to SmartFuel! Now Refueling...", 1,1)
434 output("Currently taking fuel from slot "..currSlot,1,2)
435 output("Current single fuel: "..tostring(oneFuel or 0),1,3)
436 output("Current estimate of needed fuel: ",1,4)
437 output("Single Items: "..math.floor(neededFuelItems or 0),4,5)
438 output("Stacks: "..math.ceil((neededFuelItems or 0) / 64),4,6)
439 output("Needed Fuel: "..tostring(neededFuel),1,12)
440 output("Current Fuel: "..tostring(checkFuel()),1,13)
441 end
442 while checkFuel() <= neededFuel do
443 currSlot = currSlot + 1
444 turtle.select(currSlot)
445 updateScreen()
446 while turtle.getItemCount(currSlot) == 0 do sleep(1.5) end
447 repeat
448 local previous = checkFuel()
449 turtle.refuel(1)
450 oneFuel = checkFuel() - previous
451 updateScreen()
452 until (oneFuel or 0) > 0 --Not an if to prevent errors if fuel taken out prematurely.
453 neededFuelItems = (neededFuel - checkFuel()) / oneFuel
454 turtle.refuel(roundTo(neededFuelItems, 64)) --Change because can only think about 64 at once.
455 if turtle.getItemCount(roundTo(currSlot + 1, 16)) == 0 then --Resets if no more fuel
456 currSlot = 0
457 end
458 end
459-- local neededFuel = moveVolume + (math.floor(volume / (64 * 8)) * (x+dispY+z)) --Standard move plus dropping off supplies
460 -- --How many times come back to start| * If it were at the very far side
461-- neededFuel = neededFuel + fuelTable[fuelSafety]
462-- if neededFuel < 100 then neededFuel = 100; end
463-- if checkFuel() < neededFuel then
464-- screen(1,1)
465-- print("More Fuel Needed")
466-- print("Current Fuel: ",checkFuel()," Needed: ",neededFuel)
467-- print("Place fuel in Bottom Right")
468-- while turtle.getItemCount(16) == 0 do
469 -- sleep(1)
470-- end
471-- turtle.select(16)
472-- while checkFuel() < neededFuel do
473-- if not turtle.refuel(1) then
474-- term.clearLine()
475-- print("Still too little fuel")
476-- term.clearLine()
477-- print("Insert more fuel to resume")
478-- while turtle.getItemCount(16) == 0 do
479 -- sleep(1)
480-- end
481-- end
482-- local x,y = term.getCursorPos()
483-- print(checkFuel().." Fuel")
484-- term.setCursorPos(x,y)
485-- end
486-- print(checkFuel().." Units of Fuel")
487-- sleep(3)
488-- turtle.select(1)
489-- end
490end
491--Initial Rednet Handshake
492if rednetEnabled then
493screen(1,1)
494print("Rednet is Enabled")
495print("The Channel to open is "..channels.send)
496modem = peripheral.wrap("right")
497modem.open(channels.receive)
498local i = 0
499repeat
500local id = os.startTimer(3)
501i=i+1
502print("Sending Initial Message "..i)
503modem.transmit(channels.send, channels.receive, "{ 'Initial' }")
504local message
505repeat
506local event, idCheck, channel,_,locMessage, distance = os.pullEvent()
507message = locMessage
508until (event == "timer" and idCheck == id) or (event == "modem_message" and channel == channels.receive and message == channels.confirm)
509until message == channels.confirm
510connected = true
511print("Connection Confirmed!")
512sleep(1.5)
513end
514local function biometrics(sendChannel)
515local commands = { Confirm = "Confirm" }
516local toSend = { ["x"] = x, ["y"] = (y/3 + math.ceil(lastHeight/2)), ["z"] = z, --The y calc is weird...
517 ["xPos"] = xPos, ["yPos"] = yPos, ["zPos"] = zPos,
518 ["percent"] = percent, ["mined" ]= mined,
519 ["fuel"] = checkFuel(), ["moved"] = moved,
520 ["remainingBlocks"] = (volume-mined), ["ID"] = os.getComputerID(),
521 ["isInPath"] = isInPath, --Whether it is going back to start
522 ["volume"] = volume, ["area"] = area}
523modem.transmit(channels.send, channels.receive, textutils.serialize(toSend))
524id = os.startTimer(0.1)
525local event, message
526repeat
527local locEvent, idCheck, confirm, _, locMessage, distance = os.pullEvent()
528event, message = locEvent, locMessage
529until (event == "timer" and idCheck == id) or (event == "modem_message" and confirm == channels.receive)
530if event == "modem_message" then connected = true else connected = false end
531--Stuff to do for different commands
532end
533--Showing changes to settings
534screen(1,1)
535print("Your selected settings:")
536if #changedT == 0 then
537print("Completely Default")
538else
539for i=1, #changedT do
540local title, value = changedT.getPair(i)
541print(capitalize(title)..": ",value)
542end
543end
544print("\nStarting in 3"); sleep(1); print("2"); sleep(1); print("1"); sleep(1.5) --Dramatic pause at end
545
546
547
548----------------------------------------------------------------
549--Define ALL THE FUNCTIONS
550function display() --This is just the last screen that displays at the end
551screen(1,1)
552print("Total Blocks Mined: "..mined)
553print("Current Fuel Level: "..turtle.getFuelLevel())
554print("Cobble: "..totals.cobble)
555print("Usable Fuel: "..totals.fuel)
556print("Other: "..totals.other)
557if rednetEnabled then
558print("")
559print("Sent Stop Message")
560finalTable = {{["Mined: "] = mined}, {["Cobble: "] = totals.cobble}, {["Fuel: "] = totals.fuel},
561 {["Other: "] = totals.other}, {["Fuel: "] = checkFuel()} }
562modem.transmit(channels.send,channels.receive,"stop")
563modem.transmit(channels.send,channels.receive,textutils.serialize(finalTable))
564modem.close(channels.receive)
565end
566if doBackup then fs.delete(saveFile) end
567end
568function updateDisplay() --Runs in Mine(), display information to the screen in a certain place
569screen(1,1)
570print("Blocks Mined")
571print(mined)
572print("Percent Complete")
573print(percent.."%")
574print("Fuel")
575print(checkFuel())
576if rednetEnabled then
577screenLine(1,7)
578print("Connected: "..tostring(connected))
579end
580end
581function logMiningRun(textExtension, extras) --Logging mining runs
582if logging then
583local number
584if not fs.isDir(logFolder) then
585 fs.delete(logFolder)
586 fs.makeDir(logFolder)
587 number = 1
588else
589 local i = 0
590 repeat
591 i = i + 1
592 until not fs.exists(logFolder.."/Quarry_Log_"..tostring(i)..(textExtension or ""))
593 number = i
594end
595handle = fs.open(logFolder.."/Quarry_Log_"..tostring(number)..(textExtension or ""),"w")
596local function write(...)
597 for a, b in ipairs({...}) do
598 handle.write(tostring(b))
599 end
600 handle.write("\n")
601end
602write("Welcome to the Quarry Logs!")
603write("Entry Number: ",number)
604write("Dimensions (X Z Y): ",x," ",z," ", dispY)
605write("Blocks Mined: ", mined)
606write(" Cobble: ", totals.cobble)
607write(" Usable Fuel: ", totals.fuel)
608write(" Other: ",totals.other)
609write("Total Fuel Used: ", originalFuel- checkFuel())
610write("Expected Fuel Use: ", neededFuel)
611handle.close()
612end
613end
614function isFull(slots)
615 slots = slots or 16
616 local numUsed = 0
617 sleep(0)
618 for i=1, slots do
619 if turtle.getItemCount(i) > 0 then numUsed = numUsed + 1 end
620 end
621 if numUsed >= slots then
622 return true
623 end
624 return false
625end
626function dig(doAdd, func)
627 doAdd = doAdd or true
628 func = func or turtle.dig
629 if func() then
630 if doAdd then
631 mined = mined + 1
632 end
633 return true
634 end
635 return false
636end
637function digUp(doAdd)
638 return dig(doAdd,turtle.digUp)
639end
640function digDown(doAdd)
641 return dig(doAdd,turtle.digDown)
642end
643function relativeXCalc()
644 if rowCheck == "right" then relxPos = xPos else relxPos = (x-xPos)+1 end
645end
646function forward(doAdd)
647 if doAdd == nil then doAdd = true end
648 if turtle.forward() then
649 if doAdd then
650 moved = moved + 1
651 end
652 if facing == 0 then
653 xPos = xPos + 1
654 elseif facing == 1 then
655 zPos = zPos + 1
656 elseif facing == 2 then
657 xPos = xPos - 1
658 elseif facing == 3 then
659 zPos = zPos - 1
660 else
661 error("Function forward, facing should be 0 - 3, got "..tostring(facing),2)
662 end
663 relativeXCalc()
664 return true
665 end
666 return false
667end
668function up(sneak)
669 sneak = sneak or 1
670 if inverted and sneak == 1 then
671 down(-1)
672 else
673 while not turtle.up() do
674 if not digUp() then
675 attackUp()
676 sleep(0.5)
677 end
678 end
679 yPos = yPos - sneak --Oh! I feel so clever
680 end --This works because inverted :)
681end
682function down(sneak)
683 sneak = sneak or 1
684 local count = 0
685 if inverted and sneak == 1 then
686 up(-1)
687 else
688 while not turtle.down() do
689 count = count + 1
690 if not digDown() then
691 attackDown()
692 sleep(0.2)
693 end
694 if count > 20 then bedrock() end
695 end
696 yPos = yPos + sneak
697 end
698end
699function right(num)
700 num = num or 1
701 for i=1, num do facingF(1); saveProgress(); turtle.turnRight() end
702end
703function left(num)
704 num = num or 1
705 for i=1, num do facingF(-1); saveProgress(); turtle.turnLeft() end
706end
707function attack(doAdd, func)
708 doAdd = doAdd or true
709 func = func or turtle.attack
710 if func() then
711 if doAdd then
712 attacked = attacked + 1
713 end
714 return true
715 end
716 return false
717end
718function attackUp(doAdd)
719 if inverted then
720 return attack(doAdd, turtle.attackDown)
721 else
722 return attack(doAdd, turtle.attackUp)
723 end
724end
725function attackDown(doAdd)
726 if inverted then
727 return attack(doAdd, turtle.attackUp)
728 else
729 return attack(doAdd, turtle.attackDown)
730 end
731end
732
733
734function mine(doDigDown, doDigUp, outOfPath,doCheckInv) -- Basic Move Forward
735if doCheckInv == nil then doCheckInv = true end
736if doDigDown == nil then doDigDown = true end
737if doDigUp == nil then doDigUp = true end
738if outOfPath == nil then outOfPath = false end
739if inverted then
740 doDigUp, doDigDown = doDigDown, doDigUp --Just switch the two if inverted
741end
742if doRefuel and checkFuel() <= fuelTable[fuelSafety]/2 then
743 for i=1, 16 do
744 if turtle.getItemCount(i) > 0 then
745 turtle.select(i)
746 if checkFuel() < 200 + fuelTable[fuelSafety] then
747 turtle.refuel()
748 end
749 end
750 end
751end
752local count = 0
753while not forward(not outOfPath) do
754 sleep(0) --Calls coroutine.yield to prevent errors
755 count = count + 1
756 if not dig() then
757 attack()
758 end
759 if count > 10 then
760 attack()
761 sleep(0.2)
762 end
763 if count > 50 then
764 if turtle.getFuelLevel() == 0 then --Don't worry about inf fuel because I modified this function
765 saveProgress({doCheckFuel = true})
766 error("No more fuel",0)
767 elseif yPos > (startY-7) then --If it is near bedrock
768 bedrock()
769 else --Otherwise just sleep for a bit to avoid sheeps
770 sleep(1)
771 end
772 end
773end
774local tab = {} --This registers a change in the saveProgress file
775if facing == 0 then --I do this because when it restores, it always
776 tab.xPos = xPos + 1-- Thinks it is one position back, for some reason
777elseif facing == 1 then-- This overwrites that.
778 tab.zPos = zPos + 1
779elseif facing == 2 then
780 tab.xPos = xPos - 1
781elseif facing == 3 then
782 tab.zPos = zPos - 1
783end
784saveProgress(tab)
785if doDigUp then
786while turtle.detectUp() do
787 sleep(0) --Calls coroutine.yield
788 if not digUp() then
789 attackUp()
790 count = count + 1
791 end
792 if count > 50 and yPos > (startY-7) then --Same deal with bedrock as above
793 bedrock()
794 end
795 end
796end
797if doDigDown then
798 digDown()
799end
800percent = math.ceil(moved/moveVolume*100)
801updateDisplay()
802isInPath = (not outOfPath) --For rednet
803if doCheckInv and careAboutResources then
804if moved%invCheckFreq == 0 then
805 if isFull(16-keepOpen) then dropOff() end
806end; end
807if rednetEnabled then biometrics() end
808end
809--Direction: Front = 0, Right = 1, Back = 2, Left = 3
810function facingF(num)
811facing = facing + num
812if facing > 3 then facing = 0 end
813if facing < 0 then facing = 3 end
814end
815
816function turnTo(num, dir)
817 num = num or facing
818 dir = dir or "left"
819 while facing ~= num do
820 if dir == "left" then
821 left()
822 elseif dir == "right" then
823 right()
824 else
825 error("TurnTo: Left or Right expected, got "..tosrting(dir))
826 end
827 end
828end
829function goto(x,z,y, toFace)
830--Will first go to desired z pos, then x pos, y pos varies
831x = x or 1; y = y or 1; z = z or 1; toFace = toFace or facing
832gotoX,gotoY,gotoZ,gotoFacing = xPos,yPos,zPos,facing --For use in session persistence
833if yPos > y then --Will go up first if below position
834 while yPos~=y do up() end
835end
836if zPos > z then
837 turnTo(3)
838elseif zPos < z then
839 turnTo(1)
840end
841while zPos ~= z do mine(false,false,true,false) end
842if xPos > x then
843 turnTo(2)
844elseif xPos < x then
845 turnTo(0)
846end
847while xPos ~= x do mine(false,false,true,false) end
848if yPos < y then --Will go down after if above position
849 while yPos~=y do down() end
850end
851turnTo(toFace,"right")
852saveProgress()
853gotoX,gotoY,gotoZ,gotoFacing = nil
854end
855function drop(side, final, allowSkip)
856side = sides[side] or "front" --The final number means that it will
857if final then final = 0 else final = 1 end --drop a whole stack at the end
858local allowSkip = allowSkip or (final == 0) --This will allow drop(side,t/f, rednetConnected)
859count()
860if doRefuel then
861 for i=1, 16 do
862 if slot[i][1] == 2 then
863 turtle.select(i); turtle.refuel()
864 end
865 end
866 turtle.select(1)
867end
868if side == "right" then turnTo(1) end
869if side == "left" then turnTo(3) end
870local whereDetect, whereDrop1, whereDropAll
871local _1 = slot[1][2] - final --All but one if final, all if not final
872if side == "top" then
873whereDetect = turtle.detectUp ; whereDrop = turtle.dropUp
874elseif side == "bottom" then
875whereDetect = turtle.detectDown ; whereDrop = turtle.dropDown
876else
877whereDetect = turtle.detect; whereDrop = turtle.drop
878end
879local function waitDrop(val) --This will just drop, but wait if it can't
880 val = val or 64
881 local try = 1
882 while not whereDrop(val) do
883 print("Chest Full, Try "..try)
884 try = try + 1
885 sleep(2)
886 end
887end
888repeat
889local detected = whereDetect()
890if detected then
891 waitDrop(_1)
892 for i=2, 16 do
893 if turtle.getItemCount(i) > 0 then
894 turtle.select(i)
895 waitDrop()
896 end
897 end
898elseif not allowSkip then
899 print("Waiting for chest placement place a chest to continue")
900 while not whereDetect() do
901 sleep(1)
902 end
903end
904until detected or allowSkip
905if not allowSkip then totals.cobble = totals.cobble - 1 end
906turtle.select(1)
907turnTo(0)
908end
909function dropOff() --Not local because called in mine()
910local currX,currZ,currY,currFacing = xPos, zPos, yPos, facing
911goto(0,1,1,2)
912drop(dropSide,false)
913mine(false,false,true, false)
914goto(1,1,1, 0)
915goto(currX,currZ,currY,currFacing)
916end
917function bedrock()
918if checkFuel() == 0 then error("No Fuel",0) end
919local origin = {x = xPos, y = yPos, z = zPos}
920print("Bedrock Detected")
921if turtle.detectUp() then
922print("Block Above")
923local var
924if facing == 0 then var = 2 elseif facing == 2 then var = 0 else error("Was facing left or right on bedrock") end
925goto(xPos,zPos,yPos,var)
926for i=1, relxPos do mine(true,true); end
927end
928goto(0,1,1,2)
929drop(dropSide, true)
930display()
931print("\nFound bedrock at these coordinates: ")
932print(origin.x," Was position in row\n",origin.z," Was row in layer\n",origin.y," Blocks down from start")
933error("",0)
934end
935-------------------------------------------------------------------------------------
936--Pre-Mining Stuff dealing with session persistence
937local doDigDown, doDigUp = (lastHeight ~= 1), false --Used in lastHeight
938if not restoreFound then
939--Check if it is a mining turtle
940if not isMiningTurtle then
941 local a, b = turtle.dig()
942 if a then mined = mined + 1; isMiningTurtle = true
943 elseif b == "Nothing to dig with" then
944 print("This is not a mining turtle. To make a mining turtle, craft me together with a diamond pickaxe")
945 error("",0)
946 end
947end
948else digUp(); digDown() end --Get it into the quarry
949if gpsEnabled and not restoreFound then --The initial locate is done in the arguments. This is so I can figure out what quadrant the turtle is in.
950 gpsSecondPos = {gps.locate(gpsTimeout)} --Note: Does not run this if it has already been restarted.
951end
952if restoreFound then
953 if gotoX then
954 goto(gotoX,gotoZ,gotoY,gotoFacing)
955 end
956 local func
957 if rowCheck == "left" then func = right else func = left end
958 if endRow == 1 then
959 mine()
960 func()
961 elseif endRow == 2 then
962 func()
963 end
964end
965if y ~= 0 and not restoreFound then down() end
966--Mining Loops
967turtle.select(1)
968while layersDone <= y do -------------Height---------
969moved = moved + 1 --To account for the first position in row as "moved"
970if not restoreFound then rowCheck = "right" end
971relativeXCalc()
972while zPos <= z do -------------Width----------
973while relxPos < x do ------------Length---------
974mine()
975end ---------------Length End-------
976if zPos ~= z then
977local func
978if rowCheck == "right" and zPos ~= z then --Swithcing to next row
979 func = right; rowCheck = "left"; else func = left; rowCheck = "right" end --Which way to turn
980 func()
981 endRow = 1
982 mine()
983 endRow = 2
984 func()
985 endRow = 0
986else break
987end
988end ---------------Width End--------
989goto(1,1,yPos,0)
990if yPos+1 ~= y then
991 for i=1, 3 do down() end
992end
993layersDone = layersDone + 3
994restoreFound = false --This is done so that rowCheck works properly upon restore
995end ---------------Height End-------
996if lastHeight ~= 0 then ---------LAST ROW--------- (copied from above)
997moved = moved + 1 --To account for the first position in row as "moved"
998if y ~= 0 then --If the basic y == 2 or 1
999 for i=1, 2 do down() end
1000end
1001if not restoreFound then rowCheck = "right" end
1002relativeXCalc()
1003while zPos <= z do -------------Width----------
1004while relxPos < x do ------------Length---------
1005mine(doDigDown,doDigUp)
1006end ---------------Length End-------
1007if zPos ~= z then
1008local func
1009if rowCheck == "right" and zPos ~= z then --Swithcing to next row
1010 func = right; rowCheck = "left"; else func = left; rowCheck = "right" end --Which way to turn
1011 func()
1012 endRow = 1
1013 mine(doDigDown,doDigUp)
1014 endRow = 2
1015 func()
1016 endRow = 0
1017else break
1018end
1019end ---------------Width End--------
1020goto(1,1,yPos,0)
1021end
1022if doDigDown then
1023 if inverted then
1024 digUp()
1025 else
1026 digDown()
1027 end
1028end
1029goto(0,1,1,2)
1030
1031--Output to a chest or sit there
1032drop(dropSide, true)
1033--Display was moved above to be used in bedrock function
1034display()
1035--Log current mining run
1036logMiningRun(logExtension)
1037
1038--Cleanup
1039turtle.getFuelLevel = getFuel