View difference between Paste ID: DZNBPRV6 and Mj1H7sMF
SHOW: | | - or go back to the newest paste.
1
--[[
2
	Do whatever you want with the script, but give credit to people who wrote it and keep this license. Simple, right?
3
	Writers: 
4
	access_denied
5
]]
6
7
--[[
8
	OreDig version 1.4.1
9
]]
10
11
--[[
12
	CONSTANTS
13
]]
14-
BEDROCK_LEVEL = 5 --Level at which the bedrock is
14+
BEDROCK_LEVEL = 2 --Level at which the bedrock is
15
PERSISTANCE_FILE_PATH = "digpersist"
16
MOVEMENT_DELAY = 0.0
17
ROTATION_DELAY = 0.0
18
TRY_LIMIT = 10
19
STARTUP_SCRIPT_STRING = [[shell.run("%s", "resume")]]
20
21
DIRS = { --Directions are numbers for easy manipulation.
22
	NORTH = 0,
23
	EAST = 1,
24
	SOUTH = 2,
25
	WEST = 3,
26
}
27
28
TASKS = { --Different task descriptions
29
	SHAFT =  "digging shaft",
30
	MOVING_TO_DOCK = "moving to dock",
31
	MOVING_TO_SHAFT = "moving to shaft",
32
	REFUELING = "refueling",
33
	DUMPING = "dumping all items",
34
	WAITING_FOR_FUEL = "waiting for fuel",
35
	FINISHED = "finished"
36
}
37
38
STARTUP_SCRIPT_INSTALL_STATUS = {
39
	NOT_INSTALLED = 1,
40
	DIFFERENT = 2,
41
	INSTALLED = 0
42
}
43
--[[
44
	Code from http://wiki.interfaceware.com/112.html
45
	Allows me to serialize tables.
46
]]
47
function SaveTable(Table)
48
   local savedTables = {} -- used to record tables that have been saved, so that we do not go into an infinite recursion
49
   local outFuncs = {
50
      ['string']  = function(value) return string.format("%q",value) end;
51
      ['boolean'] = function(value) if (value) then return 'true' else return 'false' end end;
52
      ['number']  = function(value) return string.format('%f',value) end;
53
   }
54
   local outFuncsMeta = {
55
      __index = function(t,k) error('Invalid Type For SaveTable: '..k) end      
56
   }
57
   setmetatable(outFuncs,outFuncsMeta)
58
   local tableOut = function(value)
59
      if (savedTables[value]) then
60
         error('There is a cyclical reference (table value referencing another table value) in this set.');
61
      end
62
      local outValue = function(value) return outFuncs[type(value)](value) end
63
      local out = '{'
64
      for i,v in pairs(value) do out = out..'['..outValue(i)..']='..outValue(v)..';' end
65
      savedTables[value] = true; --record that it has already been saved
66
      return out..'}'
67
   end
68
   outFuncs['table'] = tableOut;
69
   return tableOut(Table);
70
end
71
72
function LoadTable(Input)
73
   -- note that this does not enforce anything, for simplicity
74
   return assert(loadstring('return '..Input))()
75
end
76
77
--[[
78
	Now my stuff
79
]]
80
81
data = { --Just a table that I have created for convenience. It will be written to a file every move. Keeps track of many different variables.
82
	lenx = 4, --Width of quarry
83
	lenz = 4, --Depth of quarry
84
	height = 6, --Height of quarry
85
	shaftsDone = 0, --How many shafts are already done
86
	shaftsToDo = 0, --How many shafts left
87
	dir = DIRS.NORTH, --Relative direction in which the turtle is currently facing. North will always be the direction in which the turtle was facing when it was started.
88
	reservedSlots = 2, --How many slots are reserved for items that aren't to be mined and fuel items.
89
	fuelPerItem = 80, --How much fuel is given per fuel item
90
	currentlyDoing = TASKS.WAITING_FOR_FUEL, --What task is currently being done
91
	currentShaftProgress = 0, --How many blocks are done in the current shaft
92
	coords = {}, --Current coordinates relative to the dock
93
	shafts = {}, --Array of shaft coordinates left to do
94
	fuelItemsRequired = 0,
95
	fuelItemsUsed = 0,
96
	debug = 0,
97
	shaftsGenerated = false
98
}
99
data.coords = {x = 0, y = data.height, z = 0} --We start at the dock.
100
--[[
101
	Helper methods
102
]]
103
function xor(a, b) return (a~=b) and (a or b) end --Fake XOR snipplet
104
function cleanup()
105
	term.clear()
