View difference between Paste ID: emGHrp3i and RAHj4r2K
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
647
		navigateTo(0, 0, i)
648
		if (hollow == "n") then
649
			platform(width, depth, 0, 0)
650
		else
651
			rectangle(width, depth, 0, 0)
652
		end
653
	end
654
end
655
656
function pyramid(length, hollow)
657
	-- local height = math.ceil(length / 2) - 1
658
	i = 0
659
	while (length > 0) do
660
		navigateTo(i, i, i)
661
		if (hollow == "y") then
662
			rectangle(length, length, i, i)
663
		else
664
			platform(length, length, i, i)
665
		end
666
		i = i + 1
667
		length = length - 2
668
	end
669
end
670
671
function stair(width, height, startX, startY) -- Last two might be able to be used to make a basic home-like shape later?
672
	startX = startX or positionX
673
	startY = startY or positionY
674
	endX = startX + width - 1
675
	endY = startY + height - 1
676
	forward = true
677
	for counterY = startY, endY do
678
		if forward then
679
			for counterX = startX, endX do
680
				navigateTo(counterX, counterY)
681
				placeBlock()
682
			end
683
		else
684
			for counterX = endX, startX, -1 do
685
				navigateTo(counterX, counterY)
686
				placeBlock()
687
			end
688
		end
689
		if counterY ~= endY then
690
			navigateTo(positionX, positionY, positionZ + 1)
691
			forward = not forward
692
		end
693
	end
694
end
695
696
function circle(diameter)
697
	odd = not (math.fmod(diameter, 2) == 0)
698
	radius = diameter / 2;
699
	if odd then
700
		width = (2 * math.ceil(radius)) + 1;
701
		offset = math.floor(width/2);
702
	else
703
		width = (2 * math.ceil(radius)) + 2;
704
		offset = math.floor(width/2) - 0.5;		
705
	end
706
	--diameter --radius * 2 + 1
707
	sqrt3 = 3 ^ 0.5
708
	boundaryRadius = radius + 1.0
709
	boundary2 = boundaryRadius ^ 2
710
	radius2 = radius ^ 2
711
	z = math.floor(radius)
712
	cz2 = (radius - z) ^ 2
713
	limitOffsetY = (boundary2 - cz2) ^ 0.5
714
	maxOffsetY = math.ceil(limitOffsetY)
715
	-- We do first the +x side, then the -x side to make movement efficient
716
	for side = 0,1 do
717
			-- On the right we go from small y to large y, on the left reversed
718
			-- This makes us travel clockwise (from below) around each layer
719
			if (side == 0) then
720
				yStart = math.floor(radius) - maxOffsetY
721
				yEnd = math.floor(radius) + maxOffsetY
722
				yStep = 1
723
			else
724
				yStart = math.floor(radius) + maxOffsetY
725
				yEnd = math.floor(radius) - maxOffsetY
726
				yStep = -1
727
			end
728
			for y = yStart,yEnd,yStep do
729
				cy2 = (radius - y) ^ 2
730
				remainder2 = (boundary2 - cz2 - cy2)
731
				if remainder2 >= 0 then
732
					-- This is the maximum difference in x from the centre we can be without definitely being outside the radius
733
					maxOffsetX = math.ceil((boundary2 - cz2 - cy2) ^ 0.5)
734
					-- Only do either the +x or -x side
735
					if (side == 0) then
736
						-- +x side
737
						xStart = math.floor(radius)
738
						xEnd = math.floor(radius) + maxOffsetX
739
					else
740
						-- -x side
741
						xStart = math.floor(radius) - maxOffsetX
742
						xEnd = math.floor(radius) - 1
743
					end
744
					-- Reverse direction we traverse xs when in -y side
745
					if y > math.floor(radius) then
746
						temp = xStart
747
						xStart = xEnd
748
						xEnd = temp
749
						xStep = -1
750
					else
751
						xStep = 1
752
					end
753
754
					for x = xStart,xEnd,xStep do
755
						-- Only blocks within the radius but still within 1 3d-diagonal block of the edge are eligible
756
						if isSphereBorder(offset, x, y, z, radius2) then
757
							navigateTo(x, y)
758
							placeBlock()
759
						end
760
					end
761
				end
762
			end
763
		end
764
end
765
766
function blockInSphereIsFull(offset, x, y, z, radiusSq)
767
	x = x - offset
768
	y = y - offset
769
	z = z - offset
770
	x = x ^ 2
771
	y = y ^ 2
772
	z = z ^ 2
773
	return x + y + z <= radiusSq
774
end
775
776
function isSphereBorder(offset, x, y, z, radiusSq)
777
	spot = blockInSphereIsFull(offset, x, y, z, radiusSq)
778
	if spot then
779
		spot = not blockInSphereIsFull(offset, x, y - 1, z, radiusSq) or
780
			not blockInSphereIsFull(offset, x, y + 1, z, radiusSq) or
781
			not blockInSphereIsFull(offset, x - 1, y, z, radiusSq) or
782
			not blockInSphereIsFull(offset, x + 1, y, z, radiusSq) or
783
			not blockInSphereIsFull(offset, x, y, z - 1, radiusSq) or
784
			not blockInSphereIsFull(offset, x, y, z + 1, radiusSq)
785
	end
786
	return spot
787
end
788
789
function dome(typus, diameter)
790
	-- Main dome and sphere building routine
791
	odd = not (math.fmod(diameter, 2) == 0)
792
	radius = diameter / 2;
793
	if odd then
794
		width = (2 * math.ceil(radius)) + 1;
795
		offset = math.floor(width/2);
796
	else
797
		width = (2 * math.ceil(radius)) + 2;
798
		offset = math.floor(width/2) - 0.5;		
799
	end
800
	--diameter --radius * 2 + 1
