View difference between Paste ID: 6zR81b0t and u4S5CQqY
SHOW: | | - or go back to the newest paste.
1
-- Variable Setup
2
-- Command Line input Table
3
local argTable = {...}
4
5
-- Flag Variables: These are conditions for different features (all flags are named foo_bar, all other variables are named fooBar)
6
local cmd_line = false
7
local cmd_line_resume = false
8
local cmd_line_cost_only = false
9
local chain_next_shape = false -- This tells goHome() where to end, if true it goes to (0, 0, positionZ) if false it goes to (-1, -1, 0)
10
local special_chain = false -- For certain shapes that finish where the next chained shape should start, goHome() will  only turn to face 0 if true
11
local cost_only = false
12
local sim_mode = false
13
local resupply = false
14
local enderchest_refilling = false
15
local can_use_gps = false
16
local return_to_home = false -- whether the turtle shall return to start after build
17
18
-- Record Keeping Variables: These are for recoding the blocks and fuel used
19
local blocks = 0
20
local fuel = 0
21
22
-- Position Tracking Variables: These are for keeping track of the turtle's position
23
local positionX = 0
24
local positionY = 0
25
local positionZ = 0
26
local facing = 0
27
local gpsPositionX = 0
28
local gpsPositionY = 0
29
local gpsPositionZ = 0
30
local gpsFacing = 0
31
32
-- General Variables: Other variables that don't fit in the other categories
33
local choice = ""
34
35
-- Progress Table: These variables are the tables that the turtle's progress is tracked in
36
local tempProgTable = {}
37
local progTable = {} --This is the LOCAL table!  used for local stuff only, and is ONLY EVER WRITTEN when sim_mode is FALSE
38
local progFileName = "ShapesProgressFile"
39
40
-- Utility functions
41
42
function writeOut(...) -- ... lets writeOut() pass any arguments to print(). so writeOut(1,2,3) is the same as print(1,2,3). previously writeOut(1,2,3) would have been the same as print(1)
43
	for i, v in ipairs(arg) do
44
		print(v)
45
	end
46
end
47
48
function getInput(inputType, message, option1, option2)
49
	local input = ""
50
	if inputType == "string" then
51
		writeOut(message.. "(" ..option1 .. " or "..option2..")" )
52
		while true do
53
			input = io.read()
54
			input = string.lower(input)
55
			if input ~= option1 and input ~= option2 then
56
				writeOut("You didn't enter a valid option. Please try again.")
57
			else
58
				return input
59
			end
60
		end
61
	end
62
	if inputType == "int" then
63
		writeOut(message)
64
		while true do
65
			input = io.read()
66
			if tonumber(input) ~= nil then
67
				return tonumber(input)
68
			else
69
				writeOut("Need a number. Please try again")
70
			end
71
		end
72
	end	
73
end
74
75
function wrapModules() -- checks for and wraps turtle modules
76
	local test = 0
77
	if peripheral.getType("left" )== "resupply" then 
78
		resupplymodule=peripheral.wrap("left")
79
		resupply = true
80
	elseif peripheral.getType("right") == "resupply" then
81
		resupplymodule=peripheral.wrap("right")
82
		resupply = true
83
	end
84
	if peripheral.getType("left") == "modem" then
85
		modem=peripheral.wrap("left")
86
		test, _, _ = gps.locate(1)
87
		if test ~= nil then
88
			can_use_gps = true
89
		end
90
	elseif peripheral.getType("right") == "modem" then
91
		modem=peripheral.wrap("right")
92
		test, _, _ = gps.locate(1)
93
		if test ~= nil then
94
			can_use_gps = true
95
		end
96
	end
97
	if resupply then
98
		return "resupply"
99
	end
100
end
101
102
function linkToRSStation() -- Links to resupply station
103
	if resupplymodule.link() then
104
		return true
105
	else
106
		writeOut("Please put Resupply Station to the left of the turtle and press Enter to continue")
107
		io.read()
108
		linkToRSStation()
109
	end
110
end
111
112
function compareResources()
113
	if (turtle.compareTo(1) == false) then
114
		turtle.drop()
115
	end
116
end
117
118
function firstFullSlot()
119
	for i = 1, 16 do
120
		if (turtle.getItemCount(i) > 1) then
121
			return i
122
		end
123
	end
124
end
125
126
function turtleEmpty()
127
	for i = 1, 16 do
128
		if (turtle.getItemCount(i) > 1) then
129
			return false
130
		end
131
	end
132
	return true
133
end
134
135
function checkResources()
136
	if resupply then
137
		if turtle.getItemCount(activeSlot) <= 1 then
138
			while not(resupplymodule.resupply(1)) do
139
				os.sleep(0.5)
140
			end
141
		end
142
	elseif enderchest_refilling then
143
		compareResources()
144
		while (turtle.getItemCount(activeSlot) <= 1) do
145
			if (activeSlot == 15) and (turtle.getItemCount(activeSlot)<=1) then
146
				turtle.select(16)
147
				turtle.digUp()
148
				for i = 1, 15 do
149
					turtle.select(i)
150
					turtle.drop()
151
				end
152
				turtle.select(16)
153
				turtle.placeUp()
154
				turtle.select(1)				
155
				for i = 1, 15 do
156
					turtle.suckUp()
157
				end
158
				turtle.select(16)
159
				turtle.digUp()
160
				activeSlot = 1
161
				turtle.select(activeSlot)
162
			else
163
				activeSlot = activeSlot + 1
164
				-- writeOut("Turtle slot empty, trying slot "..activeSlot)
165
				turtle.select(activeSlot)
166
			end
167
			compareResources()
168
			os.sleep(0.2)
169
		end
170
	else
171
		compareResources()
172
		while (turtle.getItemCount(activeSlot) <= 1) do 
173
			if turtleEmpty() then
174
				writeOut("Turtle is empty, please put building block in slots and press enter to continue")
175
				io.read()
176
				activeSlot = 1
177
				turtle.select(activeSlot)
178
			else
179
				activeSlot = firstFullSlot()
180
				turtle.select(activeSlot)
181
			end
182
			compareResources()
183
		end
184
	end
185
end
186
187
function checkFuel()
188
	if (not(tonumber(turtle.getFuelLevel()) == nil)) then
189
		while turtle.getFuelLevel() < 50 do
190
			writeOut("Turtle almost out of fuel, pausing. Please drop fuel in inventory. And press enter.")
191
			io.read()
192
			turtle.refuel()
193
		end
194
	end
195
end
196
197
function placeBlock()
198
	blocks = blocks + 1
199
	simulationCheck()
200
	if cost_only then
201
		return
202
	end
203
	if turtle.detectDown() and not turtle.compareDown() then
204
		turtle.digDown()
205
	end
206
	checkResources()
207
	turtle.placeDown()
208
	progressUpdate()
209
end
210
211
function round(toBeRounded, decimalPlace) -- Needed for hexagon and octagon
212
	local multiplier = 10^(decimalPlace or 0)
213
	return math.floor(toBeRounded * multiplier + 0.5) / multiplier
214
end
215
216
-- Navigation functions
217
-- Allow the turtle to move while tracking its position
218
-- This allows us to just give a destination point and have it go there
219
220
function turnRightTrack()
221
	simulationCheck()
222
	facing = facing + 1
223
	if facing >= 4 then
224
		facing = 0
225
	end
226
	progressUpdate()
227
	if cost_only then
228
		return
229
	end
230
	turtle.turnRight()
231
end
232
233
function turnLeftTrack()
234
	simulationCheck()
235
	facing = facing - 1
236
	if facing < 0 then
237
		facing = 3
238
	end
239
	progressUpdate()
240
	if cost_only then
241
		return
242
	end
243
	turtle.turnLeft()
244
end
245
246
function turnAroundTrack()
247
	turnLeftTrack()
248
	turnLeftTrack()
249
end
250
251
function turnToFace(direction)
252
	if (direction < 0) then
253
		return false
254
	end
255
	direction = direction % 4
256
	while facing ~= direction do
257
		turnRightTrack()
258
	end
259
	return true
260
end
261
262
function safeForward()
263
	simulationCheck()
264
	if facing == 0 then
265
		positionY = positionY + 1
266
	elseif facing == 1 then
267
		positionX = positionX + 1
268
	elseif facing == 2 then
269
		positionY = positionY - 1
270
	elseif facing == 3 then
271
		positionX = positionX - 1
272
	end