106
	term.setCursorPos(1, 1)
107
end
108
--[[
109
	Persistance
110
]]
111
function dumpToFile() --Dump the state to file
112
	local file = io.open(PERSISTANCE_FILE_PATH, "w")
113
	file:write(SaveTable(data))
114
	file:close()
115
end
116
117
function readFromFile() --Read the state from file
118
	local file = io.open(PERSISTANCE_FILE_PATH, "r")
119
	if file then
120
		local tableStr = file:read("*a")
121
		data = LoadTable(tableStr)	
122
		file:close()
123
	end
124
end
125
126
function periodicSave()
127
	while 1 do
128
		dumpToFile()
129
		sleep(0.5)
130
	end
131
end
132
--[[
133
	Mining methods
134
]]
135
do
136
	function setStatus(status)
137
		data.currentlyDoing = status
138
	end
139
	local function getRequiredFuelToGoBack(x, y, z) --Not tested, but should return the fuel required to go back to dock
140
		return data.height - y + x + z + 2
141
	end
142
	local function getRequiredFuelToProcessShaft(x, z) --Calculates how much fuel is required to go to the shaft, process it and come back.
143
		return (data.height - BEDROCK_LEVEL + x + z + 2) * 2
144
	end
145
	local function hasRequiredFuelToGoBack(x, y, z)
146
		return getRequiredFuelToGoBack(x, y, z) <= turtle.getFuelLevel()
147
	end
148
	local function hasRequiredFuelToProcessShaft(x, z)
149
		return getRequiredFuelToProcessShaft(x, z) <= turtle.getFuelLevel()
150
	end
151
	local function hasRequiredFuelAndSpace(x, y, z)
152
		return hasRequiredFuelToGoBack(x, y, z) and turtle.getItemCount(16) == 0 -- We need enough fuel to go up after going down and return to the dock. We also need space to put the items into.
153
	end
154
	function setDir(todir) --Turn to the required direction optimaly
155
		if(data.dir == todir) then return end --No need to turn!
156
		local way = math.abs(data.dir-todir) <= (math.min(data.dir, todir) + 4 - math.max(data.dir,todir)) -- true if we don't need to go "out of bounds", e.g. <-0 or 3->
157
		local rotdir = (xor(way, (todir > data.dir))) and -1 or 1 --Direction in which we will spin
158
		while data.dir ~= todir do
159
			data.dir = (data.dir + rotdir) % 4 --Enforce 0<=dir<=3
160
			dumpToFile() --Each turn, we have to dump to file, otherwise we might have a problem with sync of virtual state and real state of the turtle.
161
			turtle[rotdir > 0 and "turnRight" or "turnLeft"]()
162
		end
163
		sleep(ROTATION_DELAY)
164
	end
165
	function dump() --Dump all mined materials
166
		setStatus(TASKS.DUMPING)
167
		for i = data.reservedSlots + 2, 16 do --Dump all mined materials
168
			if turtle.getItemCount(i)~=0 then --DAMN, I NEED MY CONTINUE!!! Well, we don't want to waste time on empty slots...
169
				turtle.select(i)
170
				turtle.drop(turtle.getItemCount(i))
171
			end
172
		end
173
	end
174
	function refuelAndDump(x, z) --Refuel and dump
175
		setDir(DIRS.SOUTH)
176
		setStatus(TASKS.REFUELING)
177
		turtle.select(1)
178
		if not hasRequiredFuelToProcessShaft(x, z) and turtle.getItemCount(1)>1 then --Use coal that we've mined