801
	sqrt3 = 3 ^ 0.5
802
	boundaryRadius = radius + 1.0
803
	boundary2 = boundaryRadius ^ 2
804
	radius2 = radius ^ 2
805
	
806
	if typus == "dome" then
807
		zstart = math.ceil(radius)
808
	elseif typus == "sphere" then
809
		zstart = 1
810
	elseif typus == "bowl" then
811
		zstart = 1
812
	end
813
	if typus == "bowl" then
814
		zend = math.floor(radius)
815
	else
816
		zend = width - 1
817
	end
818
819
	-- This loop is for each vertical layer through the sphere or dome.
820
	for z = zstart,zend do
821
		if not cost_only and z ~= zstart then
822
			navigateTo(positionX, positionY, positionZ + 1)
823
		end
824
		--writeOut("Layer " .. z)
825
		cz2 = (radius - z) ^ 2
826
		limitOffsetY = (boundary2 - cz2) ^ 0.5
827
		maxOffsetY = math.ceil(limitOffsetY)
828
		-- We do first the +x side, then the -x side to make movement efficient
829
		for side = 0,1 do
830
			-- On the right we go from small y to large y, on the left reversed
831
			-- This makes us travel clockwise (from below) around each layer
832
			if (side == 0) then
833
				yStart = math.floor(radius) - maxOffsetY
834
				yEnd = math.floor(radius) + maxOffsetY
835
				yStep = 1
836
			else
837
				yStart = math.floor(radius) + maxOffsetY
838
				yEnd = math.floor(radius) - maxOffsetY
839
				yStep = -1
840
			end
841
			for y = yStart,yEnd,yStep do
842
				cy2 = (radius - y) ^ 2
843
				remainder2 = (boundary2 - cz2 - cy2)
844
				if remainder2 >= 0 then
845
					-- This is the maximum difference in x from the centre we can be without definitely being outside the radius
846
					maxOffsetX = math.ceil((boundary2 - cz2 - cy2) ^ 0.5)
847
					-- Only do either the +x or -x side
848
					if (side == 0) then
849
						-- +x side
850
						xStart = math.floor(radius)
851
						xEnd = math.floor(radius) + maxOffsetX
852
					else
853
						-- -x side
854
						xStart = math.floor(radius) - maxOffsetX
855
						xEnd = math.floor(radius) - 1
856
					end
857
					-- Reverse direction we traverse xs when in -y side
858
					if y > math.floor(radius) then
859
						temp = xStart
860
						xStart = xEnd
861
						xEnd = temp
862
						xStep = -1
863
					else
864
						xStep = 1
865
					end
866
867
					for x = xStart,xEnd,xStep do
868
						-- Only blocks within the radius but still within 1 3d-diagonal block of the edge are eligible
869
						if isSphereBorder(offset, x, y, z, radius2) then
870
							navigateTo(x, y)
871
							placeBlock()
872
						end
873
					end
874
				end
875
			end
876
		end
877
	end
878
end
879
880
function cylinder(diameter, height)
881
	for i = 1, height do
882
		circle(diameter)
883
		navigateTo(positionX, positionY, positionZ + 1)
884
	end
885
end
886
887
polygonCornerList = {} -- Public list of corner coords for n-gons, will be used for hexagons, octagons, and future polygons.
888
-- It should be constructed as a nested list eg. {{x0,y0},{x1,y1},{x2,y2}...}
889
890
function constructPolygon() -- Uses polygonCornerList to draw sides between each point
891
	if #polygonCornerList == 0 then
892
		return false
893
	end
894
	for i = 1, #polygonCornerList do
895
		startX = polygonCornerList[i][1]
896
		startY = polygonCornerList[i][2]
897
		if i == #polygonCornerList then
898
			j = 1
899
		else
900
			j = i + 1
901
		end
902
		stopX = polygonCornerList[j][1]
903
		stopY = polygonCornerList[j][2]
904
		drawLine(stopX, stopY, startX, startY)
905
	end
906
	return true
907
end
908
909
function arbitraryPolygon(numberOfSides, Radius) -- Future function, this will eventually replace octagon and hexagon functions
910
end
911
912
function hexagon(sideLength) -- Fills out polygonCornerList with the points for a hexagon
913
	sideLength = sideLength - 1
914
	local changeX = sideLength / 2
915
	local changeY = round(math.sqrt(3) * changeX, 0)
916
	changeX = round(changeX, 0)
917
	polygonCornerList[1] = {changeX, 0}
918
	polygonCornerList[2] = {(changeX + sideLength), 0}
919
	polygonCornerList[3] = {((2 * changeX) + sideLength), changeY}
920
	polygonCornerList[4] = {(changeX + sideLength), (2 * changeY)}
921
	polygonCornerList[5] = {changeX, (2 * changeY)}
922
	polygonCornerList[6] = {0, changeY}
923
	if not constructPolygon() then
924
		error("This error should never happen.")
925
	end
926
end
927
928
function octagon(sideLength) -- Fills out polygonCornerList with the points for an octagon
929
	sideLength = sideLength - 1
930
	local change = round((sideLength - 1) / math.sqrt(2), 0)
931
	polygonCornerList[1] = {change, 0}
932
	polygonCornerList[2] = {(change + sideLength), 0}
933
	polygonCornerList[3] = {((2 * change) + sideLength), change}
934
	polygonCornerList[4] = {((2 * change) + sideLength), (change + sideLength)}
935
	polygonCornerList[5] = {(change + sideLength), ((2 * change) + sideLength)}
936
	polygonCornerList[6] = {change, ((2 * change) + sideLength)}
937
	polygonCornerList[7] = {0, (change + sideLength)}
938
	polygonCornerList[8] = {0, change}
939
	if not constructPolygon() then
