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