179
			turtle.refuel(math.min(turtle.getItemCount(1)-1, math.ceil((getRequiredFuelToProcessShaft(x, z)-turtle.getFuelLevel()) / data.fuelPerItem)))
180
		end
181
		while not hasRequiredFuelToProcessShaft(x, z) do
182
			turtle.select(1)
183
			data.fuelItemsRequired = math.ceil((getRequiredFuelToProcessShaft(x, z) - turtle.getFuelLevel()) / data.fuelPerItem) --We require this much fuel items
184
			data.debug = getRequiredFuelToProcessShaft(x, z).." "..turtle.getFuelLevel()
185
			turtle.suckUp()
186
			local willConsume = math.min(turtle.getItemCount(1)-1, data.fuelItemsRequired)
187
			if willConsume > 0 and turtle.refuel(willConsume) then --Successfully consumed
188
				setStatus(TASKS.REFUELING)
189
				data.fuelItemsUsed = data.fuelItemsUsed + willConsume
190
			else --Could not consume
191
				setStatus(TASKS.WAITING_FOR_FUEL)
192
				sleep(5)
193
			end
194
		end
195
		data.fuelItemsRequired = 0
196
		if turtle.getItemCount(1)>1 then turtle.dropUp(turtle.getItemCount(1)-1) end --Drop off the fuel we didn't use
197
		dump()
198
	end
199
	local function tryEmptyChest(postfix)
200
		while (turtle.select(1) or true) and turtle["suck"..postfix]() do
201
			checkShaftStep()
202
		end
203
	end
204
	local function move(forward, postfix, add, remove, dir)
205
		local tryCount = 0
206
		while turtle["detect"..postfix]() do
207
			tryEmptyChest(postfix)
208
			if not turtle["dig"..postfix]() then tryCount = tryCount + 1 end
209
			if tryCount>TRY_LIMIT then return false end
210
			sleep(0.2)
211
		end
212
		while (add(dir) or true) and not turtle[forward]() do
213
			remove(dir)
214
			if not turtle["attack"..postfix]() then tryCount = tryCount + 1 end
215
			if tryCount>TRY_LIMIT then return false end
216
			sleep(0.2)
217
		end
218
		return true
219
	end
220
	function moveX(dir) --X+ = E, X- = W
221
		setDir(DIRS.WEST - (dir + 1)) --Direction arithmetic magic :D
222
		local add = function (dir) 
223
			data.coords.x = data.coords.x + dir
224
			dumpToFile()
225
			return true
226
		end
227
		local remove = function (dir) 
228
			data.coords.x = data.coords.x - dir
229
			dumpToFile()
230
			return true
231
		end
232
		if not move("forward", "", add, remove, dir) then return false end
233
		sleep(MOVEMENT_DELAY)
234
		return true
235
	end
236
	function moveY(dir) --Y+ = U, Y- = D
237
		local add = function (dir) 
238
			data.coords.y = data.coords.y + dir
239
			dumpToFile()
240
			return true
241
		end
242
		local remove = function (dir) 
243
			data.coords.y = data.coords.y - dir
244
			dumpToFile()
245
			return true
246
		end
247
		if not move(dir > 0 and "up" or "down", dir > 0 and "Up" or "Down", add, remove, dir) then return false end
248
		dumpToFile()
249
		sleep(MOVEMENT_DELAY)
250
		return true
251
	end
252
	function moveZ(dir) --Z+ = N, Z- = S
253
		setDir(DIRS.NORTH - (dir - 1)) --Direction arithmetic magic :D
254
		local add = function (dir) 
255
			data.coords.z = data.coords.z + dir
256
			dumpToFile()
257
			return true
258
		end
259
		local remove = function (dir) 
260
			data.coords.z = data.coords.z - dir
261
			dumpToFile()
262
			return true
263
		end
264
		if not move("forward", "", add, remove, dir) then return false end
265
		dumpToFile()
266
		sleep(MOVEMENT_DELAY)
267
		return true
268
	end