940
		error("This error should never happen.")
941
	end
942
end
943
944
function sixprism(length, height)
945
	for i = 1, height do
946
		hexagon(length)
947
		if i ~= height then
948
			navigateTo(positionX, positionY, positionZ + 1)
949
		end
950
	end
951
end
952
953
function eightprism(length, height)
954
	for i = 1, height do
955
		octagon(length)
956
		if i ~= height then
957
			navigateTo(positionX, positionY, positionZ + 1)
958
		end
959
	end
960
end
961
962
-- Previous Progress Resuming, Simulation functions, Command Line, and File Backend
963
-- Will check for a "progress" file.
964
function CheckForPrevious() 
965
	if fs.exists(progFileName) then
966
		return true
967
	else
968
		return false
969
	end
970
end
971
972
-- 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)
973
function ProgressFileCreate() 
974
	if not CheckForPrevious() then
975
		fs.makeDir(progFileName)
976
		return true
977
	else
978
		return false
979
	end
980
end
981
982
-- Deletes the progress file (at the end of the project, or at beginning if user chooses to delete old progress)
983
function ProgressFileDelete() 
984
	if fs.exists(progFileName) then
985
		fs.delete(progFileName)
986
		return true
987
	else 
988
		return false
989
	end
990
end
991
992
-- To read the shape params from the file.  Shape type, and input params (e.g. "dome" and radius)
993
function ReadShapeParams()
994
	-- TODO. Unneeded for now, can just use the table elements directly
995
end
996
997
function WriteShapeParams(...) -- The ... lets it take any number of arguments and stores it to the table arg{} | This is still unused anywhere
998
	local paramTable = arg
999
	local paramName = "param"
1000
	local paramName2 = paramName
1001
	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!
1002
		paramName2 = paramName .. i
1003
		tempProgTable[paramName2] = v
1004
		progTable[paramName2] = v
1005
	end
1006
end
1007
1008
-- function to write the progress to the file (x, y, z)
1009
function writeProgress()
1010
	local progFile
1011
	local progString = ""
1012
	if not (sim_mode or cost_only) then
1013
		progString = textutils.serialize(progTable) -- Put in here to save processing time when in cost_only
1014
		progFile = fs.open(progFileName, "w")
1015
		progFile.write(progString)
1016
		progFile.close()
1017
	end
1018
1019
end
1020
1021
-- Reads progress from file (shape, x, y, z, facing, blocks, param1, param2, param3)
1022
function readProgress()
1023
	local progFile = fs.open(progFileName, "r")
1024
	local readProgTable = textutils.unserialize(progFile.readAll())
1025
	progFile.close()
1026
	return readProgTable
1027
end
1028
1029
-- compares the progress read from the file to the current sim progress.  needs all four params 
1030
function compareProgress()
1031
	local progTableIn = progTable
1032
	local readProgTable = readProgress()
1033
	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
1034
		writeOut("All caught up!")
1035
		return true -- We're caught up!
1036
	else
1037
		return false -- Not there yet...
1038
	end
1039
end
1040
1041
function getGPSInfo() -- TODO: finish this
1042
	position = gps.locate()
1043
	gpsPositionX = position.x
1044
	gpsPositionZ = position.y
1045
	gpsPositionY = position.z
1046
	
1047
end
1048
1049
function setSimFlags(b)
1050
	sim_mode = b
1051
	cost_only = b
1052
	if cmd_line_cost_only then
1053
		cost_only = true
1054
	end
1055
end
1056
1057
function simulationCheck() -- checks state of the simulation
1058
	if sim_mode then
1059
		if compareProgress() then
1060
			setSimFlags(false) -- If we're caught up, un-set flags
1061
		else
1062
			setSimFlags(true)  -- If not caught up, just re-affirm that the flags are set
1063
		end
1064
	end
1065
end
1066
1067
function continueQuery()
1068
	if cmd_line_resume then
1069
		 return true
1070
	else
1071
		 if not cmd_line then
1072
			 writeOut("Do you want to continue the last job?")
1073
			 local yes = io.read()
1074
			 if yes == "y" then
1075
				 return true
1076
			 else
1077
				 return false
1078
			 end
1079
		 end
1080
	end
1081
end
1082
1083
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
1084
	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}
1085
	if not sim_mode then 
1086
		writeProgress()
1087
	end
1088
end
1089
1090
 -- Command Line
1091
function checkCommandLine() --True if arguments were passed
1092
	if #argTable > 0 then
1093
		cmd_line = true
1094
		return true
1095
	else
1096
		cmd_line = false
1097
		return false
1098
	end
1099
end
1100
1101
function needsHelp() -- True if -h is passed
1102
	for i, v in pairs(argTable) do
1103
		if v == "-h" or v == "-help" or v == "--help" then
1104
			return true
1105
		else
1106
			return false
1107
		end
1108
	end
1109
end
1110
1111
function setFlagsFromCommandLine() -- Sets count_only, chain_next_shape, and sim_mode
1112
	for i, v in pairs(argTable) do
1113
		if v == "-c" or v == "-cost" or v == "--cost" then
1114
			cost_only = true
1115
			cmd_line_cost_only = true
1116
			writeOut("Cost Only Mode")
1117
		end
1118
		if v == "-z" or v == "-chain" or v == "--chain" then
1119
			chain_next_shape = true
1120
			writeOut("Chained Shape Mode")
1121
		end
1122
		if v == "-r" or v == "-resume" or v == "--resume" then
1123
			cmd_line_resume = true
1124
			writeOut("Resuming")
1125
		end
1126
		if v == "-e" or v == "-ender" or v == "--ender" then
1127
			enderchest_refilling = true
1128
			tempProgTable.enderchest_refilling = true
1129
			writeOut("Enderchest Mode")