273
	fuel = fuel + 1
274
	progressUpdate()
275
	if cost_only then
276
		return
277
	end
278
	checkFuel()
279
	local success = false
280
	local tries = 0
281
	while not success do
282
		success = turtle.forward()
283
		if not success then
284
			while (not success) and tries < 6 do
285
				tries = tries + 1
286
				turtle.dig() 
287
				success = turtle.forward()
288
				sleep(0.3)
289
			end
290
			if not success then
291
				writeOut("Blocked attempting to move forward.")
292
				writeOut("Please clear and press enter to continue.")
293
				io.read()
294
			end
295
		end
296
	end
297
end
298
299
function safeBack()
300
	simulationCheck()
301
	if facing == 0 then
302
		positionY = positionY - 1
303
	elseif facing == 1 then
304
		positionX = positionX - 1
305
	elseif facing == 2 then
306
		positionY = positionY + 1
307
	elseif facing == 3 then
308
		positionX = positionX + 1
309
	end
310
	fuel = fuel + 1
311
	progressUpdate()
312
	if cost_only then
313
		return
314
	end
315
	checkFuel()
316
	local success = false
317
	local tries = 0
318
	while not success do
319
		success = turtle.back()
320
		if not success then
321
			turnAroundTrack()
322
			while turtle.detect() and tries < 6 do
323
				tries = tries + 1
324
				if turtle.dig() then
325
					break
326
				end
327
				sleep(0.3)
328
			end
329
			turnAroundTrack()
330
			success = turtle.back()
331
			if not success then
332
				writeOut("Blocked attempting to move back.")
333
				writeOut("Please clear and press enter to continue.")
334
				io.read()
335
			end
336
		end
337
	end
338
end
339
340
function safeUp()
341
	simulationCheck()
342
	positionZ = positionZ + 1
343
	fuel = fuel + 1	
344
	progressUpdate()
345
	if cost_only then
346
		return
347
	end
348
	checkFuel()
349
	local success = false
350
	while not success do
351
		success = turtle.up()
352
		if not success then
353
			while turtle.detectUp() do
354
				if not turtle.digUp() then
355
					writeOut("Blocked attempting to move up.")
356
					writeOut("Please clear and press enter to continue.")
357
					io.read()
358
				end
359
			end
360
		end
361
	end
362
end
363
364
function safeDown()
365
	simulationCheck()
366
	positionZ = positionZ - 1
367
	fuel = fuel + 1
368
	progressUpdate()
369
	if cost_only then
370
		return
371
	end
372
	checkFuel()
373
	local success = false
374
	while not success do
375
		success = turtle.down()
376
		if not success then
377
			while turtle.detectDown() do
378
				if not turtle.digDown() then
379
					writeOut("Blocked attempting to move down.")
380
					writeOut("Please clear and press enter to continue.")
381
					io.read()
382
				end
383
			end
384
		end
385
	end
386
end
387
388
function moveY(targetY)
389
	if targetY == positionY then
390
		return
391
	end
392
	if (facing ~= 0 and facing ~= 2) then -- Check axis
393
		turnRightTrack()
394
	end
395
	while targetY > positionY do
396
		if facing == 0 then
397
			safeForward()
398
		else
399
			safeBack()
400
		end
401
	end
402
	while targetY < positionY do
403
		if facing == 2 then
404
			safeForward()
405
		else
406
			safeBack()
407
		end
408
	end
409
end
410
411
function moveX(targetX)
412
	if targetX == positionX then
413
		return
414
	end
415
	if (facing ~= 1 and facing ~= 3) then -- Check axis
416
		turnRightTrack()
417
	end
418
	while targetX > positionX do
419
		if facing == 1 then
420
			safeForward()
421
		else
422
			safeBack()
423
		end
424
	end
425
	while targetX < positionX do
426
		if facing == 3 then
427
			safeForward()
428
		else
429
			safeBack()
430
		end
431
	end
432
end
433
434
function moveZ(targetZ)
435
	if targetZ == positionZ then
436
		return
437
	end
438
	while targetZ < positionZ do
439
		safeDown()
440
	end
441
	while targetZ > positionZ do
442
		safeUp()
443
	end
444
end
445
446
-- I *HIGHLY* suggest formatting all shape subroutines to use the format that dome() uses;  specifically, navigateTo(x,y,[z]) then placeBlock().  This should ensure proper "data recording" and also makes readability better
447
function navigateTo(targetX, targetY, targetZ, move_z_first)
448
	targetZ = targetZ or positionZ -- If targetZ isn't used in the function call, it defaults to its current z position, this should make it compatible with all previous implementations of navigateTo()
449
	move_z_first = move_z_first or false -- Defaults to moving z last, if true is passed as 4th argument, it moves vertically first
450
	
451
	if move_z_first then
452
		moveZ(targetZ)
453
	end
454
	
455
	if facing == 0 or facing == 2 then -- Y axis
456
		moveY(targetY)
457
		moveX(targetX)
458
	else
459
		moveX(targetX)
460
		moveY(targetY)
461
	end
462
	
463
	if not move_z_first then
464
		moveZ(targetZ)
465
	end
466
end
467
468
function goHome()
469
	if chain_next_shape then
470
		if not special_chain then
471
			navigateTo(0, 0) -- So another program can chain multiple shapes together to create bigger structures
472
		end
473
	else
474
		navigateTo(-1, -1, 0) -- So the user can collect the turtle when it is done, not 0,0,0 because some shapes use the 0,0 column
475
	end
476
	turnToFace(0)
477
end
478
479
-- Shape Building functions
480
481
function drawLine(endX, endY, startX, startY)
482
	startX = startX or positionX
483
	startY = startY or positionY
484
	deltaX = math.abs(endX - startX)
485
	deltaY = math.abs(endY - startY)
486
	errorVar = 0
487
	if deltaX >= deltaY then
488
		deltaErr = math.abs(deltaY/deltaX)
489
		if startX < endX then
490
			if startY < endY then
491
				counterY = startY
492
				for counterX = startX, endX do
493
					navigateTo(counterX, counterY)
494
					placeBlock()
495
					errorVar = errorVar + deltaErr
496
					if errorVar >= 0.5 then
497
						counterY = counterY + 1
498
						errorVar = errorVar - 1
499
					end
500
				end
501
			else
502
				counterY = startY
503
				for counterX = startX, endX do
504
					navigateTo(counterX, counterY)
505
					placeBlock()
506
					errorVar = errorVar + deltaErr
507
					if errorVar >= 0.5 then
508
						counterY = counterY - 1
509
						errorVar = errorVar - 1
510
					end
511
				end
512
			end
513
		else
514
			if startY < endY then
515
				counterY = startY
516
				for counterX = startX, endX, -1 do
517
					navigateTo(counterX, counterY)
518
					placeBlock()
519
					errorVar = errorVar + deltaErr
520
					if errorVar >= 0.5 then
521
						counterY = counterY + 1
522
						errorVar = errorVar - 1
523
					end
524
				end
525
			else
526
				counterY = startY
527
				for counterX = startX, endX, -1 do
528
					navigateTo(counterX, counterY)
529
					placeBlock()
530
					errorVar = errorVar + deltaErr
531
					if errorVar >= 0.5 then
532
						counterY = counterY - 1
533
						errorVar = errorVar - 1
534
					end
535
				end
536
			end
537
		end
538
	else
539
		deltaErr = math.abs(deltaX/deltaY)
540
		if startY < endY then
541
			if startX < endX then
542
				counterX = startX
543
				for counterY = startY, endY do
544
					navigateTo(counterX, counterY)
545
					placeBlock()
546
					errorVar = errorVar + deltaErr
547
					if errorVar >= 0.5 then
548
						counterX = counterX + 1
549
						errorVar = errorVar - 1
550
					end
551
				end
552
			else
553
				counterX = startX
554
				for counterY = startY, endY do
555
					navigateTo(counterX, counterY)
556
					placeBlock()
557
					errorVar = errorVar + deltaErr
558
					if errorVar >= 0.5 then
559
						counterX = counterX - 1
560
						errorVar = errorVar - 1
561
					end
562
				end
563
			end
564
		else
565
			if startX < endX then
566
				counterX = startX
567
				for counterY = startY, endY, -1 do
568
					navigateTo(counterX, counterY)
569
					placeBlock()
570
					errorVar = errorVar + deltaErr
571
					if errorVar >= 0.5 then
572
						counterX = counterX + 1