269
	function dock(x, z) --Go back to dock
270
		setStatus(TASKS.MOVING_TO_DOCK)
271
		moveVerticalTo(data.height)
272
		moveHorizontalTo(0, 0)
273
		refuelAndDump(x, z)
274
	end
275
	function moveHorizontalTo(x, z)
276
		while data.coords.x ~= x do while not moveX(x-data.coords.x>0 and 1 or -1) do sleep(0.2) end end
277
		while data.coords.z ~= z do while not moveZ(z-data.coords.z>0 and 1 or -1) do sleep(0.2) end end
278
	end
279
	function moveVerticalTo(y)
280
		while data.coords.y ~= y do while not moveY(y-data.coords.y>0 and 1 or -1) do end end
281
	end
282
	function processBlockInFront() --Determine if we are interested in the block in front. If we are, then mine it.
283
		local flag = true
284
		for i = 2, data.reservedSlots + 1 do
285
			turtle.select(i)
286
			flag = flag and not turtle.compare(i)
287
		end
288
		turtle.select(1)
289
		if flag then
290
			tryEmptyChest("")
291
			turtle.dig()
292
		end
293
	end
294
	function checkShaftStep()
295
		--The next if should never happen, but whatever, let it live, might come in useful later on.
296
		if not hasRequiredFuelToGoBack(data.coords.x, data.coords.y, data.coords.z) and turtle.getItemCount(1)>1 then --Use coal that we've mined to refuel to cut down on docking time
297
			setStatus(TASKS.REFUELING)
298
			turtle.select(1)
299
			local consumeItems = math.ceil((getRequiredFuelToGoBack(data.coords.x, data.coords.y, data.coords.z) - turtle.getFuelLevel()) / data.fuelPerItem)
300
			turtle.refuel(math.min(turtle.getItemCount(1)-1, consumeItems))
301
		end
302
		if not hasRequiredFuelAndSpace(data.coords.x, data.coords.y, data.coords.z) then --If we don't have enough coal to refuel or we don't have enough space, we need to dock and come back to the spot
303
			local backupDir = data.dir
304
			local backupX = data.coords.x
305
			local backupY = data.coords.y
306
			local backupZ = data.coords.z
307
			dock(data.coords.x, data.coords.z)
308
			setStatus(TASKS.MOVING_TO_SHAFT)
309
			moveHorizontalTo(backupX, backupZ)
310
			moveVerticalTo(backupY)
311
			setDir(backupDir)
312
		end
313
	end
314
	function processShaft(x, z)
315
		dock(x, z)
316
		setStatus(TASKS.MOVING_TO_SHAFT)
317
		moveHorizontalTo(x, z)
318
		data.currentShaftProgress = 0
319
		while data.coords.y > BEDROCK_LEVEL + 1 do
320
			--Digging the shaft
321
			setStatus(TASKS.SHAFT)
322
			checkShaftStep()
323
			turtle.select(1)
324
			if not moveY(-1) then return end --We hit bedrock, nothing to do here...
325
			for i = 0, 3 do
326
				checkShaftStep()
327
				turtle.select(1)
328
				processBlockInFront()
329
				setDir((data.dir + (i~=3 and 1 or 0)) % 4)
330
			end
331
			data.currentShaftProgress = data.currentShaftProgress + 1
332
		end
333
		data.shaftsDone = data.shaftsDone + 1 
334
	end
335
	function excavate()
336
		if not data.shaftsGenerated then
337
			for x = 0, data.lenx - 1 do
338
				for z = 0, data.lenz - 1 do
339
					if (z-(x*2))%5==0 then table.insert(data.shafts, {x = x, z = z + 1}) end
340
				end
341
			end
342
			data.shaftsToDo = #data.shafts
343
			data.shaftsGenerated = true
344
		end
345
		while #data.shafts > 0 do
346
			local shaft = data.shafts[1]
347
			processShaft(shaft.x, shaft.z)
348
			table.remove(data.shafts, 1)
349
		end
350
		moveVerticalTo(data.height)