1130
		end
1131
		if v == "-g" or v == "-home" or v == "--home" then
1132
			return_to_home = true
1133
			writeOut("Will return home")
1134
		end
1135
	end
1136
end
1137
1138
function setTableFromCommandLine() -- Sets progTable and tempProgTable from command line arguments
1139
	progTable.shape = argTable[1]
1140
	tempProgTable.shape = argTable[1]
1141
	local paramName = "param"
1142
	local paramName2 = paramName
1143
	for i = 2, #argTable do
1144
		local addOn = tostring(i - 1)
1145
		paramName2 = paramName .. addOn
1146
		progTable[paramName2] = argTable[i]
1147
		tempProgTable[paramName2] = argTable[i]
1148
	end
1149
end
1150
1151
-- Menu, Drawing and Main functions
1152
1153
function choiceIsValidShape(choice)
1154
	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"}
1155
	for i = 1, #validShapes do
1156
		if choice == validShapes[i] then
1157
			return true
1158
		end
1159
	end
1160
	return false
1161
end
1162
1163
function choiceFunction()
1164
	if sim_mode == false and cmd_line == false then -- If we are NOT resuming progress
1165
		local page = 1
1166
		choice = io.read()
1167
		choice = string.lower(choice) -- All checks are aginst lower case words so this is to ensure that
1168
		while ((choice == "next") or (choice == "back")) do
1169
			if (choice == "next") then
1170
				if page == 1 then
1171
					writeMenu2()
1172
					page = 2
1173
				else
1174
					writeMenu()
1175
					page = 1
1176
				end
1177
			end
1178
			if (choice == "back") then
1179
				if page == 1 then
1180
					writeMenu2()
1181
					page = 2
1182
				else
1183
					writeMenu()
1184
					page = 1
1185
				end
1186
			end
1187
			choice = io.read()
1188
			choice = string.lower(choice) -- All checks are aginst lower case words so this is to ensure that
1189
		end
1190
		if choice == "end" or choice == "exit" then
1191
			writeOut("Goodbye.")
1192
			return
1193
		end
1194
		if choice == "help" then
1195
			getHelp()
1196
			return
1197
		end
1198
		if choice == "credits" then
1199
			showCredits()
1200
			return
1201
		end
1202
		tempProgTable = {shape = choice}
1203
		progTable = {shape = choice}
1204
		if not choiceIsValidShape(choice) then
1205
			writeOut(choice ..  " is not a valid shape choice.")
1206
			return
1207
		end
1208
		writeOut("Building a "..choice)
1209
		local yes = getInput("string","Want to just calculate the cost?","y","n")
1210
		if yes == 'y' then
1211
			cost_only = true
1212
		end
1213
		local yes = getInput("string","Want turtle to return to start after build?","y","n")
1214
		if yes == 'y' then
1215
			return_to_home = true
1216
		end
1217
		local yes = getInput("string","Want the turtle to refill from enderchest (slot 16)?","y","n")
1218
		if yes == 'y' then
1219
			enderchest_refilling = true
1220
			tempProgTable.enderchest_refilling = true
1221
		end
1222
	elseif sim_mode == true then -- If we ARE resuming progress
1223
		tempProgTable = readProgress()
1224
		choice = tempProgTable.shape
1225
		choice = string.lower(choice) -- All checks are aginst lower case words so this is to ensure that
1226
		enderchest_refilling =  tempProgTable.enderchest_refilling
1227
	elseif cmd_line == true then -- If running from command line
1228
		if needsHelp() then
1229
			showCmdLineHelp()
1230
			return
1231
		end
1232
		choice = tempProgTable.shape
1233
		choice = string.lower(choice) -- All checks are aginst lower case words so this is to ensure that
1234
		enderchest_refilling =  tempProgTable.enderchest_refilling
1235
		writeOut("Building a "..choice)
1236
	end	
1237
	if not cost_only then
1238
		turtle.select(1)
1239
		activeSlot = 1
1240
		if turtle.getItemCount(activeSlot) == 0 then
1241
			if resupply then
1242
				writeOut("Please put building blocks in the first slot.")
1243
			else
1244
				writeOut("Please put building blocks in the first slot (and more if you need them)")
1245
			end
1246
			while turtle.getItemCount(activeSlot) <= 1 do
1247
				os.sleep(.1)
1248
			end
1249
		end
1250
	else
1251
		activeSlot = 1
1252
	end
1253
	-- Shape selection if cascade
1254
	-- Line based shapes
1255
	if choice == "rectangle" then
1256
		local depth = 0
1257
		local width = 0
1258
		if sim_mode == false and cmd_line == false then
1259
			width = getInput("int","How wide does it need to be?")
1260
			depth = getInput("int","How deep does it need to be?")
1261
		elseif sim_mode == true or cmd_line == true then
1262
			width = tempProgTable.param1
1263
			depth = tempProgTable.param2
1264
		end
1265
		tempProgTable.param1 = width
1266
		tempProgTable.param2 = depth
1267
		progTable = {param1 = width, param2 = depth} -- THIS is here because we NEED to update the local table!
1268
		rectangle(width, depth)
1269
	end
1270
	if choice == "square" then
1271
		local sideLength
1272
		if sim_mode == false and cmd_line == false then
1273
			sideLength = getInput("int","How long does each side need to be?")
1274
		elseif sim_mode == true or cmd_line == true then
1275
			sideLength = tempProgTable.param1
1276
		end
1277
		tempProgTable.param1 = sideLength
1278
		progTable = {param1 = sideLength}
1279
		square(sideLength)
1280
	end
1281
	if choice == "line" then
1282
		local startX = 0
1283
		local startY = 0
1284
		local endX = 0
1285
		local endY = 0
1286
		if sim_mode == false and cmd_line == false then