573
						errorVar = errorVar - 1
574
					end
575
				end
576
			else
577
				counterX = startX
578
				for counterY = startY, endY, -1 do
579
					navigateTo(counterX, counterY)
580
					placeBlock()
581
					errorVar = errorVar + deltaErr
582
					if errorVar >= 0.5 then
583
						counterX = counterX - 1
584
						errorVar = errorVar - 1
585
					end
586
				end
587
			end
588
		end
589
	end
590
end
591
592
function rectangle(width, depth, startX, startY)
593
	startX = startX or positionX
594
	startY = startY or positionY
595
	endX = startX + width - 1
596
	endY = startY + depth - 1
597
	drawLine(startX, endY, startX, startY)
598
	drawLine(endX, endY, startX, endY)
599
	drawLine(endX, startY, endX, endY)
600
	drawLine(startX, startY, endX, startY)
601
end
602
603
function square(length, startX, startY)
604
	startX = startX or positionX
605
	startY = startY or positionY
606
	rectangle(length, length, startX, startY)
607
end
608
609
function wall(depth, height)
610
	for i = 1, depth do
611
		for j = 1, height do
612
			placeBlock()
613
			if j < height then
614
				navigateTo(positionX, positionY, positionZ + 1)
615
			end
616
		end
617
		if (i ~= depth) then
618
			navigateTo(positionX, positionY + 1, 0)
619
		end
620
	end
621
end
622
623
function platform(width, depth, startX, startY)
624
	startX = startX or positionX
625
	startY = startY or positionY
626
	endX = startX + width - 1
627
	endY = startY + depth - 1
628
	forward = true
629
	for counterY = startY, endY do
630
		if forward then
631
			for counterX = startX, endX do
632
				navigateTo(counterX, counterY)
633
				placeBlock()
634
			end
635
		else
636
			for counterX = endX, startX, -1 do
637
				navigateTo(counterX, counterY)
638
				placeBlock()
639
			end
640
		end
641
		forward = not forward
642
	end
643
end
644
645
function cuboid(width, depth, height, hollow)
646-
	for i = 0, height - 1 do
646+
	platform(width, depth, 0, 0)
647
	for i = 1, height - 1 do
648
		navigateTo(0, 0, i)
649
		if (hollow == "n") then
650
			platform(width, depth, 0, 0)
651-
			rectangle(width, depth, 0, 0)
651+
652
		    rectangle(width, depth, 0, 0)
653
		end
654
	end
655
	navigateTo(0,0,height)
656
	platform(width, depth, 0, 0)
657
end
658
659
function pyramid(length, hollow)
660
	-- local height = math.ceil(length / 2) - 1
661
	i = 0
662
	while (length > 0) do
663
		navigateTo(i, i, i)
664
		if (hollow == "y") then
665
			rectangle(length, length, i, i)
666
		else
667
			platform(length, length, i, i)
668
		end
669
		i = i + 1
670
		length = length - 2
671
	end
672
end
673
674
function stair(width, height, startX, startY) -- Last two might be able to be used to make a basic home-like shape later?
675
	startX = startX or positionX
676
	startY = startY or positionY
677
	endX = startX + width - 1
678
	endY = startY + height - 1
679
	forward = true
680
	for counterY = startY, endY do
681
		if forward then
682
			for counterX = startX, endX do
683
				navigateTo(counterX, counterY)
684
				placeBlock()
685
			end
686
		else
687
			for counterX = endX, startX, -1 do
688
				navigateTo(counterX, counterY)
689
				placeBlock()
690
			end
691
		end
692
		if counterY ~= endY then
693
			navigateTo(positionX, positionY, positionZ + 1)
694
			forward = not forward
695
		end
696
	end
697
end
698
699
function circle(diameter)
700
	odd = not (math.fmod(diameter, 2) == 0)
701
	radius = diameter / 2;
702
	if odd then
703
		width = (2 * math.ceil(radius)) + 1;
704
		offset = math.floor(width/2);
705
	else
706
		width = (2 * math.ceil(radius)) + 2;
707
		offset = math.floor(width/2) - 0.5;		
708
	end
709
	--diameter --radius * 2 + 1
710
	sqrt3 = 3 ^ 0.5
711
	boundaryRadius = radius + 1.0
712
	boundary2 = boundaryRadius ^ 2
713
	radius2 = radius ^ 2
714
	z = math.floor(radius)
715
	cz2 = (radius - z) ^ 2
716
	limitOffsetY = (boundary2 - cz2) ^ 0.5
717
	maxOffsetY = math.ceil(limitOffsetY)
718
	-- We do first the +x side, then the -x side to make movement efficient
719
	for side = 0,1 do
720
			-- On the right we go from small y to large y, on the left reversed
721
			-- This makes us travel clockwise (from below) around each layer
722
			if (side == 0) then
723
				yStart = math.floor(radius) - maxOffsetY
724
				yEnd = math.floor(radius) + maxOffsetY
725
				yStep = 1
726
			else
727
				yStart = math.floor(radius) + maxOffsetY
728
				yEnd = math.floor(radius) - maxOffsetY
729
				yStep = -1
730
			end
731
			for y = yStart,yEnd,yStep do
732
				cy2 = (radius - y) ^ 2
733
				remainder2 = (boundary2 - cz2 - cy2)
734
				if remainder2 >= 0 then
735
					-- This is the maximum difference in x from the centre we can be without definitely being outside the radius
736
					maxOffsetX = math.ceil((boundary2 - cz2 - cy2) ^ 0.5)
737
					-- Only do either the +x or -x side
738
					if (side == 0) then
739
						-- +x side
740
						xStart = math.floor(radius)
741
						xEnd = math.floor(radius) + maxOffsetX
742
					else
743
						-- -x side
744
						xStart = math.floor(radius) - maxOffsetX
745
						xEnd = math.floor(radius) - 1
746
					end
747
					-- Reverse direction we traverse xs when in -y side
748
					if y > math.floor(radius) then
749
						temp = xStart
750
						xStart = xEnd
751
						xEnd = temp
752
						xStep = -1
753
					else
754
						xStep = 1
755
					end
756
757
					for x = xStart,xEnd,xStep do
758
						-- Only blocks within the radius but still within 1 3d-diagonal block of the edge are eligible
759
						if isSphereBorder(offset, x, y, z, radius2) then
760
							navigateTo(x, y)
761
							placeBlock()
762
						end
763
					end
764
				end
765
			end
766
		end
767
end
768
769
function blockInSphereIsFull(offset, x, y, z, radiusSq)
770
	x = x - offset
771
	y = y - offset
772
	z = z - offset
773
	x = x ^ 2
774
	y = y ^ 2
775
	z = z ^ 2
776
	return x + y + z <= radiusSq
777
end
778
779
function isSphereBorder(offset, x, y, z, radiusSq)
780
	spot = blockInSphereIsFull(offset, x, y, z, radiusSq)
781
	if spot then
782
		spot = not blockInSphereIsFull(offset, x, y - 1, z, radiusSq) or
783
			not blockInSphereIsFull(offset, x, y + 1, z, radiusSq) or
784
			not blockInSphereIsFull(offset, x - 1, y, z, radiusSq) or
785
			not blockInSphereIsFull(offset, x + 1, y, z, radiusSq) or
786
			not blockInSphereIsFull(offset, x, y, z - 1, radiusSq) or
787
			not blockInSphereIsFull(offset, x, y, z + 1, radiusSq)
788
	end
789
	return spot
790
end
791
792
function dome(typus, diameter)
793
	-- Main dome and sphere building routine
794
	odd = not (math.fmod(diameter, 2) == 0)
795
	radius = diameter / 2;
796
	if odd then
797
		width = (2 * math.ceil(radius)) + 1;
798
		offset = math.floor(width/2);
799
	else
800
		width = (2 * math.ceil(radius)) + 2;
801
		offset = math.floor(width/2) - 0.5;		
802
	end
803
	--diameter --radius * 2 + 1
804
	sqrt3 = 3 ^ 0.5
805
	boundaryRadius = radius + 1.0
806
	boundary2 = boundaryRadius ^ 2
807
	radius2 = radius ^ 2
808
	
809
	if typus == "dome" then
810
		zstart = math.ceil(radius)
811
	elseif typus == "sphere" then
812
		zstart = 1
813
	elseif typus == "bowl" then
814
		zstart = 1
815
	end
816
	if typus == "bowl" then