351
		moveHorizontalTo(0, 0)
352
		dump()
353
		setDir(DIRS.NORTH)
354
		setStatus(TASKS.FINISHED)
355
		fs.delete(PERSISTANCE_FILE_PATH)
356
	end
357
end
358
--[[
359
	Check if the startup script is right
360
]]
361
function getStartupScriptStatus()
362
	if not fs.exists("startup") then return STARTUP_SCRIPT_INSTALL_STATUS.NOT_INSTALLED end
363
	local file = io.open("startup", "r")
364
	if not file then return STARTUP_SCRIPT_INSTALL_STATUS.NOT_INSTALLED end
365
	local str = file:read("*a")
366
	file:close()
367
	return str == string.format(STARTUP_SCRIPT_STRING, shell.getRunningProgram()) and STARTUP_SCRIPT_INSTALL_STATUS.INSTALLED or STARTUP_SCRIPT_INSTALL_STATUS.DIFFERENT
368
end
369
370
function installStartupScript()
371
	fs.delete("startup")
372
	local file = io.open("startup", "w")
373
	file:write(string.format(STARTUP_SCRIPT_STRING, shell.getRunningProgram()))
374
	file:close()
375
end
376
377
--[[
378
	GUI
379
]]
380
381
function splitIntoLines(str)
382
	local w, h = term.getSize()
383
	local lines = {}
384
	for line in str:gmatch("[^\r\n]+") do	
385
		local currentLine = ""
386
		for token in line:gmatch("[^%s]+") do
387
			if #(currentLine .. token) > w-3 then
388
				table.insert(lines, currentLine)
389
				currentLine = token
390
			else
391
				currentLine = (currentLine~="" and currentLine .. " " or "") .. token
392
			end
393
		end
394
		if currentLine~="" then table.insert(lines, currentLine) end
395
	end
396
	return lines
397
end
398
399
function showProgress(finished) --Progress
400
	local progressBarSpinChars = {"/", "-", "\\", "|"}
401
	local curChar = 0
402
	local cur = 1
403
	local w, h = term.getSize()
404
	local exit = false
405
	local running = true
406
	local function cycleProgressBar()
407
		curChar = (curChar + 1) % 4 --Cycle through the progress bar chars for an animation effect
408
	end
409
410
	local function clear()
411
		term.clear()
412
		cur = 0
413
	end
414
415
	local function allocateLine()
416
		cur = cur + 1
417
	end
418
419
	local function renderProgressBar(fraction)
420
		allocateLine()
421
		term.setCursorPos(1, cur)
422
		local numOfDone = math.floor((w-3)*fraction)
423
		local numOfLeft = math.ceil((w-3)*(1-fraction))
424
		term.write("[")
425
		if numOfDone>0 then term.write(string.rep("=", numOfDone)) end
426
		term.write(fraction == 1 and "=" or progressBarSpinChars[curChar + 1])
427
		if numOfLeft>0 then term.write(string.rep(" ", numOfLeft)) end
428
		term.write("]")
429
	end
430
431
	local function writeLine(desc, value)
432
		if type(value) ~= "string" then value = tostring(value) end
433
		allocateLine()
434
		term.setCursorPos(1, cur)
435
		term.write(desc .. (value~="" and ":" or ""))