1287
			writeOut("Note that the turtle's starting position is 0, 0.")
1288
			startX = getInput("int","Where does the start X need to be?")
1289
			startY = getInput("int","Where does the start Y need to be?")
1290
			endX = getInput("int","Where does the end X need to be?")
1291
			endY = getInput("int","Where does the end Y need to be?")
1292
		elseif sim_mode == true or cmd_line == true then
1293
			startX = tempProgTable.param1
1294
			startY = tempProgTable.param2
1295
			endX = tempProgTable.param3
1296
			endY = tempProgTable.param4
1297
		end
1298
		tempProgTable.param1 = startX
1299
		tempProgTable.param2 = startY
1300
		tempProgTable.param3 = endX
1301
		tempProgTable.param4 = endY
1302
		progTable = {param1 = startX, param2 = startY, param3 = endX, param4 = endY}
1303
		drawLine(endX, endY, startX, startY)
1304
	end
1305
	if choice == "wall" then
1306
		local depth = 0
1307
		local height = 0
1308
		if sim_mode == false and cmd_line == false then
1309
			depth = getInput("int","How deep does it need to be?")
1310
			height = getInput("int","How high does it need to be?")
1311
		elseif sim_mode == true or cmd_line == true then
1312
			depth = tempProgTable.param1
1313
			height = tempProgTable.param2
1314
		end			
1315
		tempProgTable.param1 = depth
1316
		tempProgTable.param2 = height
1317
		progTable = {param1 = depth, param2 = height}
1318
		wall(depth, height)
1319
	end
1320
	if choice == "platform" then
1321
		local width = 0
1322
		local depth = 0
1323
		if sim_mode == false and cmd_line == false then
1324
			width = getInput("int","How wide does it need to be?")
1325
			depth = getInput("int","How deep does it need to be?")
1326
		elseif sim_mode == true or cmd_line == true then	
1327
			width = tempProgTable.param1		
1328
			depth = tempProgTable.param2
1329
		end		
1330
		tempProgTable.param1 = width
1331
		tempProgTable.param2 = depth
1332
		progTable = {param1 = width, param2 = depth}
1333
		platform(width, depth)
1334
	end
1335
	if choice == "stair" or choice == "stairs" then
1336
		local width = 0
1337
		local height = 0
1338
		if sim_mode == false and cmd_line == false then
1339
			width = getInput("int","How wide does it need to be?")
1340
			height = getInput("int","How high does it need to be?")
1341
		elseif sim_mode == true or cmd_line == true then
1342
			width = tempProgTable.param1
1343
			height = tempProgTable.param2
1344
		end
1345
		tempProgTable.param1 = width
1346
		tempProgTable.param2 = height
1347
		progTable = {param1 = width, param2 = height}
1348
		stair(width, height)
1349
		special_chain = true
1350
	end
1351
	if choice == "cuboid" then
1352
		local width = 0
1353
		local depth = 0
1354
		local height = 0
1355
		local hollow = ""
1356
		if sim_mode == false and cmd_line == false then
1357
			width = getInput("int","How wide does it need to be?")
1358
			depth = getInput("int","How deep does it need to be?")
1359
			height = getInput("int","How high does it need to be?")
1360
			hollow = getInput("string","Does it need to be hollow?","y","n")
1361
		elseif sim_mode == true or cmd_line == true then
1362
			width = tempProgTable.param1
1363
			depth = tempProgTable.param2
1364
			height = tempProgTable.param3
1365
			hollow = tempProgTable.param4
1366
		end
1367
		tempProgTable.param1 = width
1368
		tempProgTable.param2 = depth
1369
		tempProgTable.param3 = height
1370
		tempProgTable.param4 = hollow	
1371
		progTable = {param1 = width, param2 = depth, param3 = height}
1372
		cuboid(width, depth, height, hollow)
1373
	end
1374
	if choice == "pyramid" then
1375
		local length = 0
1376
		local hollow = ""
1377
		if sim_mode == false and cmd_line == false then
1378
			length = getInput("int","How long does each side of the base layer need to be?")
1379
			hollow = getInput("string","Does it need to be hollow?","y","n")
1380
		elseif sim_mode == true or cmd_line == true then
1381
			length = tempProgTable.param1
1382
			hollow = tempProgTable.param2
1383
		end
1384
		tempProgTable.param1 = length
1385
		tempProgTable.param2 = hollow
1386
		progTable = {param1 = length, param2 = hollow}
1387
		pyramid(length, hollow)
1388
	end
1389
	-- Circle based shapes
1390
	if choice == "1/2-sphere" or choice == "1/2 sphere" then
1391
		local diameter = 0
1392
		local half = ""
1393
		if sim_mode == false and cmd_line == false then
1394
			diameter = getInput("int","What diameter does it need to be?")
1395
			half = getInput("string","What half of the sphere does it need to be?","bottom","top")
1396
		elseif sim_mode == true or cmd_line == true then
1397
			diameter = tempProgTable.param1
1398
			half = tempProgTable.param2
1399
		end	
1400
		tempProgTable.param1 = diameter
1401
		tempProgTable.param2 = half
1402
		progTable = {param1 = diameter, param2 = half}
1403
		if half == "bottom" then
1404
			dome("bowl", diameter)
1405
		elseif half == "top" then
1406
			dome("dome", diameter)
1407
		end
1408
	end
1409
	if choice == "dome" then
1410
		local diameter = 0
1411
		if sim_mode == false and cmd_line == false then
1412
			diameter = getInput("int","What diameter does it need to be?")
1413
		elseif sim_mode == true or cmd_line == true then
1414
			diameter = tempProgTable.param1
1415
		end	
1416
		tempProgTable.param1 = diameter
1417
		progTable = {param1 = diameter}