817
		zend = math.floor(radius)
818
	else
819
		zend = width - 1
820
	end
821
822
	-- This loop is for each vertical layer through the sphere or dome.
823
	for z = zstart,zend do
824
		if not cost_only and z ~= zstart then
825
			navigateTo(positionX, positionY, positionZ + 1)
826
		end
827
		--writeOut("Layer " .. z)
828
		cz2 = (radius - z) ^ 2
829
		limitOffsetY = (boundary2 - cz2) ^ 0.5
830
		maxOffsetY = math.ceil(limitOffsetY)
831
		-- We do first the +x side, then the -x side to make movement efficient
832
		for side = 0,1 do
833
			-- On the right we go from small y to large y, on the left reversed
834
			-- This makes us travel clockwise (from below) around each layer
835
			if (side == 0) then
836
				yStart = math.floor(radius) - maxOffsetY
837
				yEnd = math.floor(radius) + maxOffsetY
838
				yStep = 1
839
			else
840
				yStart = math.floor(radius) + maxOffsetY
841
				yEnd = math.floor(radius) - maxOffsetY
842
				yStep = -1
843
			end
844
			for y = yStart,yEnd,yStep do
845
				cy2 = (radius - y) ^ 2
846
				remainder2 = (boundary2 - cz2 - cy2)
847
				if remainder2 >= 0 then
848
					-- This is the maximum difference in x from the centre we can be without definitely being outside the radius
849
					maxOffsetX = math.ceil((boundary2 - cz2 - cy2) ^ 0.5)
850
					-- Only do either the +x or -x side
851
					if (side == 0) then
852
						-- +x side
853
						xStart = math.floor(radius)
854
						xEnd = math.floor(radius) + maxOffsetX
855
					else
856
						-- -x side
857
						xStart = math.floor(radius) - maxOffsetX
858
						xEnd = math.floor(radius) - 1
859
					end
860
					-- Reverse direction we traverse xs when in -y side
861
					if y > math.floor(radius) then
862
						temp = xStart
863
						xStart = xEnd
864
						xEnd = temp
865
						xStep = -1
866
					else
867
						xStep = 1
868
					end
869
870
					for x = xStart,xEnd,xStep do
871
						-- Only blocks within the radius but still within 1 3d-diagonal block of the edge are eligible
872
						if isSphereBorder(offset, x, y, z, radius2) then
873
							navigateTo(x, y)
874
							placeBlock()
875
						end
876
					end
877
				end
878
			end
879
		end
880
	end
881
end
882
883
function cylinder(diameter, height)
884
	for i = 1, height do
885
		circle(diameter)
886
		navigateTo(positionX, positionY, positionZ + 1)
887
	end
888
end
889
890
polygonCornerList = {} -- Public list of corner coords for n-gons, will be used for hexagons, octagons, and future polygons.
891
-- It should be constructed as a nested list eg. {{x0,y0},{x1,y1},{x2,y2}...}
892
893
function constructPolygon() -- Uses polygonCornerList to draw sides between each point
894
	if #polygonCornerList == 0 then
895
		return false
896
	end
897
	for i = 1, #polygonCornerList do
898
		startX = polygonCornerList[i][1]
899
		startY = polygonCornerList[i][2]
900
		if i == #polygonCornerList then
901
			j = 1
902
		else
903
			j = i + 1
904
		end
905
		stopX = polygonCornerList[j][1]
906
		stopY = polygonCornerList[j][2]
907
		drawLine(stopX, stopY, startX, startY)
908
	end
909
	return true
910
end
911
912
function arbitraryPolygon(numberOfSides, Radius) -- Future function, this will eventually replace octagon and hexagon functions
913
end
914
915
function hexagon(sideLength) -- Fills out polygonCornerList with the points for a hexagon
916
	sideLength = sideLength - 1
917
	local changeX = sideLength / 2
918
	local changeY = round(math.sqrt(3) * changeX, 0)
919
	changeX = round(changeX, 0)
920
	polygonCornerList[1] = {changeX, 0}
921
	polygonCornerList[2] = {(changeX + sideLength), 0}
922
	polygonCornerList[3] = {((2 * changeX) + sideLength), changeY}
923
	polygonCornerList[4] = {(changeX + sideLength), (2 * changeY)}
924
	polygonCornerList[5] = {changeX, (2 * changeY)}
925
	polygonCornerList[6] = {0, changeY}
926
	if not constructPolygon() then
927
		error("This error should never happen.")
928
	end
929
end
930
931
function octagon(sideLength) -- Fills out polygonCornerList with the points for an octagon
932
	sideLength = sideLength - 1
933
	local change = round((sideLength - 1) / math.sqrt(2), 0)
934
	polygonCornerList[1] = {change, 0}
935
	polygonCornerList[2] = {(change + sideLength), 0}
936
	polygonCornerList[3] = {((2 * change) + sideLength), change}
937
	polygonCornerList[4] = {((2 * change) + sideLength), (change + sideLength)}
938
	polygonCornerList[5] = {(change + sideLength), ((2 * change) + sideLength)}
939
	polygonCornerList[6] = {change, ((2 * change) + sideLength)}
940
	polygonCornerList[7] = {0, (change + sideLength)}
941
	polygonCornerList[8] = {0, change}
942
	if not constructPolygon() then
943
		error("This error should never happen.")
944
	end
945
end
946
947
function sixprism(length, height)
948
	for i = 1, height do
949
		hexagon(length)
950
		if i ~= height then
951
			navigateTo(positionX, positionY, positionZ + 1)
952
		end
953
	end
954
end
955
956
function eightprism(length, height)
957
	for i = 1, height do
958
		octagon(length)
959
		if i ~= height then
960
			navigateTo(positionX, positionY, positionZ + 1)
961
		end
962
	end
963
end
964
965
-- Previous Progress Resuming, Simulation functions, Command Line, and File Backend
966
-- Will check for a "progress" file.
967
function CheckForPrevious() 
968
	if fs.exists(progFileName) then
969
		return true
970
	else
971
		return false
972
	end
973
end
974
975
-- Creates a progress file, containing a serialized table consisting of the shape type, shape input params, and the last known x, y, and z coords of the turtle (beginning of build project)
976
function ProgressFileCreate() 
977
	if not CheckForPrevious() then
978
		fs.makeDir(progFileName)
979
		return true
980
	else
981
		return false
982
	end
983
end
984
985
-- Deletes the progress file (at the end of the project, or at beginning if user chooses to delete old progress)
986
function ProgressFileDelete() 
987
	if fs.exists(progFileName) then
988
		fs.delete(progFileName)
989
		return true
990
	else 
991
		return false
992
	end
993
end
994
995
-- To read the shape params from the file.  Shape type, and input params (e.g. "dome" and radius)
996
function ReadShapeParams()
997
	-- TODO. Unneeded for now, can just use the table elements directly
998
end
999
1000
function WriteShapeParams(...) -- The ... lets it take any number of arguments and stores it to the table arg{} | This is still unused anywhere
1001
	local paramTable = arg
1002
	local paramName = "param"
1003
	local paramName2 = paramName
1004
	for i, v in ipairs(paramTable) do -- Iterates through the args passed to the function, ex. paramTable[1] i = 1 so paramName2 should be "param1", tested and works!
1005
		paramName2 = paramName .. i
1006
		tempProgTable[paramName2] = v
1007
		progTable[paramName2] = v
1008
	end
1009
end
1010
1011
-- function to write the progress to the file (x, y, z)
1012
function writeProgress()
1013
	local progFile
1014
	local progString = ""
1015
	if not (sim_mode or cost_only) then
1016
		progString = textutils.serialize(progTable) -- Put in here to save processing time when in cost_only
1017
		progFile = fs.open(progFileName, "w")
1018
		progFile.write(progString)
1019
		progFile.close()
1020
	end
1021
1022
end
1023
1024
-- Reads progress from file (shape, x, y, z, facing, blocks, param1, param2, param3)
1025
function readProgress()
1026
	local progFile = fs.open(progFileName, "r")
1027
	local readProgTable = textutils.unserialize(progFile.readAll())
1028
	progFile.close()
1029
	return readProgTable
1030
end
1031
1032
-- compares the progress read from the file to the current sim progress.  needs all four params 
1033
function compareProgress()
1034
	local progTableIn = progTable
1035
	local readProgTable = readProgress()