436
		term.setCursorPos(w - #value + 1, cur)
437
		term.write(value)
438
	end
439
440
	local function normalProgressRenderer()
441
		writeLine("Current task", data.currentlyDoing)
442
		writeLine("Shafts done", data.shaftsDone)
443
		writeLine("Total shafts", data.shaftsToDo)
444
		local localProgress = data.currentShaftProgress / (data.height - BEDROCK_LEVEL - 1)
445
		if localProgress==0/0 then localProgress = 0 end
446
		writeLine("Current shaft progress", math.floor(localProgress*100).."%")
447
		renderProgressBar(localProgress)
448
		local totalProgress = (data.shaftsDone + localProgress % 1)/data.shaftsToDo
449
		if totalProgress==0/0 then totalProgress = 0 end
450
		writeLine("Whole progress", math.floor(totalProgress*100).."%")
451
		renderProgressBar(totalProgress)
452
		writeLine("Coordinates", data.coords.x..", "..data.coords.y..", "..data.coords.z)
453
		writeLine("Fuel used so far", data.fuelItemsUsed)
454
		if data.currentlyDoing == TASKS.WAITING_FOR_FUEL then writeLine("Fuel items needed", data.fuelItemsRequired)
455
		else writeLine("Sufficient fuel for now.", "") cycleProgressBar() end
456
		term.setCursorPos(1, h) term.write("Press Enter to exit...")
457
	end
458
459
	local function finishedProgressRenderer()
460
		writeLine("Finished.", "")
461
		writeLine("Shafts done", data.shaftsDone)
462
		writeLine("Fuel used", data.fuelItemsUsed)
463
		term.setCursorPos(1, 4)
464
	end
465
466
	local function renderProgress()
467
		clear()
468
		if finished then
469
			finishedProgressRenderer()
470
		else
471
			normalProgressRenderer()
472
		end
473
	end
474
475
	local function displayProgress()
476
		while data.currentlyDoing~=TASKS.FINISHED and running do
477
			--Update information
478
			renderProgress(false)		
479
			sleep(0.1)
480
		end
481
		running = false
482
	end
483
484
	local function waitForKey()
485
		while running do
486
			local sEvent, param = os.pullEvent("key")
487
			if sEvent == "key" then
488
			    if param == 28 then
489
				exit = true
490
				running = false
491
				dumpToFile()
492
			    end
493
			end
494
		end
495
	end
496
	if finished then renderProgress() else parallel.waitForAny(function() parallel.waitForAll(displayProgress, waitForKey) end, excavate, periodicSave) cleanup() end
497
	return exit
498
end
499
function showConfig() --Config
500
	local currentlySelected = 1
501
	local running = true
502
	local exit = false
503
	local configOptions = setmetatable({
504
		{key = "Width", keyBlank = "Width (required!)", value = "8", varType = "number", transferName = "lenx"},
505
		{key = "Length", keyBlank = "Length (required!)", value = "8", varType = "number", transferName = "lenz"},
506
		{key = "Height", keyBlank = "Height (required!)", value = "8", varType = "number", transferName = "height"},
507
		{key = "Number of excluded blocks", keyBlank = "Number of excluded blocks (required!)", value = "2", varType = "number", transferName = "reservedSlots"},
508
		{key = "Fuel units per item", keyBlank = "Fuel units per item (required!)", value = "80", varType = "number", transferName = "fuelPerItem"}--[[, TODO
509
		{key = "Save config to", keyBlank = "Save config to (optional)", value = "", varType = "string", transferName = nil}	]]
510
	},
511
	{
512
		__concat = function(t, s)
513
			t[currentlySelected].value = t[currentlySelected].value .. (t[currentlySelected].varType=="number" and (tonumber(s)~=nil and s or "") or s)
514
		end,
515
		__sub = function(t, s)
516
			t[currentlySelected].value = t[currentlySelected].value:sub(1, #t[currentlySelected].value - 1)
517
		end,
518
		__index = function(t, key)
519
			if tonumber(key)~=nil then
520
				return t[key]
521
			else
522
				for i = 1, #t do
523
					if t[i].transferName == key then return t[i] end
524
				end
525
			end
526
			return nil
527
		end
528
	}
529
	)
530
	
531
	local function renderConfig()
532
		term.clear()
533
		local w, h = term.getSize()
534
		for i = 1, #configOptions do
535
			term.setCursorPos(1, i)
536
			term.write(#configOptions[i].value>0 and configOptions[i].key or configOptions[i].keyBlank)
537
			term.setCursorPos(w-1-#configOptions[i].value, i)
538
			term.write(i==currentlySelected and "[" or " ")
539
			term.write(configOptions[i].value)
540
			term.write(i==currentlySelected and "]" or " ")
541
		end
542
		term.setCursorPos(1, h-1)
543
		term.write((currentlySelected == (#configOptions + 1)) and "[Next]" or " Next ")
544
		term.setCursorPos(w-5, h-1)
545
		term.write((currentlySelected == (#configOptions + 2)) and "[Exit]" or " Exit ")
546
		term.setCursorPos(w-2, currentlySelected)
547
	end
548
549
	local function showConfig()
550
		while running do renderConfig() sleep(0.2) end
551
	end
552
553
	local function transferValues()
554
		for i = 1, #configOptions do if configOptions[i].transferName ~= nil then
555
			data[configOptions[i].transferName] = (configOptions[i].varType=="number" and tonumber or function(a) return a end)(configOptions[i].value)
556
		end end
557
		data.coords = {x = 0, y = data.height, z = 0} --We start at the dock.
558
	end
559
	local function handleInputForConfig()
560
		while running do
561
			local event, param = os.pullEvent()
562
			if event == "key" then
563
				if param == 200 then
564
					currentlySelected = math.max(1, currentlySelected - 1)
565
					renderConfig()
566
				elseif param == 208 then
567
					currentlySelected = math.min(#configOptions + 2, currentlySelected + 1)
568
					renderConfig()
569
				elseif param == 14 then
570
					local t = configOptions - nil
571
					renderConfig()
572
				elseif param == 28 then
573
					if currentlySelected == #configOptions + 2 then
574
						exit = true
575
						running = false
576
					elseif currentlySelected == #configOptions + 1 then
577
						transferValues()
578
						running = false
579
						term.clear()
580
					end
581
				end
582
			elseif event == "char" then
583
				local t = configOptions .. param
584
				renderConfig()
585
			end
586
		end
587
	end
588
	parallel.waitForAll(handleInputForConfig, showConfig)
589
	cleanup()
590
	return exit
591
end
592
function showDialog(dialogStr, buttons, centre) --Load from old config or not
593
	local currentlySelected = 1
594
	local running = true
595
	local result = false
596
	--local dialogStr = "Persistance file from previous run found. Would you like to continue from where you left off?"
597
	local lines = {}
598
	local w, h = term.getSize()
599
	for line in dialogStr:gmatch("[^\r\n]+") do	
600
		local currentLine = ""
601
		for token in line:gmatch("[^%s]+") do
602
			if #(currentLine .. token) > w-3 then
603
				table.insert(lines, currentLine)
604
				currentLine = token
605
			else
606
				currentLine = (currentLine~="" and currentLine .. " " or "") .. token
607
			end
608
		end
609
		if currentLine~="" then table.insert(lines, currentLine) end
610
	end
611
	local function renderDialog()
612
		term.clear()		
613
		for i = 1, #lines do		
614
			term.setCursorPos(centre and ((w - #lines[i]) / 2 + 1) or 1, i + 1)
615
			term.write(lines[i])
616
		end
617
		for i = 1, #buttons do
618
			term.setCursorPos((w / (#buttons + 1)) * i - #buttons[i]/2, h - 1)
619
			term.write((currentlySelected == i) and ("[" .. buttons[i] .. "]") or (" " .. buttons[i] .. " "))
620
		end
621
	end
622
623
	local function showDialog()
624
		while running do renderDialog() sleep(0.2) end
625
	end
626
627
	local function handleInputForDialog()
628
		while running do
629
			local event, param = os.pullEvent()
630
			if event == "key" then
631
				if param == 200 then
632
					currentlySelected = math.max(1, currentlySelected - 1)
633
					renderDialog()
634
				elseif param == 208 then
635
					currentlySelected = math.min(#buttons, currentlySelected + 1)
636
					renderDialog()
637
				elseif param == 28 then
638
					running = false
639
				end
640
			end
641
		end
642
	end
643
	parallel.waitForAll(handleInputForDialog, showDialog)
644
	cleanup()
645
	return currentlySelected
646
end
647
648
function showResumeWarning()
649
	
650
	local running = true
651
	local exit = false
652
	local function displayWarning()
653
		for i = 10, 0, -1 do
654
			term.clear()
655
			local lines = splitIntoLines(string.format(
656
[[The turtle will continue to dig shafts in %i seconds.
657
Press Enter to exit to shell.]], i))
658
			for i = 1, #lines do
659
				term.setCursorPos(1, i)
660
				term.write(lines[i])
661
			end
662
			sleep(1)
663
			if not running then return end
664
		end
665
		running = false
666
	end
667
	local function waitForKey()
668
		while running do
669
			local sEvent, param = os.pullEvent("key")
670
			if sEvent == "key" then
671
			    if param == 28 then
672
				exit = true
673
				running = false
674
				dumpToFile()
675
			    end
676
			end
677
		end
678
	end
679
	parallel.waitForAny(waitForKey, displayWarning)
680
	return exit
681
end
682
--[[
683
	Entry
684
]]
685
args={...}
686
687
if args[1] == "resume" then
688
	if fs.exists(PERSISTANCE_FILE_PATH) then
689
		readFromFile()
690
		--[[print("The turtle will automatically resume in 10 seconds.")
691
		print("Press Enter to abort.")
692
		parallel.waitForAny(function() sleep(10) running = false end,
693
		function()
694
			while running do
695
				local sEvent, param = os.pullEvent("key")
696
				if sEvent == "key" then
697
				    if param == 28 then
698
					exit = true
699
					running = false
700
				    end
701
				end
702
			end
703
		end)]]
704
		if showResumeWarning() then
705
			cleanup()
706
			return
707
		end
708
		if showProgress(false) then
709
			cleanup()
710
			return
711
		end
712
		showProgress(true)
713
	end
714
	cleanup()
715
	return
716
end
717
local startupStatus = getStartupScriptStatus()
718
if startupStatus ~= STARTUP_SCRIPT_INSTALL_STATUS.INSTALLED then
719
	local variations =  {"not installed", "different from what this program suggests/needs"}
720
	local dialogString = string.format(
721
[[The startup script is %s.
722
This means that the turtle will not automatically resume when it boots up (e.g. chunk loads).
723
Would you like to install the recommended startup script?]], variations[startupStatus])
724
	local startupDialogResult = showDialog(dialogString, {"Yes", "No"}, true)
725
	if startupDialogResult == 1 then
726
		installStartupScript()
727
	end
728
end
729
local loadFromFile = false
730
if fs.exists(PERSISTANCE_FILE_PATH) then
731
	loadFromFile = showDialog("Persistance file from previous run found. Would you like to continue from where you left off?", {"Yes", "No"}, true) == 1
732
end
733
if loadFromFile then 
734
	readFromFile()
735
	local dirNames = {"north", "east", "south", "west"}
736
	local dialogString = string.format(
737
[[Persistance file loaded.
738
The turtle thinks it is located at:
739
Y=%i; relative X,Z (to dock)=%i,%i; facing %s
740
Options are:
741
1. The turtle is facing and is located as stated above.
742
2. The turtle is located at the dock, facing away from the output chest.
743
744
]],
745
	data.coords.y, data.coords.x, data.coords.z, dirNames[data.dir + 1])
746
	local posDialogResult = showDialog(dialogString, {"1", "2", "Exit"}, false)
747
	if posDialogResult == 2 then
748
		data.coords = {x = 0, y = data.height, z = 0}
749
		data.dir = DIRS.NORTH
750
	elseif posDialogResult == 3 then
751
		cleanup()
752
		return
753
	end
754
else
755
	if showConfig() then
756
		cleanup()
757
		return
758
	end
759
end
760
local warningStr = string.format("Before continuing, please make sure that the first slot is occupied by the fuel item, and the next %i slots are occupied by the blocks that shouldn't be mined.", data.reservedSlots)
761
if showDialog(warningStr, {"Continue", "Exit"}, true) == 2 then
762
	cleanup()
763
	return
764
end
765
if showProgress(false) then
766
	cleanup()
767
	return
768
end
769
showProgress(true)