1418
		dome("dome", diameter)
1419
	end
1420
	if choice == "bowl" then
1421
		local diameter = 0
1422
		if sim_mode == false and cmd_line == false then
1423
			diameter = getInput("int","What diameter does it need to be?")
1424
		elseif sim_mode == true or cmd_line == true then
1425
			diameter = tempProgTable.param1
1426
		end	
1427
		tempProgTable.param1 = diameter
1428
		progTable = {param1 = diameter}
1429
		dome("bowl", diameter)
1430
	end
1431
	if choice == "sphere" then
1432
		local diameter = 0
1433
		if sim_mode == false and cmd_line == false then
1434
			diameter = getInput("int","What diameter does it need to be?")
1435
		elseif sim_mode == true or cmd_line == true then
1436
			diameter = tempProgTable.param1
1437
		end
1438
		tempProgTable.param1 = diameter
1439
		progTable = {param1 = diameter}
1440
		dome("sphere", diameter)
1441
	end
1442
	if choice == "circle" then
1443
		local diameter = 0
1444
		if sim_mode == false and cmd_line == false then
1445
			diameter = getInput("int","What diameter does it need to be?")
1446
		elseif sim_mode == true or cmd_line == true then
1447
			diameter = tempProgTable.param1
1448
		end
1449
		tempProgTable.param1 = diameter
1450
		progTable = {param1 = diameter}
1451
		circle(diameter)
1452
	end
1453
	if choice == "cylinder" then
1454
		local diameter = 0
1455
		local height = 0
1456
		if sim_mode == false and cmd_line == false then
1457
			diameter = getInput("int","What diameter does it need to be?")
1458
			height = getInput("int","How high does it need to be?")
1459
		elseif sim_mode == true or cmd_line == true then
1460
			diameter = tempProgTable.param1
1461
			height = tempProgTable.param2
1462
		end
1463
		tempProgTable.param1 = diameter
1464
		tempProgTable.param2 = height
1465
		progTable = {param1 = diameter, param2 = height}
1466
		cylinder(diameter, height)
1467
	end
1468
	-- Polygon shapes
1469
	if choice == "hexagon" then
1470
		local length = 0
1471
		if sim_mode == false and cmd_line == false then
1472
			length = getInput("int","How long does each side need to be?")
1473
		elseif sim_mode == true or cmd_line == true then
1474
			length = tempProgTable.param1
1475
		end
1476
		tempProgTable.param1 = length
1477
		progTable = {param1 = length}
1478
		hexagon(length)
1479
	end
1480
	if choice == "octagon" then
1481
		local length = 0
1482
		if sim_mode == false and cmd_line == false then
1483
			length = getInput("int","How long does each side need to be?")
1484
		elseif sim_mode == true or cmd_line == true then
1485
			length = tempProgTable.param1
1486
		end
1487
		tempProgTable.param1 = length
1488
		progTable = {param1 = length}
1489
		octagon(length)
1490
	end
1491
	if choice == "6-prism" or choice == "6 prism" then
1492
		local length = 0
1493
		local height = 0
1494
		if sim_mode == false and cmd_line == false then
1495
			length = getInput("int","How long does each side need to be?")
1496
			height = getInput("int","How high does it need to be?")
1497
		elseif sim_mode == true or cmd_line == true then
1498
			length = tempProgTable.param1
1499
			height = tempProgTable.param2
1500
		end
1501
		tempProgTable.param1 = length
1502
		tempProgTable.param2 = height
1503
		progTable = {param1 = length, param2 = height}
1504
		sixprism(length, height)
1505
	end
1506
	if choice == "8-prism" or choice == "8 prism" then
1507
		local length = 0
1508
		local height = 0
1509
		if sim_mode == false and cmd_line == false then
1510
			length = getInput("int","How long does each side need to be?")
1511
			height = getInput("int","How high does it need to be?")
1512
		elseif sim_mode == true or cmd_line == true then
1513
			length = tempProgTable.param1
1514
			height = tempProgTable.param2
1515
		end
1516
		tempProgTable.param1 = length
1517
		tempProgTable.param2 = height
1518
		progTable = {param1 = length, param2 = height}
1519
		eightprism(length, height)
1520
	end
1521
	if return_to_home then
1522
		goHome() -- After all shape building has finished
1523
	end
1524
	writeOut("Done") -- Saves a few lines when put here rather than in each if statement
1525
end
1526
1527
function writeMenu()
1528
	term.clear()
1529
	term.setCursorPos(1, 1)
1530
	writeOut("Shape Maker 1.7 by Keridos/CupricWolf/pokemane")
1531
	if resupply then					-- Any ideas to make this more compact/better looking (in terms of code)?
1532
		writeOut("Resupply Mode Active")
1533
	elseif (resupply and can_use_gps) then
1534
		writeOut("Resupply and GPS Mode Active")
1535
	elseif can_use_gps then
1536
		writeOut("GPS Mode Active")
1537
	else
1538
		writeOut("Standard Mode Active")
1539
	end
1540
	if not cmd_line then
1541
		writeOut("What shape do you want to build? [page 1/2]");
1542
		writeOut("next for page 2")
1543
		writeOut("+---------+-----------+-------+-------+")
1544
		writeOut("| square  | rectangle | wall  | line  |")
1545
		writeOut("| cylinder| platform  | stair | cuboid|")
1546
		writeOut("| pyramid | 1/2-sphere| sphere| circle|")
1547
		writeOut("+---------+-----------+-------+-------+")
1548
		writeOut("")
1549
	end
1550
end
1551
1552
function writeMenu2()
1553
	term.clear()
1554
	term.setCursorPos(1, 1)
1555
	writeOut("Shape Maker 1.7 by Keridos/CupricWolf/pokemane")