1036
	if (progTableIn.shape == readProgTable.shape and progTableIn.x == readProgTable.x and progTableIn.y == readProgTable.y and progTableIn.blocks == readProgTable.blocks and progTableIn.facing == readProgTable.facing) then
1037
		writeOut("All caught up!")
1038
		return true -- We're caught up!
1039
	else
1040
		return false -- Not there yet...
1041
	end
1042
end
1043
1044
function getGPSInfo() -- TODO: finish this
1045
	position = gps.locate()
1046
	gpsPositionX = position.x
1047
	gpsPositionZ = position.y
1048
	gpsPositionY = position.z
1049
	
1050
end
1051
1052
function setSimFlags(b)
1053
	sim_mode = b
1054
	cost_only = b
1055
	if cmd_line_cost_only then
1056
		cost_only = true
1057
	end
1058
end
1059
1060
function simulationCheck() -- checks state of the simulation
1061
	if sim_mode then
1062
		if compareProgress() then
1063
			setSimFlags(false) -- If we're caught up, un-set flags
1064
		else
1065
			setSimFlags(true)  -- If not caught up, just re-affirm that the flags are set
1066
		end
1067
	end
1068
end
1069
1070
function continueQuery()
1071
	if cmd_line_resume then
1072
		 return true
1073
	else
1074
		 if not cmd_line then
1075
			 writeOut("Do you want to continue the last job?")
1076
			 local yes = io.read()
1077
			 if yes == "y" then
1078
				 return true
1079
			 else
1080
				 return false
1081
			 end
1082
		 end
1083
	end
1084
end
1085
1086
function progressUpdate()  -- This ONLY updates the local table variable.  Writing is handled above. -- I want to change this to allow for any number of params
1087
	progTable = {shape = choice, enderchest_refilling = tempProgTable.enderchest_refilling, param1 = tempProgTable.param1, param2 = tempProgTable.param2, param3 = tempProgTable.param3, param4 = tempProgTable.param4, x = positionX, y = positionY, z = positionZ, facing = facing, blocks = blocks}
1088
	if not sim_mode then 
1089
		writeProgress()
1090
	end
1091
end
1092
1093
 -- Command Line
1094
function checkCommandLine() --True if arguments were passed
1095
	if #argTable > 0 then
1096
		cmd_line = true
1097
		return true
1098
	else
1099
		cmd_line = false
1100
		return false
1101
	end
1102
end
1103
1104
function needsHelp() -- True if -h is passed
1105
	for i, v in pairs(argTable) do
1106
		if v == "-h" or v == "-help" or v == "--help" then
1107
			return true
1108
		else
1109
			return false
1110
		end
1111
	end
1112
end
1113
1114
function setFlagsFromCommandLine() -- Sets count_only, chain_next_shape, and sim_mode
1115
	for i, v in pairs(argTable) do
1116
		if v == "-c" or v == "-cost" or v == "--cost" then
1117
			cost_only = true
1118
			cmd_line_cost_only = true
1119
			writeOut("Cost Only Mode")
1120
		end
1121
		if v == "-z" or v == "-chain" or v == "--chain" then
1122
			chain_next_shape = true
1123
			writeOut("Chained Shape Mode")
1124
		end
1125
		if v == "-r" or v == "-resume" or v == "--resume" then
1126
			cmd_line_resume = true
1127
			writeOut("Resuming")
1128
		end
1129
		if v == "-e" or v == "-ender" or v == "--ender" then
1130
			enderchest_refilling = true
1131
			tempProgTable.enderchest_refilling = true
1132
			writeOut("Enderchest Mode")
1133
		end
1134
		if v == "-g" or v == "-home" or v == "--home" then
1135
			return_to_home = true
1136
			writeOut("Will return home")
1137
		end
1138
	end
1139
end
1140
1141
function setTableFromCommandLine() -- Sets progTable and tempProgTable from command line arguments
1142
	progTable.shape = argTable[1]
1143
	tempProgTable.shape = argTable[1]
1144
	local paramName = "param"
1145
	local paramName2 = paramName
1146
	for i = 2, #argTable do
1147
		local addOn = tostring(i - 1)
1148
		paramName2 = paramName .. addOn
1149
		progTable[paramName2] = argTable[i]
1150
		tempProgTable[paramName2] = argTable[i]
1151
	end
1152
end
1153
1154
-- Menu, Drawing and Main functions
1155
1156
function choiceIsValidShape(choice)
1157
	local validShapes = {"rectangle", "square", "line", "wall", "platform", "stair", "stairs", "cuboid", "1/2-sphere", "1/2 sphere", "dome", "bowl", "sphere", "circle", "cylinder", "pyramid", "hexagon", "octagon", "6-prism", "6 prism", "8-prism", "8 prism"}
1158
	for i = 1, #validShapes do
1159
		if choice == validShapes[i] then
1160
			return true
1161
		end
1162
	end
1163
	return false
1164
end
1165
1166
function choiceFunction()
1167
	if sim_mode == false and cmd_line == false then -- If we are NOT resuming progress
1168
		local page = 1
1169
		choice = io.read()
1170
		choice = string.lower(choice) -- All checks are aginst lower case words so this is to ensure that
1171
		while ((choice == "next") or (choice == "back")) do
1172
			if (choice == "next") then
1173
				if page == 1 then
1174
					writeMenu2()
1175
					page = 2
1176
				else
1177
					writeMenu()
1178
					page = 1
1179
				end
1180
			end
1181
			if (choice == "back") then
1182
				if page == 1 then
1183
					writeMenu2()
1184
					page = 2
1185
				else
1186
					writeMenu()
1187
					page = 1
1188
				end
1189
			end
1190
			choice = io.read()
1191
			choice = string.lower(choice) -- All checks are aginst lower case words so this is to ensure that
1192
		end
1193
		if choice == "end" or choice == "exit" then
1194
			writeOut("Goodbye.")
1195
			return
1196
		end
1197
		if choice == "help" then
1198
			getHelp()
1199
			return
1200
		end
1201
		if choice == "credits" then
1202
			showCredits()
1203
			return
1204
		end
1205
		tempProgTable = {shape = choice}
1206
		progTable = {shape = choice}
1207
		if not choiceIsValidShape(choice) then
1208
			writeOut(choice ..  " is not a valid shape choice.")
1209
			return
1210
		end
1211
		writeOut("Building a "..choice)
1212
		local yes = getInput("string","Want to just calculate the cost?","y","n")
1213
		if yes == 'y' then
1214
			cost_only = true
1215
		end
1216
		local yes = getInput("string","Want turtle to return to start after build?","y","n")
1217
		if yes == 'y' then
1218
			return_to_home = true
1219
		end
1220
		local yes = getInput("string","Want the turtle to refill from enderchest (slot 16)?","y","n")
1221
		if yes == 'y' then
1222
			enderchest_refilling = true
1223
			tempProgTable.enderchest_refilling = true
1224
		end
1225
	elseif sim_mode == true then -- If we ARE resuming progress
1226
		tempProgTable = readProgress()
1227
		choice = tempProgTable.shape
1228
		choice = string.lower(choice) -- All checks are aginst lower case words so this is to ensure that
1229
		enderchest_refilling =  tempProgTable.enderchest_refilling
1230
	elseif cmd_line == true then -- If running from command line
1231
		if needsHelp() then
1232
			showCmdLineHelp()
1233
			return
1234
		end
1235
		choice = tempProgTable.shape
1236
		choice = string.lower(choice) -- All checks are aginst lower case words so this is to ensure that
1237
		enderchest_refilling =  tempProgTable.enderchest_refilling
1238
		writeOut("Building a "..choice)
1239
	end	
1240
	if not cost_only then
1241
		turtle.select(1)
1242
		activeSlot = 1
1243
		if turtle.getItemCount(activeSlot) == 0 then
1244
			if resupply then
1245
				writeOut("Please put building blocks in the first slot.")
1246
			else
1247
				writeOut("Please put building blocks in the first slot (and more if you need them)")
1248
			end
1249
			while turtle.getItemCount(activeSlot) <= 1 do
1250
				os.sleep(.1)
1251
			end
1252
		end
1253
	else
1254
		activeSlot = 1
1255
	end
1256
	-- Shape selection if cascade
1257
	-- Line based shapes
1258
	if choice == "rectangle" then
1259
		local depth = 0
1260
		local width = 0
1261
		if sim_mode == false and cmd_line == false then
1262
			width = getInput("int","How wide does it need to be?")
