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