1556
	if resupply then					-- Any ideas to make this more compact/better looking (in terms of code)?
1557
		writeOut("Resupply Mode Active")
1558
	elseif (resupply and can_use_gps) then
1559
		writeOut("Resupply and GPS Mode Active")
1560
	elseif can_use_gps then
1561
		writeOut("GPS Mode Active")
1562
	else
1563
		writeOut("Standard Mode Active")
1564
	end
1565
	writeOut("What shape do you want to build? [page 2/2]");
1566
	writeOut("back for page 1")
1567
	writeOut("+---------+-----------+-------+-------+")
1568
	writeOut("| hexagon | octagon   | dome  |       |")
1569
	writeOut("| 6-prism | 8-prism   | bowl  |       |")
1570
	writeOut("| help    | credits   | end   |       |")
1571
	writeOut("+---------+-----------+-------+-------+")
1572
	writeOut("")
1573
end
1574
1575
function showCmdLineHelp()
1576
	term.clear()
1577
	term.setCursorPos(1, 1)
1578
	writeOut("Command line help")
1579
	writeOut("Usage: shape [shape-type] [param1] [param2] [param3] [param4] [-c] [-h] [-z] [-r]\n")
1580
	writeOut("-c or -cost or --cost: Activate cost only mode\n")
1581
	writeOut("-h or -help or --help: Show this information")
1582
	io.read()
1583
	writeOut("-z or -chain or --chain: Lets you chain together multiple shapes\n")
1584
	writeOut("-g or -home or --home: Make turtle go 'home' after build\n")
1585
	writeOut("-r or -resume or --resume: Resume the last build if possible")
1586
	io.read()
1587
	writeOut("-e or -ender or --ender: Activate enderchest refilling\n")
1588
	writeOut("shape-type can be any of the shapes in the menu\n")
1589
	writeOut("After shape-type input all of the paramaters for the shape, varies by shape\n")
1590
	writeOut("Put any flags (-c, -h, etc.) at the end of your command")
1591
end
1592
1593
function getHelp()
1594
	term.clear()
1595
	term.setCursorPos(1, 1)
1596
	writeOut("Width is to the right of the turtle. (X-Axis)")
1597
	writeOut("Depth is to the front of the turtle. (Y-Axis)")
1598
	writeOut("Height is to the top of the turtle. (Z-Axis)")
1599
	writeOut("Length is the side length of some shapes. (Squares and Polygons)")
1600
	io.read()
1601
	term.clear()
1602
	term.setCursorPos(1, 1)
1603
	local page = 1
1604
	writeOut("What shape do you want help with? [page 1/2]");
1605
	writeOut("next for page 2")
1606
	writeOut("+---------+-----------+-------+-------+")
1607
	writeOut("| square  | rectangle | wall  | line  |")
1608
	writeOut("| cylinder| platform  | stair | cuboid|")
1609
	writeOut("| pyramid | 1/2-sphere| sphere| circle|")
1610
	writeOut("+---------+-----------+-------+-------+")
1611
	writeOut("")
1612
	choice = io.read()
1613
	choice = string.lower(choice)
1614
	while ((choice == "next") or (choice == "back")) do
1615
		if (choice == "next") then
1616
			if (page == 1) then
1617
				page = 2
1618
				term.clear()
1619
				term.setCursorPos(1, 1)
1620
				writeOut("What shape do you want help wih? [page 2/2]?");
1621
				writeOut("back for page 1")
1622
				writeOut("+---------+-----------+-------+-------+")
1623
				writeOut("| hexagon | octagon   | dome  |       |")
1624
				writeOut("| 6-prism | 8-prism   | bowl  |       |")
1625
				writeOut("|         |           |       |       |")
1626
				writeOut("+---------+-----------+-------+-------+")
1627
				writeOut("")
1628
			else
1629
				page = 1
1630
				term.clear()
1631
				term.setCursorPos(1, 1)
1632
				writeOut("What shape do you want help with? [page 1/2]");
1633
				writeOut("next for page 2")
1634
				writeOut("+---------+-----------+-------+-------+")
1635
				writeOut("| square  | rectangle | wall  | line  |")
1636
				writeOut("| cylinder| platform  | stair | cuboid|")
1637
				writeOut("| pyramid | 1/2-sphere| sphere| circle|")
1638
				writeOut("+---------+-----------+-------+-------+")
1639
				writeOut("")
1640
			end
1641
		end
1642
		if (choice == "back") then
1643
			if (page == 1) then
1644
				page = 2
1645
				term.clear()
1646
				term.setCursorPos(1, 1)
1647
				writeOut("What shape do you want help wih? [page 2/2]?");
1648
				writeOut("back for page 1")
1649
				writeOut("+---------+-----------+-------+-------+")
1650
				writeOut("| hexagon | octagon   | dome  |       |")
1651
				writeOut("| 6-prism | 8-prism   | bowl  |       |")
1652
				writeOut("|         |           |       |       |")
1653
				writeOut("+---------+-----------+-------+-------+")
1654
				writeOut("")
1655
			else
1656
				page = 1
1657
				term.clear()
1658
				term.setCursorPos(1, 1)
1659
				writeOut("What shape do you want help with? [page 1/2]");
1660
				writeOut("next for page 2")
1661
				writeOut("+---------+-----------+-------+-------+")
1662
				writeOut("| square  | rectangle | wall  | line  |")
1663
				writeOut("| cylinder| platform  | stair | cuboid|")
1664
				writeOut("| pyramid | 1/2-sphere| sphere| circle|")
1665
				writeOut("+---------+-----------+-------+-------+")
1666
				writeOut("")
1667
			end
1668
		end
1669
		choice = io.read()
1670
		choice = string.lower(choice) 
1671
	end
1672
	if not choiceIsValidShape(choice) then