1263
			depth = getInput("int","How deep does it need to be?")
1264
		elseif sim_mode == true or cmd_line == true then
1265
			width = tempProgTable.param1
1266
			depth = tempProgTable.param2
1267
		end
1268
		tempProgTable.param1 = width
1269
		tempProgTable.param2 = depth
1270
		progTable = {param1 = width, param2 = depth} -- THIS is here because we NEED to update the local table!
1271
		rectangle(width, depth)
1272
	end
1273
	if choice == "square" then
1274
		local sideLength
1275
		if sim_mode == false and cmd_line == false then
1276
			sideLength = getInput("int","How long does each side need to be?")
1277
		elseif sim_mode == true or cmd_line == true then
1278
			sideLength = tempProgTable.param1
1279
		end
1280
		tempProgTable.param1 = sideLength
1281
		progTable = {param1 = sideLength}
1282
		square(sideLength)
1283
	end
1284
	if choice == "line" then
1285
		local startX = 0
1286
		local startY = 0
1287
		local endX = 0
1288
		local endY = 0
1289
		if sim_mode == false and cmd_line == false then
1290
			writeOut("Note that the turtle's starting position is 0, 0.")
1291
			startX = getInput("int","Where does the start X need to be?")
1292
			startY = getInput("int","Where does the start Y need to be?")
1293
			endX = getInput("int","Where does the end X need to be?")
1294
			endY = getInput("int","Where does the end Y need to be?")
1295
		elseif sim_mode == true or cmd_line == true then
1296
			startX = tempProgTable.param1
1297
			startY = tempProgTable.param2
1298
			endX = tempProgTable.param3
1299
			endY = tempProgTable.param4
1300
		end
1301
		tempProgTable.param1 = startX
1302
		tempProgTable.param2 = startY
1303
		tempProgTable.param3 = endX
1304
		tempProgTable.param4 = endY
1305
		progTable = {param1 = startX, param2 = startY, param3 = endX, param4 = endY}
1306
		drawLine(endX, endY, startX, startY)
1307
	end
1308
	if choice == "wall" then
1309
		local depth = 0
1310
		local height = 0
1311
		if sim_mode == false and cmd_line == false then
1312
			depth = getInput("int","How deep does it need to be?")
1313
			height = getInput("int","How high does it need to be?")
1314
		elseif sim_mode == true or cmd_line == true then
1315
			depth = tempProgTable.param1
1316
			height = tempProgTable.param2
1317
		end			
1318
		tempProgTable.param1 = depth
1319
		tempProgTable.param2 = height
1320
		progTable = {param1 = depth, param2 = height}
1321
		wall(depth, height)
1322
	end
1323
	if choice == "platform" then
1324
		local width = 0
1325
		local depth = 0
1326
		if sim_mode == false and cmd_line == false then
1327
			width = getInput("int","How wide does it need to be?")
1328
			depth = getInput("int","How deep does it need to be?")
1329
		elseif sim_mode == true or cmd_line == true then	
1330
			width = tempProgTable.param1		
1331
			depth = tempProgTable.param2
1332
		end		
1333
		tempProgTable.param1 = width
1334
		tempProgTable.param2 = depth
1335
		progTable = {param1 = width, param2 = depth}
1336
		platform(width, depth)
1337
	end
1338
	if choice == "stair" or choice == "stairs" then
1339
		local width = 0
1340
		local height = 0
1341
		if sim_mode == false and cmd_line == false then
1342
			width = getInput("int","How wide does it need to be?")
1343
			height = getInput("int","How high does it need to be?")
1344
		elseif sim_mode == true or cmd_line == true then
1345
			width = tempProgTable.param1
1346
			height = tempProgTable.param2
1347
		end
1348
		tempProgTable.param1 = width
1349
		tempProgTable.param2 = height
1350
		progTable = {param1 = width, param2 = height}
1351
		stair(width, height)
1352
		special_chain = true
1353
	end
1354
	if choice == "cuboid" then
1355
		local width = 0
1356
		local depth = 0
1357
		local height = 0
1358
		local hollow = ""
1359
		if sim_mode == false and cmd_line == false then
1360
			width = getInput("int","How wide does it need to be?")
1361
			depth = getInput("int","How deep does it need to be?")
1362
			height = getInput("int","How high does it need to be?")
1363
			hollow = getInput("string","Does it need to be hollow?","y","n")
1364
		elseif sim_mode == true or cmd_line == true then
1365
			width = tempProgTable.param1
1366
			depth = tempProgTable.param2
1367
			height = tempProgTable.param3
1368
			hollow = tempProgTable.param4
1369
		end
1370
		tempProgTable.param1 = width
1371
		tempProgTable.param2 = depth
1372
		tempProgTable.param3 = height
1373
		tempProgTable.param4 = hollow	
1374
		progTable = {param1 = width, param2 = depth, param3 = height}
1375
		cuboid(width, depth, height, hollow)
1376
	end
1377
	if choice == "pyramid" then
1378
		local length = 0
1379
		local hollow = ""
1380
		if sim_mode == false and cmd_line == false then
1381
			length = getInput("int","How long does each side of the base layer need to be?")
1382
			hollow = getInput("string","Does it need to be hollow?","y","n")
1383
		elseif sim_mode == true or cmd_line == true then
1384
			length = tempProgTable.param1
1385
			hollow = tempProgTable.param2
1386
		end
1387
		tempProgTable.param1 = length
1388
		tempProgTable.param2 = hollow
1389
		progTable = {param1 = length, param2 = hollow}
1390
		pyramid(length, hollow)
1391
	end
1392
	-- Circle based shapes
1393
	if choice == "1/2-sphere" or choice == "1/2 sphere" then
1394
		local diameter = 0
1395
		local half = ""
1396
		if sim_mode == false and cmd_line == false then
1397
			diameter = getInput("int","What diameter does it need to be?")
1398
			half = getInput("string","What half of the sphere does it need to be?","bottom","top")
1399
		elseif sim_mode == true or cmd_line == true then
1400
			diameter = tempProgTable.param1
1401
			half = tempProgTable.param2
1402
		end	
1403
		tempProgTable.param1 = diameter
1404
		tempProgTable.param2 = half
1405
		progTable = {param1 = diameter, param2 = half}
1406
		if half == "bottom" then
1407
			dome("bowl", diameter)
1408
		elseif half == "top" then
1409
			dome("dome", diameter)
1410
		end
1411
	end
1412
	if choice == "dome" then
1413
		local diameter = 0
1414
		if sim_mode == false and cmd_line == false then
1415
			diameter = getInput("int","What diameter does it need to be?")
1416
		elseif sim_mode == true or cmd_line == true then
1417
			diameter = tempProgTable.param1
1418
		end	
1419
		tempProgTable.param1 = diameter
1420
		progTable = {param1 = diameter}
1421
		dome("dome", diameter)
1422
	end
1423
	if choice == "bowl" then
1424
		local diameter = 0
1425
		if sim_mode == false and cmd_line == false then
1426
			diameter = getInput("int","What diameter does it need to be?")
1427
		elseif sim_mode == true or cmd_line == true then
1428
			diameter = tempProgTable.param1
1429
		end	
1430
		tempProgTable.param1 = diameter
1431
		progTable = {param1 = diameter}
1432
		dome("bowl", diameter)
1433
	end
1434
	if choice == "sphere" then
1435
		local diameter = 0
1436
		if sim_mode == false and cmd_line == false then
1437
			diameter = getInput("int","What diameter does it need to be?")
1438
		elseif sim_mode == true or cmd_line == true then
1439
			diameter = tempProgTable.param1
1440
		end
1441
		tempProgTable.param1 = diameter
1442
		progTable = {param1 = diameter}
1443
		dome("sphere", diameter)
1444
	end
1445
	if choice == "circle" then
1446
		local diameter = 0
1447
		if sim_mode == false and cmd_line == false then
1448
			diameter = getInput("int","What diameter does it need to be?")
1449
		elseif sim_mode == true or cmd_line == true then
1450
			diameter = tempProgTable.param1
1451
		end
1452
		tempProgTable.param1 = diameter
1453
		progTable = {param1 = diameter}
1454
		circle(diameter)
1455
	end
1456
	if choice == "cylinder" then
1457
		local diameter = 0
1458
		local height = 0
1459
		if sim_mode == false and cmd_line == false then
1460
			diameter = getInput("int","What diameter does it need to be?")
