turtlogenesis.lua

1600 lines · 44.3 KB

Open raw

MerlinLikeTheWizard

Copy & run

wget https://perlytiara.github.io/turtles.tips/raw/programs/MerlinLikeTheWizard/turtlogenesis.lua
1-- MerlinLikeTheWizard
2
3TITLE = {
4 ' ##### ## ## ##### ##### ### #####',
5 ' ##### ## ## ##### ##### ### #####',
6 ' ### ## ## ## ## ### ### ## ##',
7 ' ### ##### #### ### ##### #####',
8 ' ### ##### ## ## ### ##### #####',
9 '',
10 '##### ##### # ## ##### ##### ### #####',
11 '##### ## ## ## ## ## ##',
12 '## #### ##### #### ##### ### #####',
13 '## ## ## ## ## ## ## ### ##',
14 '##### ##### ## # ##### ##### ### #####',
15}
16
17-------------------------------------------+
18
19VEIN_MAX = 64
20FUEL_BAR = 20
21START_FUEL = 640
22TRAVEL_FUEL = 1280
23TRAVEL_FUEL_MIN = 400
24HOUSEKEEP_FREQUENCY = 10
25
26-------------------------------------------+
27
28local pretty = require "cc.pretty"
29pprint = pretty.pretty_print
30
31CRAFTING_SLOTS = {1, 2, 3, 5, 6, 7, 9, 10, 11}
32NON_CRAFTING_SLOTS = {4, 8, 12, 13, 14, 15, 16}
33
34CRAFTING_RECIPES = {
35 ['minecraft:crafting_table'] = {
36 'planks', 'planks', nil,
37 'planks', 'planks',
38 },
39 ['minecraft:stick'] = {
40 'planks', nil, nil,
41 'planks',
42 },
43 ['minecraft:furnace'] = {
44 'minecraft:cobblestone', 'minecraft:cobblestone', 'minecraft:cobblestone',
45 'minecraft:cobblestone', nil, 'minecraft:cobblestone',
46 'minecraft:cobblestone', 'minecraft:cobblestone', 'minecraft:cobblestone',
47 },
48 ['minecraft:chest'] = {
49 'planks', 'planks', 'planks',
50 'planks', nil, 'planks',
51 'planks', 'planks', 'planks',
52 },
53 ['minecraft:diamond_pickaxe'] = {
54 'minecraft:diamond', 'minecraft:diamond', 'minecraft:diamond',
55 nil, 'minecraft:stick', nil,
56 nil, 'minecraft:stick',
57 },
58 ['minecraft:glass_pane'] = {
59 'minecraft:glass', 'minecraft:glass', 'minecraft:glass',
60 'minecraft:glass', 'minecraft:glass', 'minecraft:glass',
61 },
62 ['minecraft:paper'] = {
63 'minecraft:sugar_cane', 'minecraft:sugar_cane', 'minecraft:sugar_cane',
64 },
65 ['computercraft:disk_drive'] = {
66 'minecraft:stone', 'minecraft:stone', 'minecraft:stone',
67 'minecraft:stone', 'minecraft:redstone', 'minecraft:stone',
68 'minecraft:stone', 'minecraft:redstone', 'minecraft:stone',
69 },
70 ['computercraft:turtle_normal'] = {
71 'minecraft:iron_ingot', 'minecraft:iron_ingot', 'minecraft:iron_ingot',
72 'minecraft:iron_ingot', 'computercraft:computer_normal', 'minecraft:iron_ingot',
73 'minecraft:iron_ingot', 'minecraft:chest', 'minecraft:iron_ingot',
74 },
75 ['computercraft:computer_normal'] = {
76 'minecraft:stone', 'minecraft:stone', 'minecraft:stone',
77 'minecraft:stone', 'minecraft:redstone', 'minecraft:stone',
78 'minecraft:stone', 'minecraft:glass_pane', 'minecraft:stone',
79 },
80 ['computercraft:disk'] = {
81 'minecraft:paper', 'minecraft:redstone',
82 },
83 ['mining_crafty_turtle'] = {
84 'minecraft:diamond_pickaxe', 'computercraft:turtle_normal', 'minecraft:crafting_table',
85 },
86 ['planks'] = {
87 'log'
88 }
89}
90
91CRAFTING_TREE = {
92 ['computercraft:turtle_normal'] = {count = 1, components = {
93 ['computercraft:computer_normal'] = {count = 1, components = {
94 ['minecraft:stone'] = {count = 7, components = {
95 ['minecraft:cobblestone'] = {count = 1, subterranean = true},
96 }},
97 ['minecraft:redstone'] = {count = 1, components = {
98 ['minecraft:redstone_ore'] = {count = 1, subterranean = true},
99 }},
100 ['minecraft:glass_pane'] = {count = 1, components = {
101 ['minecraft:glass'] = {count = 6, components = {
102 ['minecraft:sand'] = {count = 1, subterranean = false},
103 }},
104 }},
105 }},
106 ['minecraft:iron_ingot'] = {count = 7, components = {
107 ['minecraft:raw_iron'] = {count = 1, components = {
108 ['minecraft:iron_ore'] = {count = 1, subterranean = true},
109 }},
110 }},
111 ['minecraft:chest'] = {count = 1, components = {
112 ['planks'] = {count = 8, components = {
113 ['log'] = {count = 0.25, subterranean = false},
114 }},
115 }},
116 }},
117 ['minecraft:diamond_pickaxe'] = {count = 1, components = {
118 ['minecraft:diamond'] = {count = 3, components = {
119 ['minecraft:diamond_ore'] = {count = 1, subterranean = true},
120 }},
121 ['minecraft:stick'] = {count = 2, components = {
122 ['planks'] = {count = 1, components = {
123 ['log'] = {count = 0.25, subterranean = false},
124 }},
125 }},
126 }},
127 ['minecraft:crafting_table'] = {count = 1, components = {
128 ['planks'] = {count = 4, components = {
129 ['log'] = {count = 0.25, subterranean = false},
130 }},
131 }},
132 ['computercraft:disk_drive'] = {count = 1, components = {
133 ['minecraft:stone'] = {count = 7, components = {
134 ['minecraft:cobblestone'] = {count = 1, subterranean = true},
135 }},
136 ['minecraft:redstone'] = {count = 2, components = {
137 ['minecraft:redstone_ore'] = {count = 1, subterranean = true},
138 }},
139 }},
140 ['computercraft:disk'] = {count = 1, components = {
141 ['minecraft:redstone'] = {count = 1, components = {
142 ['minecraft:redstone_ore'] = {count = 1, subterranean = true},
143 }},
144 ['minecraft:paper'] = {count = 1, components = {
145 ['minecraft:dirt'] = {count = 1, subterranean = false},
146 ['minecraft:sugar_cane'] = {count = 1, subterranean = false},
147 }},
148 }},
149 ['minecraft:chest'] = {count = 2, components = {
150 ['planks'] = {count = 8, components = {
151 ['log'] = {count = 0.25, subterranean = false},
152 }},
153 }},
154 ['minecraft:furnace'] = {count = 3, components = {
155 ['minecraft:cobblestone'] = {count = 8, subterranean = true},
156 }},
157 ['minecraft:coal'] = {count = 16, components = {
158 ['minecraft:coal_ore'] = {count = 1, subterranean = true},
159 }},
160}
161
162ORE_PRIORITY = {
163 'minecraft:diamond_ore',
164 'minecraft:redstone_ore',
165 'minecraft:iron_ore',
166 'minecraft:coal_ore',
167 'minecraft:cobblestone'
168}
169
170ORE_DEPTH = {
171 ['minecraft:diamond_ore'] = -57,
172 ['minecraft:redstone_ore'] = -57,
173 ['minecraft:iron_ore'] = 15,
174 ['minecraft:coal_ore'] = 30,
175 ['minecraft:cobblestone'] = 15
176}
177
178ORE_ITEMS = {
179 ['minecraft:deepslate_diamond_ore'] = 'minecraft:diamond_ore',
180 ['minecraft:deepslate_redstone_ore'] = 'minecraft:redstone_ore',
181 ['minecraft:deepslate_iron_ore'] = 'minecraft:iron_ore',
182 ['minecraft:deepslate_coal_ore'] = 'minecraft:coal_ore',
183 ['minecraft:deepslate_cobblestone'] = 'minecraft:cobblestone'
184}
185
186NEEDED_ITEMS = {}
187function flattenTree(tree, items)
188 for item_name, item_details in pairs(tree) do
189 items[item_name] = true
190 if item_details.components then
191 flattenTree(item_details.components, items)
192 end
193 end
194end
195flattenTree(CRAFTING_TREE, NEEDED_ITEMS)
196
197LOG_ITEMS = {
198 ['minecraft:oak_log'] = true,
199 ['minecraft:spruce_log'] = true,
200 ['minecraft:birch_log'] = true,
201 ['minecraft:jungle_log'] = true,
202 ['minecraft:acacia_log'] = true,
203 ['minecraft:dark_oak_log'] = true,
204}
205
206PLANKS_ITEMS = {
207 ['minecraft:oak_planks'] = true,
208 ['minecraft:spruce_planks'] = true,
209 ['minecraft:birch_planks'] = true,
210 ['minecraft:jungle_planks'] = true,
211 ['minecraft:acacia_planks'] = true,
212 ['minecraft:dark_oak_planks'] = true,
213}
214
215LEAVES_ITEMS = {
216 ['minecraft:oak_leaves'] = true,
217 ['minecraft:spruce_leaves'] = true,
218 ['minecraft:birch_leaves'] = true,
219 ['minecraft:jungle_leaves'] = true,
220 ['minecraft:acacia_leaves'] = true,
221 ['minecraft:dark_oak_leaves'] = true,
222}
223
224BUMPS = {
225 north = { 0, 0, -1},
226 south = { 0, 0, 1},
227 east = { 1, 0, 0},
228 west = {-1, 0, 0},
229}
230
231LEFT_SHIFT = {
232 north = 'west',
233 south = 'east',
234 east = 'north',
235 west = 'south',
236}
237
238RIGHT_SHIFT = {
239 north = 'east',
240 south = 'west',
241 east = 'south',
242 west = 'north',
243}
244
245REVERSE_SHIFT = {
246 north = 'south',
247 south = 'north',
248 east = 'west',
249 west = 'east',
250}
251
252MOVE = {
253 forward = turtle.forward,
254 up = turtle.up,
255 down = turtle.down,
256 back = turtle.back,
257 left = turtle.turnLeft,
258 right = turtle.turnRight
259}
260
261DETECT = {
262 forward = turtle.detect,
263 up = turtle.detectUp,
264 down = turtle.detectDown
265}
266
267INSPECT = {
268 forward = turtle.inspect,
269 up = turtle.inspectUp,
270 down = turtle.inspectDown
271}
272
273DIG = {
274 forward = turtle.dig,
275 up = turtle.digUp,
276 down = turtle.digDown
277}
278
279PLACE = {
280 forward = turtle.place,
281 up = turtle.placeUp,
282 down = turtle.placeDown
283}
284
285ATTACK = {
286 forward = turtle.attack,
287 up = turtle.attackUp,
288 down = turtle.attackDown
289}
290
291VOWELS = {
292 'a', 'a', 'a', 'a', 'a',
293 'e', 'e', 'e', 'e', 'e', 'e',
294 'i', 'i', 'i',
295 'o', 'o', 'o',
296 'u', 'u',
297 'y',
298}
299CONSONANTS = {
300 'b', 'b', 'b', 'b', 'b', 'b', 'b',
301 'c', 'c', 'c', 'c', 'c', 'c', 'c',
302 'd', 'd', 'd', 'd', 'd',
303 'f', 'f', 'f', 'f', 'f',
304 'g', 'g', 'g', 'g',
305 'h', 'h', 'h',
306 'j',
307 'k', 'k',
308 'l', 'l', 'l', 'l', 'l',
309 'm', 'm', 'm', 'm', 'm', 'm', 'm',
310 'n', 'n', 'n', 'n', 'n', 'n', 'n',
311 'p', 'p', 'p', 'p', 'p',
312 'r', 'r', 'r', 'r', 'r', 'r', 'r',
313 's', 's', 's', 's', 's', 's', 's', 's', 's',
314 't', 't', 't', 't', 't', 't', 't',
315 'v',
316 'w',
317 'x',
318 'y',
319 'z', 'z', 'z',
320}
321DOUBLES = {
322 'bl', 'br', 'bw',
323 'cr', 'cl',
324 'dr', 'dw',
325 'fr', 'fl', 'fw',
326 'gr', 'gl', 'gw', 'gh',
327 'kr', 'kl', 'kw',
328 'mw',
329 'ng',
330 'pr', 'pl',
331 'qu',
332 'sr', 'sl', 'sw', 'st', 'sh',
333 'tr', 'tl', 'tw', 'th',
334 'vr', 'vl',
335 'wr',
336}
337CONS_DOUB = {}
338for _, c in pairs(CONSONANTS) do
339 table.insert(CONS_DOUB, c)
340end
341for _, c in pairs(DOUBLES) do
342 table.insert(CONS_DOUB, c)
343end
344
345
346function genRandName()
347 local name = ''
348 local count = math.random(3, 6)
349
350 for i = 0, count - 1 do
351 if i % 2 == 1 then
352 name = name .. VOWELS[math.random(#VOWELS)]
353 else
354 if (i == count-1) then
355 name = name .. CONSONANTS[math.random(#CONSONANTS)]
356 else
357 name = name .. CONS_DOUB[math.random(#CONS_DOUB)]
358 end
359 end
360 end
361
362 return string.upper(name:sub(1, 1)) .. name:sub(2, -1)
363end
364
365
366function nameTurtle()
367 if not os.getComputerLabel() then
368 os.setComputerLabel(genRandName())
369 end
370end
371
372
373location = {x = 0, y = 0, z = 0}
374orientation = 'north'
375calibrated = false
376
377
378function go(direction, nodig)
379 if not nodig then
380 if DETECT[direction] then
381 if DETECT[direction]() then
382 DIG[direction]()
383 end
384 end
385 end
386 if not MOVE[direction] then
387 return false
388 end
389 if not MOVE[direction]() then
390 if ATTACK[direction] then
391 ATTACK[direction]()
392 end
393 return false
394 end
395 logMovement(direction)
396 return true
397end
398
399
400function goAbsolute(direction)
401 while not go(direction) do end
402end
403
404
405function logMovement(direction)
406 if direction == 'up' then
407 location.y = location.y + 1
408 elseif direction == 'down' then
409 location.y = location.y - 1
410 elseif direction == 'forward' then
411 bump = BUMPS[orientation]
412 location = {x = location.x + bump[1], y = location.y + bump[2], z = location.z + bump[3]}
413 elseif direction == 'back' then
414 bump = BUMPS[orientation]
415 location = {x = location.x - bump[1], y = location.y - bump[2], z = location.z - bump[3]}
416 elseif direction == 'left' then
417 orientation = LEFT_SHIFT[orientation]
418 elseif direction == 'right' then
419 orientation = RIGHT_SHIFT[orientation]
420 end
421 return true
422end
423
424
425function followRoute(route)
426 for step in route:gmatch'.' do
427 if step == 'u' then
428 goAbsolute('up')
429 elseif step == 'f' then
430 goAbsolute('forward')
431 elseif step == 'd' then
432 goAbsolute('down')
433 elseif step == 'b' then
434 goAbsolute('back')
435 elseif step == 'l' then
436 goAbsolute('left')
437 elseif step == 'r' then
438 goAbsolute('right')
439 end
440 end
441 return true
442end
443
444
445function face(new_orientation)
446 if orientation == new_orientation then
447 return true
448 elseif RIGHT_SHIFT[orientation] == new_orientation then
449 if not go('right') then return false end
450 elseif LEFT_SHIFT[orientation] == new_orientation then
451 if not go('left') then return false end
452 elseif RIGHT_SHIFT[RIGHT_SHIFT[orientation]] == new_orientation then
453 if not go('right') then return false end
454 if not go('right') then return false end
455 else
456 return false
457 end
458 return true
459end
460
461
462function getAdjacentBlock(direction, loc, ori)
463 if not loc then loc = location end
464 if not ori then ori = orientation end
465 if direction == 'up' then
466 return {x = loc.x, y = loc.y + 1, z = loc.z}
467 elseif direction == 'down' then
468 return {x = loc.x, y = loc.y - 1, z = loc.z}
469 elseif direction == 'forward' then
470 local bump = BUMPS[ori]
471 return {x = loc.x + bump[1], y = loc.y + bump[2], z = loc.z + bump[3]}
472 elseif direction == 'back' then
473 local bump = BUMPS[ori]
474 return {x = loc.x - bump[1], y = loc.y - bump[2], z = loc.z - bump[3]}
475 elseif direction == 'left' then
476 local bump = BUMPS[LEFT_SHIFT[ori]]
477 return {x = loc.x + bump[1], y = loc.y + bump[2], z = loc.z + bump[3]}
478 elseif direction == 'right' then
479 local bump = BUMPS[RIGHT_SHIFT[ori]]
480 return {x = loc.x + bump[1], y = loc.y + bump[2], z = loc.z + bump[3]}
481 end
482end
483
484
485function getFromChest(wanted_items)
486 local slot = 1
487 local unwanted = {}
488 local remaining_count = 0
489 for _, _ in pairs(wanted_items) do
490 remaining_count = remaining_count + 1
491 end
492
493 while slot <= 16 and remaining_count > 0 do
494 if turtle.getItemCount(slot) == 0 then
495 turtle.select(slot)
496 if not turtle.suck() then break end
497 local item_name = interpretItemName(turtle.getItemDetail().name)
498 local wanted = false
499
500 if wanted_items[item_name] then
501 remaining_count = remaining_count - 1
502 else
503 table.insert(unwanted, slot)
504 end
505 end
506 slot = slot + 1
507 end
508
509 for _, unwanted_slot in pairs(unwanted) do
510 turtle.select(unwanted_slot)
511 turtle.drop()
512 end
513
514 if remaining_count > 0 then
515 return nil
516 end
517
518 return true
519end
520
521
522function itemsLackedToCraft(craft_item_name, count)
523 craft_item_name = interpretItemName(craft_item_name)
524 local items = itemsBeared(true)
525 local recipe = CRAFTING_RECIPES[craft_item_name]
526
527 local lacked = {}
528
529 for _, item_name in pairs(recipe) do
530 for i = 1, count do
531 if items[item_name] then
532 if items[item_name].count <= 1 then
533 items[item_name] = nil
534 else
535 items[item_name].count = items[item_name].count - 1
536 end
537 else
538 if lacked[item_name] then
539 lacked[item_name] = lacked[item_name] + 1
540 else
541 lacked[item_name] = 1
542 end
543 end
544 end
545 end
546
547 return lacked
548end
549
550
551function craft(craft_item_name, count)
552 craft_item_name = interpretItemName(craft_item_name)
553 if not count then count = 1 end
554
555 local recipe = CRAFTING_RECIPES[craft_item_name]
556 local required_items = {}
557
558 for i, item_name in pairs(recipe) do
559 if required_items[item_name] then
560 required_items[item_name] = required_items[item_name] + count
561 else
562 required_items[item_name] = count
563 end
564 end
565
566 -- Check that the correct items are being used
567 for slot = 1, 16 do
568 local item = turtle.getItemDetail(slot)
569 if item then
570 local name = interpretItemName(item.name)
571 if not required_items[name] then
572 error('Item "' .. name .. '" not used in recipe for "' .. craft_item_name .. '"')
573 end
574 if item.count < required_items[name] then
575 error('Not enough "' .. name .. '" in stack as per recipe')
576 end
577 end
578 end
579
580 -- Move all items out of the crafting area
581 for _, stack_slot in pairs(CRAFTING_SLOTS) do
582 if turtle.getItemDetail(stack_slot) then
583 turtle.select(stack_slot)
584 for _, tranfer_slot in pairs(NON_CRAFTING_SLOTS) do
585 if not turtle.getItemDetail(tranfer_slot) then
586 turtle.transferTo(tranfer_slot)
587 break
588 end
589 end
590 if turtle.getItemDetail(stack_slot) then
591 error('Too many stacks (crafting recipes with more than 7 unique ingredients not supported)')
592 end
593 end
594 end
595
596 -- Move items back into the crafting area and into the correct positions
597 for _, stack_slot in pairs(NON_CRAFTING_SLOTS) do
598 local item = turtle.getItemDetail(stack_slot)
599 if item then
600 local name = interpretItemName(item.name)
601
602 local place_slots = {}
603 for i, item_name in pairs(recipe) do
604 if item_name == name then
605 table.insert(place_slots, CRAFTING_SLOTS[i])
606 end
607 end
608
609 for i, place_slot in pairs(place_slots) do
610 if i == 1 then
611 turtle.select(stack_slot)
612 turtle.transferTo(place_slot)
613 else
614 turtle.select(place_slots[1])
615 turtle.transferTo(place_slot, count)
616 end
617 end
618 end
619 end
620
621 -- Craft!
622 if not turtle.craft(count) then
623 error('Crafting failed')
624 end
625end
626
627
628function craftAsNeeded(craft_item_name, count, original_items)
629 craft_item_name = interpretItemName(craft_item_name)
630 local needed_count = count
631 local beared = original_items[craft_item_name]
632 if beared then
633 needed_count = count - beared.count
634 end
635
636 if needed_count > 0 then
637 local recipe = CRAFTING_RECIPES[craft_item_name]
638 local required_items = {}
639 for _, item_name in pairs(recipe) do
640 required_items[interpretItemName(item_name)] = true
641 end
642
643 dumpExcept(required_items)
644
645 if not getFromChest(itemsLackedToCraft(craft_item_name, count)) then
646 error('Needed items not found in chest')
647 end
648
649 itemsBeared(true)
650
651 craft(craft_item_name, needed_count)
652 end
653
654 if beared then
655 getFromChest({[craft_item_name] = true})
656 itemsBeared(true)
657 end
658end
659
660
661function itemsBeared(drop)
662 local item_data = {}
663
664 for slot = 1, 16 do
665 local item = turtle.getItemDetail(slot)
666 if item then
667 local name = interpretItemName(item.name)
668 if NEEDED_ITEMS[name] then
669 if not item_data[name] then
670 item_data[name] = {count = item.count, slot = slot}
671 elseif drop then
672 turtle.select(slot)
673 if (item_data[name].count < 64) then
674 turtle.transferTo(item_data[name].slot)
675 end
676 if (item_data[name].count < turtle.getItemCount(slot)) then
677 turtle.select(item_data[name].slot)
678 item_data[name] = {count = item.count, slot = slot}
679 end
680 turtle.dropDown()
681 end
682 elseif drop then
683 turtle.select(slot)
684 turtle.dropDown()
685 end
686 end
687 end
688
689 turtle.select(1)
690 return item_data
691end
692
693
694function itemsLacked(subterranean, item_data, tree, lacked, count)
695 if item_data == nil then item_data = itemsBeared() end
696 if tree == nil then tree = CRAFTING_TREE end
697 if lacked == nil then lacked = {} end
698 if count == nil then count = 1 end
699
700 for item_name, item_details in pairs(tree) do
701
702 local need_count = count * item_details.count
703 local bear_count = 0
704 if item_data[item_name] then
705 bear_count = item_data[item_name].count
706 end
707 local lack_count = need_count - bear_count
708
709 if lack_count >= 0 then
710 item_data[item_name] = nil
711 if lack_count > 0 then
712 if item_details.components then
713 itemsLacked(subterranean, item_data, item_details.components, lacked, lack_count)
714 elseif subterranean == nil or subterranean == item_details.subterranean then
715 if lacked[item_name] then
716 lacked[item_name] = lacked[item_name] + lack_count
717 else
718 lacked[item_name] = lack_count
719 end
720 end
721 end
722 else
723 item_data[item_name].count = item_data[item_name].count - need_count
724 end
725 end
726
727 return lacked
728end
729
730
731function calibrate()
732 if not calibrated then
733 print('Tunneling down to calibrate height')
734 while ({INSPECT.down()})[2].name ~= 'minecraft:bedrock' do
735 go('down')
736 end
737 location.y = 10
738 location.y = -59
739 calibrated = true
740 end
741end
742
743
744function atDepth(depth)
745 return location.y == depth
746end
747
748
749function travelToDepth(depth)
750 calibrate()
751 while location.y > depth do
752 if ({INSPECT.down()})[2].name == 'minecraft:bedrock' then
753 location.y = math.min(location.y, -59)
754 break
755 end
756 goAbsolute('down')
757 end
758 while location.y < depth do
759 goAbsolute('up')
760 end
761end
762
763
764function mineVein(subterranean, skip_return, always_mine)
765 if not always_mine then always_mine = {} end
766
767 -- Log starting location
768 local start = strXYZ(location, orientation)
769 local start_orientation = orientation
770
771 -- Begin block map
772 local valid = {}
773 local ores = {}
774 valid[strXYZ(location)] = true
775 valid[strXYZ(getAdjacentBlock('back'))] = false
776 local ore_found = false
777 for i = 1, VEIN_MAX do
778
779 -- Get item types that are still lacking
780 local lacking = itemsLacked(subterranean)
781 for name, _ in pairs(always_mine) do
782 if not lacking[name] then
783 lacking[name] = 1
784 end
785 end
786
787 -- Scan adjacent
788 local scan_items = scan(valid, ores, lacking)
789
790 -- Do special case 'leaves' thing (for finding logs easier)
791 if scan_items['log'] and always_mine['leaves'] then
792 always_mine['leaves'] = nil
793 lacking['leaves'] = nil
794 valid = {}
795 ores = {}
796 valid[strXYZ(location)] = true
797 local s = scan(valid, ores, lacking)
798 end
799
800 -- Search for nearest ore
801 local route = fastestRoute(valid, ores, location, orientation)
802
803 -- Check if there is one
804 if not route then
805 break
806 end
807
808 -- Retrieve ore
809 turtle.select(1)
810 if not followRoute(route) then
811 face(start_orientation)
812 return false
813 end
814 ores[strXYZ(location)] = nil
815
816 end
817
818 -- Return to start
819 if skip_return then
820 face(start_orientation)
821 else
822 followRoute(fastestRoute(valid, {[start] = true}, location, orientation))
823 end
824
825 return true
826end
827
828
829function scan(valid, ores, ore_names)
830 local checked_left = false
831 local checked_right = false
832
833 local found_ore_names = {}
834
835 local f = strXYZ(getAdjacentBlock('forward'))
836 local u = strXYZ(getAdjacentBlock('up'))
837 local d = strXYZ(getAdjacentBlock('down'))
838 local l = strXYZ(getAdjacentBlock('left'))
839 local r = strXYZ(getAdjacentBlock('right'))
840 local b = strXYZ(getAdjacentBlock('back'))
841
842 if not valid[f] and valid[f] ~= false then
843 valid[f] = detectOre('forward', ore_names)
844 ores[f] = valid[f]
845 if ores[f] then found_ore_names[ores[f]] = true end
846 end
847 if not valid[u] and valid[u] ~= false then
848 valid[u] = detectOre('up', ore_names)
849 ores[u] = valid[u]
850 if ores[u] then found_ore_names[ores[u]] = true end
851 end
852 if not valid[d] and valid[d] ~= false then
853 valid[d] = detectOre('down', ore_names)
854 ores[d] = valid[d]
855 if ores[d] then found_ore_names[ores[d]] = true end
856 end
857 if not valid[l] and valid[l] ~= false then
858 go('left')
859 checked_left = true
860 valid[l] = detectOre('forward', ore_names)
861 ores[l] = valid[l]
862 if ores[l] then found_ore_names[ores[l]] = true end
863 end
864 if not valid[r] and valid[r] ~= false then
865 go('right')
866 if checked_left then
867 go('right')
868 end
869 checked_right = true
870 valid[r] = detectOre('forward', ore_names)
871 ores[r] = valid[r]
872 if ores[r] then found_ore_names[ores[r]] = true end
873 end
874 if not valid[b] and valid[b] ~= false then
875 if checked_right then
876 go('right')
877 elseif checked_left then
878 go('left')
879 else
880 go('right')
881 go('right')
882 end
883 valid[b] = detectOre('forward', ore_names)
884 ores[b] = valid[b]
885 if ores[b] then found_ore_names[ores[b]] = true end
886 end
887
888 return found_ore_names
889end
890
891
892function detectOre(direction, ore_names)
893 local _, block = INSPECT[direction]()
894 local name = interpretItemName(block.name)
895 if ore_names[name] then
896 return name
897 end
898 return false
899end
900
901
902function fastestRoute(area, end_locations, loc, ori)
903 local queue = {}
904 local explored = {}
905 table.insert(queue,
906 {
907 coords = {x = loc.x, y = loc.y, z = loc.z},
908 facing = ori,
909 path = '',
910 }
911 )
912 explored[strXYZ(loc, ori)] = true
913
914 while #queue > 0 do
915 local node = table.remove(queue, 1)
916 if end_locations[strXYZ(node.coords)] or end_locations[strXYZ(node.coords, node.facing)] then
917 return node.path
918 end
919 for _, step in pairs({
920 {coords = node.coords, facing = LEFT_SHIFT[node.facing], path = node.path .. 'l'},
921 {coords = node.coords, facing = RIGHT_SHIFT[node.facing], path = node.path .. 'r'},
922 {coords = getAdjacentBlock('forward', node.coords, node.facing), facing = node.facing, path = node.path .. 'f'},
923 {coords = getAdjacentBlock('up', node.coords, node.facing), facing = node.facing, path = node.path .. 'u'},
924 {coords = getAdjacentBlock('down', node.coords, node.facing), facing = node.facing, path = node.path .. 'd'},
925 }) do
926 explore_string = strXYZ(step.coords, step.facing)
927 if not explored[explore_string] and (not area or area[strXYZ(step.coords)]) then
928 explored[explore_string] = true
929 table.insert(queue, step)
930 end
931 end
932 end
933end
934
935
936function strXYZ(coords, facing)
937 if facing then
938 return coords.x .. ',' .. coords.y .. ',' .. coords.z .. ':' .. facing
939 else
940 return coords.x .. ',' .. coords.y .. ',' .. coords.z
941 end
942end
943
944
945function interpretItemName(item_name)
946 if LOG_ITEMS[item_name] then
947 return 'log'
948 elseif PLANKS_ITEMS[item_name] then
949 return 'planks'
950 elseif LEAVES_ITEMS[item_name] then
951 return 'leaves'
952 elseif ORE_ITEMS[item_name] then
953 return ORE_ITEMS[item_name]
954 else
955 return item_name
956 end
957end
958
959
960refuel_max = false
961function smartRefuel()
962 if refuel_max then
963 if refuelTo(TRAVEL_FUEL) then
964 refuel_max = false
965 return true
966 end
967 else
968 if refuelTo(TRAVEL_FUEL_MIN) then
969 return true
970 else
971 refuel_max = true
972 end
973 end
974 return false
975end
976
977
978function refuelTo(target_level)
979 local lacked_coal = math.ceil((target_level - turtle.getFuelLevel()) / 80)
980 if lacked_coal <= 0 then return true end
981
982 for slot = 1, 16 do
983 local item_details = turtle.getItemDetail(slot)
984 if item_details and item_details.name == 'minecraft:coal' then
985 turtle.select(slot)
986 turtle.refuel(lacked_coal)
987 lacked_coal = math.ceil((target_level - turtle.getFuelLevel()) / 80)
988 if lacked_coal <= 0 then return true end
989 end
990 end
991
992 return false
993end
994
995
996SAND_IGNORE = {['minecraft:water'] = true}
997REGULAR_IGNORE = {['minecraft:grass'] = true, ['minecraft:tall_grass'] = true}
998function is_trace_block(direction, lacked)
999 local is_block, block_data = INSPECT[direction]()
1000 if not is_block then return false end
1001 return not (REGULAR_IGNORE[block_data.name] or (lacked['minecraft:sand'] and SAND_IGNORE[block_data.name]))
1002end
1003
1004
1005function traceStep(lacked)
1006 lacked = lacked or {}
1007
1008 local is_block_forward = is_trace_block('forward', lacked)
1009 local is_block_down = is_trace_block('down', lacked)
1010
1011 if is_block_forward then
1012 go('up')
1013 is_block_forward = is_trace_block('forward', lacked)
1014 if not is_block_forward then
1015 go('forward')
1016 end
1017 elseif is_block_down then
1018 go('forward')
1019 else
1020 go('down')
1021 end
1022end
1023
1024
1025function explore()
1026 print("Exploring the surface for resources")
1027 local lacked = itemsLacked(false)
1028 local i = 0
1029 local refuelGood = true
1030 while next(lacked) ~= nil and refuelGood do
1031 traceStep(lacked)
1032
1033 local is_block_forward, data_block_forward = INSPECT.forward()
1034 local is_block_down, data_block_down = INSPECT.down()
1035 local is_block_up, data_block_up = INSPECT.up()
1036
1037 local block_found = (is_block_forward and lacked[interpretItemName(data_block_forward.name)])
1038 block_found = block_found or (is_block_down and lacked[interpretItemName(data_block_down.name)])
1039 block_found = block_found or (is_block_up and lacked[interpretItemName(data_block_up.name)])
1040
1041 if block_found then
1042 if is_block_forward and data_block_forward.name == 'minecraft:sugar_cane' then
1043 while is_block_forward and data_block_forward.name == 'minecraft:sugar_cane' do
1044 go('up')
1045 is_block_forward, data_block_forward = INSPECT.forward()
1046 end
1047 go('forward')
1048 end
1049 if lacked['log'] then
1050 mineVein(false, true, {['leaves'] = true})
1051 else
1052 mineVein(false, true)
1053 end
1054 end
1055
1056 lacked = itemsLacked(false)
1057 if lacked['log'] then
1058 lacked['leaves'] = true
1059 end
1060 if next(lacked) == nil or i >= HOUSEKEEP_FREQUENCY then
1061 i = 0
1062 refuelGood = smartRefuel()
1063 lacked = itemsLacked(false, itemsBeared(true))
1064 else
1065 i = i + 1
1066 end
1067 end
1068end
1069
1070
1071function mine()
1072 local lacked = itemsLacked(true)
1073 local refuelGood = smartRefuel()
1074 if not refuelGood then
1075 lacked['minecraft:coal_ore'] = true
1076 end
1077
1078 local i = 0
1079 while next(lacked) ~= nil or not refuelGood do
1080 while ({INSPECT.forward()})[2].name == 'minecraft:bedrock' do
1081 goAbsolute('up')
1082 location.y = -59
1083 end
1084
1085 if not refuelGood then
1086 if not atDepth(ORE_DEPTH['minecraft:coal_ore']) then
1087 print("Traveling to y=" .. ORE_DEPTH['minecraft:coal_ore'] .. " to refuel")
1088 travelToDepth(ORE_DEPTH['minecraft:coal_ore'])
1089 end
1090 else
1091 for _, ore_name in pairs(ORE_PRIORITY) do
1092 if lacked[ore_name] then
1093 if not atDepth(ORE_DEPTH[ore_name]) then
1094 print("Traveling to y=" .. ORE_DEPTH[ore_name] .. " to find " .. ore_name)
1095 travelToDepth(ORE_DEPTH[ore_name])
1096 end
1097 break
1098 end
1099 end
1100 end
1101
1102 lacked = itemsLacked(true)
1103 if detectOre('up', lacked) or detectOre('forward', lacked) or detectOre('down', lacked) then
1104 itemsBeared(true)
1105 mineVein(true, false, {['minecraft:diamond_ore'] = true})
1106 end
1107 go('forward')
1108
1109 if next(lacked) == nil or i >= HOUSEKEEP_FREQUENCY then
1110 i = 0
1111 lacked = itemsLacked(true, itemsBeared(true))
1112 refuelGood = smartRefuel()
1113 if not refuelGood then
1114 lacked['minecraft:coal_ore'] = true
1115 end
1116 else
1117 i = i + 1
1118 end
1119 end
1120end
1121
1122
1123function createFarm()
1124 print('Creating sugar cane farm')
1125 local items = itemsBeared(true)
1126 local is_block_down, data_block_down = INSPECT.down()
1127 local is_block_forward = INSPECT.forward()
1128
1129 while is_block_forward or not (is_block_down and data_block_down.name == 'minecraft:water') do
1130 traceStep()
1131 is_block_down, data_block_down = INSPECT.down()
1132 is_block_forward = INSPECT.forward()
1133 end
1134
1135 goAbsolute('forward')
1136 selectItem('minecraft:dirt')
1137 DIG.down()
1138 PLACE.down()
1139 goAbsolute('up')
1140 selectItem('minecraft:sugar_cane')
1141 PLACE.down()
1142 goAbsolute('up')
1143end
1144
1145
1146function dumpExcept(exceptions)
1147 for slot = 1, 16 do
1148 local item = turtle.getItemDetail(slot)
1149 if item then
1150 local name = interpretItemName(item.name)
1151 if not exceptions[name] then
1152 turtle.select(slot)
1153 turtle.drop()
1154 end
1155 end
1156 end
1157end
1158
1159
1160function destroy(item_name)
1161 if selectItem(item_name) then
1162 turtle.dropDown()
1163 end
1164end
1165
1166
1167function selectItem(item_name)
1168 local items = itemsBeared()
1169 if not items[interpretItemName(item_name)] then
1170 return false
1171 end
1172 turtle.select(items[interpretItemName(item_name)].slot)
1173 return true
1174end
1175
1176
1177function genesis()
1178 print("Items collected, begining genesis process")
1179
1180 local original_items = itemsBeared(true)
1181 local items = itemsBeared(true)
1182
1183 -- Make sugar cane farm if needed
1184 local sugar_needed = 5 - original_items['minecraft:sugar_cane'].count
1185 if original_items['computercraft:disk'] or original_items['minecraft:paper'] then
1186 sugar_needed = math.max(0, sugar_needed - 3)
1187 end
1188 if sugar_needed > 0 then
1189 createFarm()
1190 end
1191
1192 -- Place chest
1193 print('Placing proxy chest')
1194 destroy('minecraft:dirt')
1195 items = itemsBeared(true)
1196 selectItem('minecraft:chest')
1197 DIG.forward()
1198 PLACE.forward()
1199
1200 -- Craft furnaces and collect smelting items
1201 print('Creating smeltery')
1202 dumpExcept({['minecraft:cobblestone'] = true})
1203 craftAsNeeded('minecraft:furnace', 3, original_items)
1204 getFromChest({['minecraft:coal'] = true, ['minecraft:sand'] = true, ['minecraft:raw_iron'] = true})
1205 goAbsolute('left')
1206 goAbsolute('forward')
1207 goAbsolute('right')
1208 goAbsolute('right')
1209
1210 -- Place furnaces
1211 for i = 1, 3 do
1212 items = itemsBeared(true)
1213 selectItem('minecraft:furnace')
1214 DIG.up()
1215 PLACE.up()
1216 selectItem('minecraft:coal')
1217 turtle.dropUp(1)
1218 if i == 2 then
1219 turtle.dropUp(1)
1220 end
1221 goAbsolute('forward')
1222 end
1223
1224 -- Place items in furnaces
1225 print('Smelting')
1226 goAbsolute('up')
1227 goAbsolute('left')
1228 goAbsolute('up')
1229 goAbsolute('left')
1230 goAbsolute('forward')
1231 if selectItem('minecraft:sand') then
1232 turtle.dropDown()
1233 end
1234 goAbsolute('forward')
1235 if selectItem('minecraft:cobblestone') then
1236 turtle.dropDown()
1237 end
1238 goAbsolute('forward')
1239 if selectItem('minecraft:raw_iron') then
1240 turtle.dropDown()
1241 end
1242 goAbsolute('forward')
1243 goAbsolute('down')
1244 goAbsolute('right')
1245 goAbsolute('down')
1246 goAbsolute('right')
1247 goAbsolute('forward')
1248 goAbsolute('forward')
1249 goAbsolute('left')
1250 items = itemsBeared(true)
1251
1252 -- Collect sugar cane if needed
1253 print('Collecting all necessary sugar cane')
1254 for i = 1, sugar_needed do
1255 while not INSPECT.down() do
1256 sleep(1)
1257 end
1258 DIG.down()
1259 end
1260 if sugar_needed > 0 then
1261 goAbsolute('down')
1262 goAbsolute('down')
1263 DIG.down()
1264 goAbsolute('up')
1265 goAbsolute('up')
1266 destroy('minecraft:dirt')
1267 end
1268
1269 -- Collect furnace contents when ready
1270 print('Collecting furnace contents')
1271 dumpExcept({})
1272 turtle.select(1)
1273 while true do
1274 turtle.suckUp()
1275 if turtle.getItemCount() >= 14 then
1276 break
1277 end
1278 sleep(1)
1279 end
1280 goAbsolute('left')
1281 goAbsolute('forward')
1282 goAbsolute('right')
1283 goAbsolute('up')
1284 goAbsolute('right')
1285 goAbsolute('forward')
1286 goAbsolute('forward')
1287 goAbsolute('left')
1288 goAbsolute('down')
1289 goAbsolute('left')
1290 goAbsolute('forward')
1291 goAbsolute('right')
1292 destroy('minecraft:sand')
1293 destroy('minecraft:iron_ore')
1294 destroy('minecraft:cobblestone')
1295 destroy('minecraft:furnace')
1296
1297 -- Do crafting
1298 doCrafting(original_items)
1299
1300 -- Grab final items
1301 dumpExcept({})
1302 local items_aquired = getFromChest({
1303 ['computercraft:turtle_normal'] = true,
1304 ['computercraft:disk_drive'] = true,
1305 ['computercraft:disk'] = true,
1306 ['minecraft:coal'] = true,
1307 ['minecraft:sugar_cane'] = true,
1308 ['minecraft:chest'] = true,
1309 })
1310 if not items_aquired then
1311 error('Something went wrong in the crafting process')
1312 end
1313
1314 -- Place disk drive
1315 print('Tranferring contents of brain')
1316 goAbsolute('left')
1317 selectItem('computercraft:disk_drive')
1318 while not PLACE.forward() do
1319 DIG.forward()
1320 end
1321 selectItem('computercraft:disk')
1322 turtle.drop()
1323 populateDisk()
1324
1325 -- Place turtle
1326 print('Creating turtle')
1327 goAbsolute('up')
1328 goAbsolute('forward')
1329 goAbsolute('forward')
1330 selectItem('computercraft:turtle_normal')
1331 while not PLACE.down() do
1332 DIG.down()
1333 end
1334 selectItem('minecraft:chest')
1335 turtle.dropDown(1)
1336 selectItem('minecraft:sugar_cane')
1337 turtle.dropDown(1)
1338 selectItem('minecraft:coal')
1339 turtle.dropDown(16)
1340
1341 -- Give life
1342 print('Giving life')
1343 peripheral.call('bottom', 'turnOn')
1344
1345 -- Pack up
1346 print('Packing up')
1347 goAbsolute('right')
1348 goAbsolute('right')
1349 goAbsolute('forward')
1350 goAbsolute('down')
1351 goAbsolute('forward')
1352 goAbsolute('left')
1353 goAbsolute('forward')
1354
1355end
1356
1357
1358function doCrafting(original_items)
1359 print('Do crafting of all necessary items')
1360
1361 -- Craft turtle
1362 local chests_lacked = math.max(0, 3 - original_items['minecraft:chest'].count)
1363 if chests_lacked > 0 then
1364 craftAsNeeded('planks', chests_lacked * 2, original_items)
1365 craftAsNeeded('minecraft:chest', chests_lacked, {})
1366 destroy('planks')
1367 end
1368 craftAsNeeded('minecraft:glass_pane', 1, original_items)
1369 destroy('minecraft:glass')
1370 craftAsNeeded('computercraft:computer_normal', 1, {})
1371 craftAsNeeded('computercraft:turtle_normal', 1, {})
1372 destroy('minecraft:iron_ingot')
1373 if not (original_items['minecraft:stick'] and original_items['minecraft:stick'].count >= 2) then
1374 craftAsNeeded('planks', 1, original_items)
1375 craftAsNeeded('minecraft:stick', 1, {})
1376 destroy('planks')
1377 end
1378 craftAsNeeded('minecraft:diamond_pickaxe', 1, {})
1379 destroy('minecraft:stick')
1380 if not original_items['minecraft:crafting_table'] then
1381 craftAsNeeded('planks', 1, original_items)
1382 craftAsNeeded('minecraft:crafting_table', 1, {})
1383 end
1384 craftAsNeeded('mining_crafty_turtle', 1, {})
1385
1386 -- Craft disk
1387 craftAsNeeded('computercraft:disk_drive', 1, original_items)
1388 if not original_items['computercraft:disk'] then
1389 craftAsNeeded('minecraft:paper', 1, original_items)
1390 craftAsNeeded('computercraft:disk', 1, {})
1391 destroy('minecraft:paper')
1392 end
1393
1394end
1395
1396
1397function main()
1398 while true do
1399 local refueled = smartRefuel()
1400 local need_subterranian_items = next(itemsLacked(true)) ~= nil
1401
1402 if not refueled or need_subterranian_items then
1403 -- Items are needed from underground
1404 mine()
1405 else
1406 local need_surface_items = next(itemsLacked(false)) ~= nil
1407 if need_surface_items then
1408 -- Items are needed from surface
1409 explore()
1410 else
1411 -- Items are collected
1412 genesis()
1413 end
1414 end
1415 end
1416end
1417
1418
1419function manualChest()
1420 print('\nPlease insert...')
1421 print('1 Chest [ ] 1 Sugar Cane [ ]')
1422 sleep(0.5)
1423
1424 while true do
1425 local aquired = 0
1426 for slot = 1, 16 do
1427 local item = turtle.getItemDetail(slot)
1428 if item and item.name == 'minecraft:chest' then
1429 aquired = bit32.bor(aquired, 1)
1430 end
1431 if item and item.name == 'minecraft:sugar_cane' then
1432 aquired = bit32.bor(aquired, 2)
1433 end
1434 end
1435 term.setCursorPos(10, 6)
1436 if bit32.band(aquired, 1) ~= 0 then
1437 term.write('x')
1438 else
1439 term.write(' ')
1440 end
1441 term.setCursorPos(31, 6)
1442 if bit32.band(aquired, 2) ~= 0 then
1443 term.write('x')
1444 else
1445 term.write(' ')
1446 end
1447 if aquired == 3 then
1448 return
1449 end
1450 sleep(0.5)
1451 end
1452
1453end
1454
1455
1456function manualRefuel(desired_level)
1457 print('Please insert coal...')
1458
1459 local cursor_x, cursor_y = term.getCursorPos()
1460 local current_level = turtle.getFuelLevel()
1461 local slot = 1
1462
1463 printFuelBar(cursor_y, current_level, desired_level)
1464
1465 while current_level < desired_level do
1466
1467 for i = 1, 16 do
1468 local item = turtle.getItemDetail(slot)
1469 if item and item.name == 'minecraft:coal' then
1470 turtle.select(slot)
1471 if turtle.refuel(5) then break end
1472 end
1473 slot = (slot % 16) + 1
1474 end
1475
1476 current_level = turtle.getFuelLevel()
1477 printFuelBar(cursor_y, current_level, desired_level)
1478 sleep(0)
1479
1480 end
1481
1482 sleep(1)
1483 print('\nFueling complete.')
1484end
1485
1486
1487function printFuelBar(cursor_y, current_level, desired_level)
1488 term.setCursorPos(1, cursor_y)
1489 local progress = math.min(math.floor(FUEL_BAR * current_level / desired_level), FUEL_BAR)
1490 term.write('[')
1491 for i = 1, progress do
1492 term.write('+')
1493 end
1494 for i = 1, FUEL_BAR - progress do
1495 term.write('-')
1496 end
1497 term.write('] ')
1498 term.write(tostring(current_level))
1499 term.write('/')
1500 term.write(tostring(desired_level))
1501end
1502
1503
1504function printTitle()
1505 for y_offset, line in pairs(TITLE) do
1506 term.setCursorPos(1, y_offset)
1507 for char in line:gmatch"." do
1508 if char == '#' then
1509 term.setBackgroundColor(colors.white)
1510 else
1511 term.setBackgroundColor(colors.black)
1512 end
1513 term.write(' ')
1514 end
1515 end
1516 term.setBackgroundColor(colors.black)
1517end
1518
1519
1520function userInit()
1521
1522 term.clear()
1523 printTitle()
1524 print('\n press return to continue...')
1525 read()
1526
1527 term.clear()
1528 term.setCursorPos(1, 1)
1529 manualRefuel(START_FUEL)
1530
1531 sleep(1)
1532 manualChest()
1533
1534 sleep(1)
1535 print('\nTurtle preparation complete.')
1536 sleep(1)
1537 print('\nFinal confirmation...')
1538 sleep(0.5)
1539 print('Initiate global turtle colonization?')
1540 term.write('(Y/N) > ')
1541
1542 if string.upper(read()) ~= 'Y' then
1543 print('Shutdown...')
1544 os.shutdown()
1545 return
1546 end
1547
1548 term.clear()
1549 term.setCursorPos(1, 1)
1550
1551 print('Beginning...')
1552 sleep(1)
1553 for i = 5, 1, -1 do
1554 print(i)
1555 sleep(1)
1556 end
1557
1558 term.clear()
1559 term.setCursorPos(1, 1)
1560
1561 initiate()
1562
1563end
1564
1565
1566function populateDisk()
1567 -- This is the most meta function I've ever written
1568 if not fs.isDir('/disk') then
1569 error('Disk not inserted')
1570 end
1571 local file_contents = fs.open('startup', 'r').readAll()
1572 s = 'FILE_CONTENTS = [===[' .. file_contents .. ']' .. '===]'
1573 s = s .. [[
1574 file = fs.open('/startup', 'w')
1575 file.write(FILE_CONTENTS)
1576 file.close()
1577 shell.run('startup')
1578 ]]
1579 file = fs.open('/disk/startup', 'w')
1580 file.write(s)
1581 file.close()
1582end
1583
1584
1585function initiate()
1586 local filename = debug.getinfo(2, "S").short_src
1587 local file = fs.open(filename, 'r')
1588 if not file then error('File not found somehow...') end
1589
1590 local file_contents = file.readAll()
1591 file_contents = file_contents:sub(1, -11) .. 'main()'
1592 file = fs.open('/startup', 'w')
1593 file.write(file_contents)
1594 file.close()
1595 os.reboot()
1596end
1597
1598
1599nameTurtle()
1600userInit()