1673
		writeOut(choice ..  " is not a valid shape choice.")
1674
		return
1675
	end
1676
	-- If cascade time!
1677
	if choice == "rectangle" then
1678
		term.clear()
1679
		term.setCursorPos(1, 1)
1680
		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.")
1681
	end
1682
	if choice == "square" then
1683
		term.clear()
1684
		term.setCursorPos(1, 1)
1685
		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.")
1686
	end
1687
	if choice == "line" then
1688
		term.clear()
1689
		term.setCursorPos(1, 1)
1690
		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.")
1691
	end
1692
	if choice == "wall" then
1693
		term.clear()
1694
		term.setCursorPos(1, 1)
1695
		writeOut("The wall is a vertical plane. The wall takes two parameters (two integers) Depth then Height.")
1696
	end
1697
	if choice == "platform" then
1698
		term.clear()
1699
		term.setCursorPos(1, 1)
1700
		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.")
1701
	end
1702
	if choice == "stair" or choice == "stairs" then
1703
		term.clear()
1704
		term.setCursorPos(1, 1)
1705
		writeOut("The stair or stairs are an incline of width by height. The stair takes two parameters (two integers) Width then Height.")
1706
	end
1707
	if choice == "cuboid" then
1708
		term.clear()
1709
		term.setCursorPos(1, 1)
1710
		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).")
1711
	end
1712
	if choice == "1/2-sphere" or choice == "1/2 sphere" then
1713
		term.clear()
1714
		term.setCursorPos(1, 1)
1715
		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).")
1716
	end
1717
	if choice == "dome" then
1718
		term.clear()
1719
		term.setCursorPos(1, 1)
1720
		writeOut("The dome shape is a shortcut to the top half sphere. The dome takes one parameter (one integer) Diameter.")
1721
	end
1722
	if choice == "bowl" then
1723
		term.clear()
1724
		term.setCursorPos(1, 1)
1725
		writeOut("The bowl shape is a shortcut to the bottom half sphere. The bowl takes one parameter (one integer) Diameter.")
1726
	end
1727
	if choice == "sphere" then
1728
		term.clear()
1729
		term.setCursorPos(1, 1)
1730
		writeOut("The sphere is just that, a sphere. It is hollow. The sphere takes one parameter (one integer) Diameter.")
1731
	end
1732
	if choice == "circle" then
1733
		term.clear()
1734
		term.setCursorPos(1, 1)
1735
		writeOut("The circle is just that, a circle. It is just a perimeter. The circle takes one parameter (one integer) Diameter.")
1736
	end
1737
	if choice == "cylinder" then
1738
		term.clear()
1739
		term.setCursorPos(1, 1)
1740
		writeOut("The cylinder is a cylindrical tube of diameter by height. The cylinder takes two parameters (two integers) Diameter then Height.")
1741
	end
1742
	if choice == "pyramid" then
1743
		term.clear()
1744
		term.setCursorPos(1, 1)
1745
		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).")
1746
	end
1747
	if choice == "hexagon" then
1748
		term.clear()
1749
		term.setCursorPos(1, 1)
1750
		writeOut("The hexagon is a hexagonal perimeter. The hexagon takes one parameter (one integer) Length.")
1751
	end
1752
	if choice == "octagon" then
1753
		term.clear()
1754
		term.setCursorPos(1, 1)
1755
		writeOut("The octagon is and octagonal perimeter. The octagon takes one parameter (one integer) Length.")
1756
	end
1757
	if choice == "6-prism" or choice == "6 prism" then
1758
		term.clear()
1759
		term.setCursorPos(1, 1)
1760
		writeOut("The 6 prism is a hexagonal prism shaped tube. The 6 prism takes two parameters (two integers) Length then Height.")
1761
	end
1762
	if choice == "8-prism" or choice == "8 prism" then
1763
		term.clear()
1764
		term.setCursorPos(1, 1)
1765
		writeOut("The 8 prism is an octagonal prism shaped tube. The 8 prism takes two parameters (two integers) Length then Height.")
1766
	end
1767
end
1768
1769
function showCredits()
1770
	term.clear()
1771
	term.setCursorPos(1, 1)
1772
	writeOut("Credits for the shape builder:")
1773
	writeOut("Based on work by Michiel, Vliekkie, and Aeolun")
1774
	writeOut("Sphere/dome code by IMarvinTPA")
1775
	writeOut("Additional improvements by Keridos, CupricWolf, and pokemane")
1776
end
1777
1778
function main()
1779
	if wrapModules()=="resupply" then
1780
		linkToRSStation()
1781
	end
1782
	if checkCommandLine() then
1783
		if needsHelp() then
1784
			showCmdLineHelp()
1785
			return -- Close the program after help info is shown
1786
		end
1787
		setFlagsFromCommandLine()
1788
		setTableFromCommandLine()
1789
	end
1790
	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
1791
		if not continueQuery() then -- If the user doesn't want to continue
1792
			ProgressFileDelete()
1793
			setSimFlags(false) -- Just to be safe
1794
			writeMenu()
1795
			choiceFunction()
1796
		else	-- If the user wants to continue
1797
			setSimFlags(true)
1798
			choiceFunction()
1799
		end
1800
	else
1801
		setSimFlags(false)
1802
		writeMenu()
1803
		choiceFunction()
1804
	end
1805
	if (blocks ~= 0) and (fuel ~= 0) then -- Do not show on help or credits page or when selecting end
1806
		writeOut("Blocks used: " .. blocks)
1807
		writeOut("Fuel used: " .. fuel)
1808
	end
1809
	ProgressFileDelete() -- Removes file upon successful completion of a job, or completion of a previous job.
1810
	progTable = {}
1811
	tempProgTable = {}
1812
end
1813
1814
main()