1461
			height = getInput("int","How high does it need to be?")
1462
		elseif sim_mode == true or cmd_line == true then
1463
			diameter = tempProgTable.param1
1464
			height = tempProgTable.param2
1465
		end
1466
		tempProgTable.param1 = diameter
1467
		tempProgTable.param2 = height
1468
		progTable = {param1 = diameter, param2 = height}
1469
		cylinder(diameter, height)
1470
	end
1471
	-- Polygon shapes
1472
	if choice == "hexagon" then
1473
		local length = 0
1474
		if sim_mode == false and cmd_line == false then
1475
			length = getInput("int","How long does each side need to be?")
1476
		elseif sim_mode == true or cmd_line == true then
1477
			length = tempProgTable.param1
1478
		end
1479
		tempProgTable.param1 = length
1480
		progTable = {param1 = length}
1481
		hexagon(length)
1482
	end
1483
	if choice == "octagon" then
1484
		local length = 0
1485
		if sim_mode == false and cmd_line == false then
1486
			length = getInput("int","How long does each side need to be?")
1487
		elseif sim_mode == true or cmd_line == true then
1488
			length = tempProgTable.param1
1489
		end
1490
		tempProgTable.param1 = length
1491
		progTable = {param1 = length}
1492
		octagon(length)
1493
	end
1494
	if choice == "6-prism" or choice == "6 prism" then
1495
		local length = 0
1496
		local height = 0
1497
		if sim_mode == false and cmd_line == false then
1498
			length = getInput("int","How long does each side need to be?")
1499
			height = getInput("int","How high does it need to be?")
1500
		elseif sim_mode == true or cmd_line == true then
1501
			length = tempProgTable.param1
1502
			height = tempProgTable.param2
1503
		end
1504
		tempProgTable.param1 = length
1505
		tempProgTable.param2 = height
1506
		progTable = {param1 = length, param2 = height}
1507
		sixprism(length, height)
1508
	end
1509
	if choice == "8-prism" or choice == "8 prism" then
1510
		local length = 0
1511
		local height = 0
1512
		if sim_mode == false and cmd_line == false then
1513
			length = getInput("int","How long does each side need to be?")
1514
			height = getInput("int","How high does it need to be?")
1515
		elseif sim_mode == true or cmd_line == true then
1516
			length = tempProgTable.param1
1517
			height = tempProgTable.param2
1518
		end
1519
		tempProgTable.param1 = length
1520
		tempProgTable.param2 = height
1521
		progTable = {param1 = length, param2 = height}
1522
		eightprism(length, height)
1523
	end
1524
	if return_to_home then
1525
		goHome() -- After all shape building has finished
1526
	end
1527
	writeOut("Done") -- Saves a few lines when put here rather than in each if statement
1528
end
1529
1530
function writeMenu()
1531
	term.clear()
1532
	term.setCursorPos(1, 1)
1533
	writeOut("Shape Maker 1.7 by Keridos/CupricWolf/pokemane")
1534
	if resupply then					-- Any ideas to make this more compact/better looking (in terms of code)?
1535
		writeOut("Resupply Mode Active")
1536
	elseif (resupply and can_use_gps) then
1537
		writeOut("Resupply and GPS Mode Active")
1538
	elseif can_use_gps then
1539
		writeOut("GPS Mode Active")
1540
	else
1541
		writeOut("Standard Mode Active")
1542
	end
1543
	if not cmd_line then
1544
		writeOut("What shape do you want to build? [page 1/2]");
1545
		writeOut("next for page 2")
1546
		writeOut("+---------+-----------+-------+-------+")
1547
		writeOut("| square  | rectangle | wall  | line  |")
1548
		writeOut("| cylinder| platform  | stair | cuboid|")
1549
		writeOut("| pyramid | 1/2-sphere| sphere| circle|")
1550
		writeOut("+---------+-----------+-------+-------+")
1551
		writeOut("")
1552
	end
1553
end
1554
1555
function writeMenu2()
1556
	term.clear()
1557
	term.setCursorPos(1, 1)
1558
	writeOut("Shape Maker 1.7 by Keridos/CupricWolf/pokemane")
1559
	if resupply then					-- Any ideas to make this more compact/better looking (in terms of code)?
1560
		writeOut("Resupply Mode Active")
1561
	elseif (resupply and can_use_gps) then
1562
		writeOut("Resupply and GPS Mode Active")
1563
	elseif can_use_gps then
1564
		writeOut("GPS Mode Active")
1565
	else
1566
		writeOut("Standard Mode Active")
1567
	end
1568
	writeOut("What shape do you want to build? [page 2/2]");
1569
	writeOut("back for page 1")
1570
	writeOut("+---------+-----------+-------+-------+")
1571
	writeOut("| hexagon | octagon   | dome  |       |")
1572
	writeOut("| 6-prism | 8-prism   | bowl  |       |")
1573
	writeOut("| help    | credits   | end   |       |")
1574
	writeOut("+---------+-----------+-------+-------+")
1575
	writeOut("")
1576
end
1577
1578
function showCmdLineHelp()
1579
	term.clear()
1580
	term.setCursorPos(1, 1)
1581
	writeOut("Command line help")
1582
	writeOut("Usage: shape [shape-type] [param1] [param2] [param3] [param4] [-c] [-h] [-z] [-r]\n")
1583
	writeOut("-c or -cost or --cost: Activate cost only mode\n")
1584
	writeOut("-h or -help or --help: Show this information")
1585
	io.read()
1586
	writeOut("-z or -chain or --chain: Lets you chain together multiple shapes\n")
1587
	writeOut("-g or -home or --home: Make turtle go 'home' after build\n")
1588
	writeOut("-r or -resume or --resume: Resume the last build if possible")
1589
	io.read()
1590
	writeOut("-e or -ender or --ender: Activate enderchest refilling\n")
1591
	writeOut("shape-type can be any of the shapes in the menu\n")
1592
	writeOut("After shape-type input all of the paramaters for the shape, varies by shape\n")
1593
	writeOut("Put any flags (-c, -h, etc.) at the end of your command")
1594
end
1595
1596
function getHelp()
1597
	term.clear()
1598
	term.setCursorPos(1, 1)
1599
	writeOut("Width is to the right of the turtle. (X-Axis)")
1600
	writeOut("Depth is to the front of the turtle. (Y-Axis)")
1601
	writeOut("Height is to the top of the turtle. (Z-Axis)")
1602
	writeOut("Length is the side length of some shapes. (Squares and Polygons)")
1603
	io.read()
1604
	term.clear()
1605
	term.setCursorPos(1, 1)
1606
	local page = 1
1607
	writeOut("What shape do you want help with? [page 1/2]");
1608
	writeOut("next for page 2")
1609
	writeOut("+---------+-----------+-------+-------+")
1610
	writeOut("| square  | rectangle | wall  | line  |")
1611
	writeOut("| cylinder| platform  | stair | cuboid|")
1612
	writeOut("| pyramid | 1/2-sphere| sphere| circle|")
1613
	writeOut("+---------+-----------+-------+-------+")
1614
	writeOut("")
1615
	choice = io.read()
1616
	choice = string.lower(choice)
1617
	while ((choice == "next") or (choice == "back")) do
1618
		if (choice == "next") then
1619
			if (page == 1) then
1620
				page = 2
1621
				term.clear()
1622
				term.setCursorPos(1, 1)
1623
				writeOut("What shape do you want help wih? [page 2/2]?");
1624
				writeOut("back for page 1")
1625
				writeOut("+---------+-----------+-------+-------+")
1626
				writeOut("| hexagon | octagon   | dome  |       |")
1627
				writeOut("| 6-prism | 8-prism   | bowl  |       |")
1628
				writeOut("|         |           |       |       |")
1629
				writeOut("+---------+-----------+-------+-------+")
1630
				writeOut("")
1631
			else
1632
				page = 1
1633
				term.clear()
1634
				term.setCursorPos(1, 1)
1635
				writeOut("What shape do you want help with? [page 1/2]");
1636
				writeOut("next for page 2")
1637
				writeOut("+---------+-----------+-------+-------+")
1638
				writeOut("| square  | rectangle | wall  | line  |")
1639
				writeOut("| cylinder| platform  | stair | cuboid|")
1640
				writeOut("| pyramid | 1/2-sphere| sphere| circle|")
1641
				writeOut("+---------+-----------+-------+-------+")
1642
				writeOut("")
1643
			end
1644
		end
1645
		if (choice == "back") then
1646
			if (page == 1) then
1647
				page = 2
1648
				term.clear()
1649
				term.setCursorPos(1, 1)
1650
				writeOut("What shape do you want help wih? [page 2/2]?");
1651
				writeOut("back for page 1")
1652
				writeOut("+---------+-----------+-------+-------+")
1653
				writeOut("| hexagon | octagon   | dome  |       |")
1654
				writeOut("| 6-prism | 8-prism   | bowl  |       |")
1655
				writeOut("|         |           |       |       |")
1656
				writeOut("+---------+-----------+-------+-------+")
1657
				writeOut("")
1658
			else
1659
				page = 1
1660
				term.clear()
1661
				term.setCursorPos(1, 1)
1662
				writeOut("What shape do you want help with? [page 1/2]");
1663
				writeOut("next for page 2")
1664
				writeOut("+---------+-----------+-------+-------+")
1665
				writeOut("| square  | rectangle | wall  | line  |")
1666
				writeOut("| cylinder| platform  | stair | cuboid|")
1667
				writeOut("| pyramid | 1/2-sphere| sphere| circle|")
1668
				writeOut("+---------+-----------+-------+-------+")
1669
				writeOut("")
1670
			end
1671
		end
1672
		choice = io.read()
1673
		choice = string.lower(choice) 
1674
	end
1675
	if not choiceIsValidShape(choice) then
1676
		writeOut(choice ..  " is not a valid shape choice.")
1677
		return
1678
	end
1679
	-- If cascade time!
1680
	if choice == "rectangle" then
1681
		term.clear()
1682
		term.setCursorPos(1, 1)
1683
		writeOut("The rectangle is a perimiter of width by depth. Use platform if you want a filled in rectangle. The rectangle takes two parameters (two integers) Width then Depth.")
1684
	end
1685
	if choice == "square" then
1686
		term.clear()
1687
		term.setCursorPos(1, 1)
1688
		writeOut("The square is a perimiter of length by length. Use platform if you want a filled in square. The square takes one parameter (one integer) Length.")
1689
	end
1690
	if choice == "line" then
1691
		term.clear()
1692
		term.setCursorPos(1, 1)
1693
		writeOut("The line is drawn between the start and end points given. The turtle's initial position is 0, 0 so that must by taken into account. The line takes four parameters (four integers) Start X then Start Y then End X then End Y.")
1694
	end
1695
	if choice == "wall" then
1696
		term.clear()
1697
		term.setCursorPos(1, 1)
1698
		writeOut("The wall is a vertical plane. The wall takes two parameters (two integers) Depth then Height.")
1699
	end
1700
	if choice == "platform" then
1701
		term.clear()
1702
		term.setCursorPos(1, 1)
1703
		writeOut("The platform is a horizontal plane of width by depth. Use rectangle or square if you want just a perimeter. The platform takes two parameters (two integers) Width then Depth.")
1704
	end
1705
	if choice == "stair" or choice == "stairs" then
1706
		term.clear()
1707
		term.setCursorPos(1, 1)
1708
		writeOut("The stair or stairs are an incline of width by height. The stair takes two parameters (two integers) Width then Height.")
1709
	end
1710
	if choice == "cuboid" then
1711
		term.clear()
1712
		term.setCursorPos(1, 1)
1713
		writeOut("The cuboid is a rectangular prism of width by depth by height. The hollow parameter determines if the shape is solid or like a rectangular tube. The cuboid takes four parameters (three intergers and one y/n) Width then Depth then Height then Hollow(y/n).")
1714
	end
1715
	if choice == "1/2-sphere" or choice == "1/2 sphere" then
1716
		term.clear()
1717
		term.setCursorPos(1, 1)
1718
		writeOut("The half sphere is the top or bottom half of a sphere. The half parameter determines of the top or bottom half of the sphere built. The half sphere takes two parameters (one integer and one top/bottom) Diameter then half(top/bottom).")
1719
	end
1720
	if choice == "dome" then
1721
		term.clear()
1722
		term.setCursorPos(1, 1)
1723
		writeOut("The dome shape is a shortcut to the top half sphere. The dome takes one parameter (one integer) Diameter.")
1724
	end
1725
	if choice == "bowl" then
1726
		term.clear()
1727
		term.setCursorPos(1, 1)
1728
		writeOut("The bowl shape is a shortcut to the bottom half sphere. The bowl takes one parameter (one integer) Diameter.")
1729
	end
1730
	if choice == "sphere" then
1731
		term.clear()
1732
		term.setCursorPos(1, 1)
1733
		writeOut("The sphere is just that, a sphere. It is hollow. The sphere takes one parameter (one integer) Diameter.")
1734
	end
1735
	if choice == "circle" then
1736
		term.clear()
1737
		term.setCursorPos(1, 1)
1738
		writeOut("The circle is just that, a circle. It is just a perimeter. The circle takes one parameter (one integer) Diameter.")
1739
	end
1740
	if choice == "cylinder" then
1741
		term.clear()
1742
		term.setCursorPos(1, 1)
1743
		writeOut("The cylinder is a cylindrical tube of diameter by height. The cylinder takes two parameters (two integers) Diameter then Height.")
1744
	end
1745
	if choice == "pyramid" then
1746
		term.clear()
1747
		term.setCursorPos(1, 1)
1748
		writeOut("The pyramid is a four sided pyramid with base length by length. The hollow parameter determines if the inside is filled. The pyramid takes two parameters (one integer and one y/n) Base Length then Hollow(y/n).")
1749
	end
1750
	if choice == "hexagon" then
1751
		term.clear()
1752
		term.setCursorPos(1, 1)
1753
		writeOut("The hexagon is a hexagonal perimeter. The hexagon takes one parameter (one integer) Length.")
1754
	end
1755
	if choice == "octagon" then
1756
		term.clear()
1757
		term.setCursorPos(1, 1)
1758
		writeOut("The octagon is and octagonal perimeter. The octagon takes one parameter (one integer) Length.")
1759
	end
1760
	if choice == "6-prism" or choice == "6 prism" then
1761
		term.clear()
1762
		term.setCursorPos(1, 1)
1763
		writeOut("The 6 prism is a hexagonal prism shaped tube. The 6 prism takes two parameters (two integers) Length then Height.")
1764
	end
1765
	if choice == "8-prism" or choice == "8 prism" then
1766
		term.clear()
1767
		term.setCursorPos(1, 1)
1768
		writeOut("The 8 prism is an octagonal prism shaped tube. The 8 prism takes two parameters (two integers) Length then Height.")
1769
	end
1770
end
1771
1772
function showCredits()
1773
	term.clear()
1774
	term.setCursorPos(1, 1)
1775
	writeOut("Credits for the shape builder:")
1776
	writeOut("Based on work by Michiel, Vliekkie, and Aeolun")
1777
	writeOut("Sphere/dome code by IMarvinTPA")
1778
	writeOut("Additional improvements by Keridos, CupricWolf, and pokemane")
1779
end
1780
1781
function main()
1782
	if wrapModules()=="resupply" then
1783
		linkToRSStation()
1784
	end
1785
	if checkCommandLine() then
1786
		if needsHelp() then
1787
			showCmdLineHelp()
1788
			return -- Close the program after help info is shown
1789
		end
1790
		setFlagsFromCommandLine()
1791
		setTableFromCommandLine()
1792
	end
1793
	if (CheckForPrevious()) then  -- Will check to see if there was a previous job and gps is enabled, and if so, ask if the user would like to re-initialize to current progress status
1794
		if not continueQuery() then -- If the user doesn't want to continue
1795
			ProgressFileDelete()
1796
			setSimFlags(false) -- Just to be safe
1797
			writeMenu()
1798
			choiceFunction()
1799
		else	-- If the user wants to continue
1800
			setSimFlags(true)
1801
			choiceFunction()
1802
		end
1803
	else
1804
		setSimFlags(false)
1805
		writeMenu()
1806
		choiceFunction()
1807
	end
1808
	if (blocks ~= 0) and (fuel ~= 0) then -- Do not show on help or credits page or when selecting end
1809
		writeOut("Blocks used: " .. blocks)
1810
		writeOut("Fuel used: " .. fuel)
1811
	end
1812
	ProgressFileDelete() -- Removes file upon successful completion of a job, or completion of a previous job.
1813
	progTable = {}
1814
	tempProgTable = {}
1815
end
1816
1817
main()