· 9 years ago · Nov 05, 2016, 01:16 AM
1{
2 misc = {},
3 sbin = {},
4 home = {
5 fisher = {},
6 },
7 var = {},
8 usr = {
9 share = {
10 doc = {
11 copyright = {
12 statement = "This is free software, do what you want with it,\
13tbh this page was just for shits and giggles\
14just in case anyone *responsible* actually wanted\
15to read this lol\
16\
17-F.\
18",
19 },
20 welcome = "welcome\
21",
22 },
23 },
24 },
25 bin = {
26 nano = "-- Get file to edit\
27local tArgs = { ... }\
28if #tArgs == 0 then\
29 print( \"Usage: nano <path/to/file>\" )\
30 return\
31end\
32\
33-- Error checking\
34local sPath = shell.resolve( tArgs[1] )\
35local bReadOnly = fs.isReadOnly( sPath )\
36if fs.exists( sPath ) and fs.isDir( sPath ) then\
37 print( \"Cannot edit a directory.\" )\
38 return\
39end\
40\
41local x,y = 1,1\
42local w,h = term.getSize()\
43local scrollX, scrollY = 0,0\
44\
45local tLines = {}\
46local bRunning = true\
47\
48-- Colours\
49local highlightColour, keywordColour, commentColour, textColour, bgColour\
50if term.isColour() then\
51 bgColour = colours.black\
52 textColour = colours.white\
53 highlightColour = colours.yellow\
54 keywordColour = colours.yellow\
55 commentColour = colours.green\
56 stringColour = colours.red\
57else\
58 bgColour = colours.black\
59 textColour = colours.white\
60 highlightColour = colours.white\
61 keywordColour = colours.white\
62 commentColour = colours.white\
63 stringColour = colours.white\
64end\
65\
66-- Menus\
67local bMenu = false\
68local nMenuItem = 1\
69local tMenuItems\
70if bReadOnly then\
71 tMenuItems = { \"Exit\", \"Print\" }\
72else\
73 tMenuItems = { \"Save\", \"Exit\", \"Print\" }\
74end\
75 \
76local sStatus = \"Press Ctrl to access menu\"\
77if string.len( sStatus ) > w - 5 then\
78 sStatus = \"Press Ctrl for menu\"\
79end\
80\
81local function load( _sPath )\
82 tLines = {}\
83 if fs.exists( _sPath ) then\
84 local file = io.open( _sPath, \"r\" )\
85 local sLine = file:read()\
86 while sLine do\
87 table.insert( tLines, sLine )\
88 sLine = file:read()\
89 end\
90 file:close()\
91 end\
92 \
93 if #tLines == 0 then\
94 table.insert( tLines, \"\" )\
95 end\
96end\
97\
98local function save( _sPath )\
99 -- Create intervening folder\
100 local sDir = sPath:sub(1, sPath:len() - fs.getName(sPath):len() )\
101 if not fs.exists( sDir ) then\
102 fs.makeDir( sDir )\
103 end\
104\
105 -- Save\
106 local file = nil\
107 local function innerSave()\
108 file = fs.open( _sPath, \"w\" )\
109 if file then\
110 for n, sLine in ipairs( tLines ) do\
111 file.write( sLine .. \"\\n\" )\
112 end\
113 else\
114 error( \"Failed to open \".._sPath )\
115 end\
116 end\
117 \
118 local ok = pcall( innerSave )\
119 if file then \
120 file.close()\
121 end\
122 return ok\
123end\
124\
125local tKeywords = {\
126 [\"and\"] = true,\
127 [\"break\"] = true,\
128 [\"do\"] = true,\
129 [\"else\"] = true,\
130 [\"elseif\"] = true,\
131 [\"end\"] = true,\
132 [\"false\"] = true,\
133 [\"for\"] = true,\
134 [\"function\"] = true,\
135 [\"if\"] = true,\
136 [\"in\"] = true,\
137 [\"local\"] = true,\
138 [\"nil\"] = true,\
139 [\"not\"] = true,\
140 [\"or\"] = true,\
141 [\"repeat\"] = true,\
142 [\"return\"] = true,\
143 [\"then\"] = true,\
144 [\"true\"] = true,\
145 [\"until\"]= true,\
146 [\"while\"] = true,\
147}\
148\
149local function tryWrite( sLine, regex, colour )\
150 local match = string.match( sLine, regex )\
151 if match then\
152 if type(colour) == \"number\" then\
153 term.setTextColour( colour )\
154 else\
155 term.setTextColour( colour(match) )\
156 end\
157 term.write( match )\
158 term.setTextColour( textColour )\
159 return string.sub( sLine, string.len(match) + 1 )\
160 end\
161 return nil\
162end\
163\
164local function writeHighlighted( sLine )\
165 while string.len(sLine) > 0 do \
166 sLine = \
167 tryWrite( sLine, \"^%-%-%[%[.-%]%]\", commentColour ) or\
168 tryWrite( sLine, \"^%-%-.*\", commentColour ) or\
169 tryWrite( sLine, \"^\\\".-[^\\\\]\\\"\", stringColour ) or\
170 tryWrite( sLine, \"^\\'.-[^\\\\]\\'\", stringColour ) or\
171 tryWrite( sLine, \"^%[%[.-%]%]\", stringColour ) or\
172 tryWrite( sLine, \"^[%w_]+\", function( match )\
173 if tKeywords[ match ] then\
174 return keywordColour\
175 end\
176 return textColour\
177 end ) or\
178 tryWrite( sLine, \"^[^%w_]\", textColour )\
179 end\
180end\
181\
182local function redrawText()\
183 for y=1,h-1 do\
184 term.setCursorPos( 1 - scrollX, y )\
185 term.clearLine()\
186\
187 local sLine = tLines[ y + scrollY ]\
188 if sLine ~= nil then\
189 writeHighlighted( sLine )\
190 end\
191 end\
192 term.setCursorPos( x - scrollX, y - scrollY )\
193end\
194\
195local function redrawLine(_nY)\
196 local sLine = tLines[_nY]\
197 term.setCursorPos( 1 - scrollX, _nY - scrollY )\
198 term.clearLine()\
199 writeHighlighted( sLine )\
200 term.setCursorPos( x - scrollX, _nY - scrollY )\
201end\
202\
203local function redrawMenu()\
204 -- Clear line\
205 term.setCursorPos( 1, h )\
206 term.clearLine()\
207\
208 -- Draw line numbers\
209 term.setCursorPos( w - string.len( \"Ln \"..y ) + 1, h )\
210 term.setTextColour( highlightColour )\
211 term.write( \"Ln \" )\
212 term.setTextColour( textColour )\
213 term.write( y )\
214\
215 term.setCursorPos( 1, h )\
216 if bMenu then\
217 -- Draw menu\
218 term.setTextColour( textColour )\
219 for nItem,sItem in pairs( tMenuItems ) do\
220 if nItem == nMenuItem then\
221 term.setTextColour( highlightColour )\
222 term.write( \"[\" )\
223 term.setTextColour( textColour )\
224 term.write( sItem )\
225 term.setTextColour( highlightColour )\
226 term.write( \"]\" )\
227 term.setTextColour( textColour )\
228 else\
229 term.write( \" \"..sItem..\" \" )\
230 end\
231 end\
232 else\
233 -- Draw status\
234 term.setTextColour( highlightColour )\
235 term.write( sStatus )\
236 term.setTextColour( textColour )\
237 end\
238\
239 -- Reset cursor\
240 term.setCursorPos( x - scrollX, y - scrollY )\
241end\
242\
243local tMenuFuncs = { \
244 Save=function()\
245 if bReadOnly then\
246 sStatus = \"Access denied\"\
247 else\
248 local ok, err = save( sPath )\
249 if ok then\
250 sStatus=\"Nano'd to \"..sPath\
251 else\
252 sStatus=\"Error saving to \"..sPath\
253 end\
254 end\
255 redrawMenu()\
256 end,\
257 Print=function()\
258 local printer = peripheral.find( \"printer\" )\
259 if not printer then\
260 sStatus = \"No printer attached\"\
261 return\
262 end\
263\
264 local nPage = 0\
265 local sName = fs.getName( sPath )\
266 if printer.getInkLevel() < 1 then\
267 sStatus = \"Printer out of ink\"\
268 return\
269 elseif printer.getPaperLevel() < 1 then\
270 sStatus = \"Printer out of paper\"\
271 return\
272 end\
273\
274 local screenTerminal = term.current()\
275 local printerTerminal = {\
276 getCursorPos = printer.getCursorPos,\
277 setCursorPos = printer.setCursorPos,\
278 getSize = printer.getPageSize,\
279 write = printer.write,\
280 }\
281 printerTerminal.scroll = function()\
282 if nPage == 1 then\
283 printer.setPageTitle( sName..\" (page \"..nPage..\")\" ) \
284 end\
285 \
286 while not printer.newPage() do\
287 if printer.getInkLevel() < 1 then\
288 sStatus = \"Printer out of ink, please refill\"\
289 elseif printer.getPaperLevel() < 1 then\
290 sStatus = \"Printer out of paper, please refill\"\
291 else\
292 sStatus = \"Printer output tray full, please empty\"\
293 end\
294 \
295 term.redirect( screenTerminal )\
296 redrawMenu()\
297 term.redirect( printerTerminal )\
298 \
299 local timer = os.startTimer(0.5)\
300 sleep(0.5)\
301 end\
302\
303 nPage = nPage + 1\
304 if nPage == 1 then\
305 printer.setPageTitle( sName )\
306 else\
307 printer.setPageTitle( sName..\" (page \"..nPage..\")\" )\
308 end\
309 end\
310 \
311 bMenu = false\
312 term.redirect( printerTerminal )\
313 local ok, error = pcall( function()\
314 term.scroll()\
315 for n, sLine in ipairs( tLines ) do\
316 print( sLine )\
317 end\
318 end )\
319 term.redirect( screenTerminal )\
320 if not ok then\
321 print( error )\
322 end\
323 \
324 while not printer.endPage() do\
325 sStatus = \"Printer output tray full, please empty\"\
326 redrawMenu()\
327 sleep( 0.5 )\
328 end\
329 bMenu = true\
330 \
331 if nPage > 1 then\
332 sStatus = \"Printed \"..nPage..\" Pages\"\
333 else\
334 sStatus = \"Printed 1 Page\"\
335 end\
336 redrawMenu()\
337 end,\
338 Exit=function()\
339 bRunning = false\
340 end\
341}\
342\
343local function doMenuItem( _n )\
344 tMenuFuncs[tMenuItems[_n]]()\
345 if bMenu then\
346 bMenu = false\
347 term.setCursorBlink( true )\
348 end\
349 redrawMenu()\
350end\
351\
352local function setCursor( x, y )\
353 local screenX = x - scrollX\
354 local screenY = y - scrollY\
355 \
356 local bRedraw = false\
357 if screenX < 1 then\
358 scrollX = x - 1\
359 screenX = 1\
360 bRedraw = true\
361 elseif screenX > w then\
362 scrollX = x - w\
363 screenX = w\
364 bRedraw = true\
365 end\
366 \
367 if screenY < 1 then\
368 scrollY = y - 1\
369 screenY = 1\
370 bRedraw = true\
371 elseif screenY > h-1 then\
372 scrollY = y - (h-1)\
373 screenY = h-1\
374 bRedraw = true\
375 end\
376 \
377 if bRedraw then\
378 redrawText()\
379 end\
380 term.setCursorPos( screenX, screenY )\
381 \
382 -- Statusbar now pertains to menu, it would probably be safe to redraw the menu on every key event.\
383 redrawMenu()\
384end\
385\
386-- Actual program functionality begins\
387load(sPath)\
388\
389term.setBackgroundColour( bgColour )\
390term.clear()\
391term.setCursorPos(x,y)\
392term.setCursorBlink( true )\
393\
394redrawText()\
395redrawMenu()\
396\
397-- Handle input\
398while bRunning do\
399 local sEvent, param, param2, param3 = os.pullEvent()\
400 if sEvent == \"key\" then\
401 if param == keys.up then\
402 -- Up\
403 if not bMenu then\
404 if y > 1 then\
405 -- Move cursor up\
406 y = y - 1\
407 x = math.min( x, string.len( tLines[y] ) + 1 )\
408 setCursor( x, y )\
409 end\
410 end\
411 elseif param == keys.down then\
412 -- Down\
413 if not bMenu then\
414 -- Move cursor down\
415 if y < #tLines then\
416 y = y + 1\
417 x = math.min( x, string.len( tLines[y] ) + 1 )\
418 setCursor( x, y )\
419 end\
420 end\
421 elseif param == keys.tab then\
422 -- Tab\
423 if not bMenu and not bReadOnly then\
424 -- Indent line\
425 tLines[y]=\" \"..tLines[y]\
426 x = x + 2\
427 setCursor( x, y )\
428 redrawLine(y)\
429 end\
430 elseif param == keys.pageUp then\
431 -- Page Up\
432 if not bMenu then\
433 -- Move up a page\
434 if y - (h - 1) >= 1 then\
435 y = y - (h - 1)\
436 else\
437 y = 1\
438 end\
439 x = math.min( x, string.len( tLines[y] ) + 1 )\
440 setCursor( x, y )\
441 end\
442 elseif param == keys.pageDown then\
443 -- Page Down\
444 if not bMenu then\
445 -- Move down a page\
446 if y + (h - 1) <= #tLines then\
447 y = y + (h - 1)\
448 else\
449 y = #tLines\
450 end\
451 x = math.min( x, string.len( tLines[y] ) + 1 )\
452 setCursor( x, y )\
453 end\
454 elseif param == keys.home then\
455 -- Home\
456 if not bMenu then\
457 -- Move cursor to the beginning\
458 x=1\
459 setCursor(x,y)\
460 end\
461 elseif param == keys[\"end\"] then\
462 -- End\
463 if not bMenu then\
464 -- Move cursor to the end\
465 x = string.len( tLines[y] ) + 1\
466 setCursor(x,y)\
467 end\
468 elseif param == keys.left then\
469 -- Left\
470 if not bMenu then\
471 if x > 1 then\
472 -- Move cursor left\
473 x = x - 1\
474 elseif x==1 and y>1 then\
475 x = string.len( tLines[y-1] ) + 1\
476 y = y - 1\
477 end\
478 setCursor( x, y )\
479 else\
480 -- Move menu left\
481 nMenuItem = nMenuItem - 1\
482 if nMenuItem < 1 then\
483 nMenuItem = #tMenuItems\
484 end\
485 redrawMenu()\
486 end\
487 elseif param == keys.right then\
488 -- Right\
489 if not bMenu then\
490 if x < string.len( tLines[y] ) + 1 then\
491 -- Move cursor right\
492 x = x + 1\
493 elseif x==string.len( tLines[y] ) + 1 and y<#tLines then\
494 x = 1\
495 y = y + 1\
496 end\
497 setCursor( x, y )\
498 else\
499 -- Move menu right\
500 nMenuItem = nMenuItem + 1\
501 if nMenuItem > #tMenuItems then\
502 nMenuItem = 1\
503 end\
504 redrawMenu()\
505 end\
506 elseif param == keys.delete then\
507 -- Delete\
508 if not bMenu and not bReadOnly then\
509 if x < string.len( tLines[y] ) + 1 then\
510 local sLine = tLines[y]\
511 tLines[y] = string.sub(sLine,1,x-1) .. string.sub(sLine,x+1)\
512 redrawLine(y)\
513 elseif y<#tLines then\
514 tLines[y] = tLines[y] .. tLines[y+1]\
515 table.remove( tLines, y+1 )\
516 redrawText()\
517 redrawMenu()\
518 end\
519 end\
520 elseif param == keys.backspace then\
521 -- Backspace\
522 if not bMenu and not bReadOnly then\
523 if x > 1 then\
524 -- Remove character\
525 local sLine = tLines[y]\
526 tLines[y] = string.sub(sLine,1,x-2) .. string.sub(sLine,x)\
527 redrawLine(y)\
528 \
529 x = x - 1\
530 setCursor( x, y )\
531 elseif y > 1 then\
532 -- Remove newline\
533 local sPrevLen = string.len( tLines[y-1] )\
534 tLines[y-1] = tLines[y-1] .. tLines[y]\
535 table.remove( tLines, y )\
536 redrawText()\
537 \
538 x = sPrevLen + 1\
539 y = y - 1\
540 setCursor( x, y )\
541 end\
542 end\
543 elseif param == keys.enter then\
544 -- Enter\
545 if not bMenu and not bReadOnly then\
546 -- Newline\
547 local sLine = tLines[y]\
548 local _,spaces=string.find(sLine,\"^[ ]+\")\
549 if not spaces then\
550 spaces=0\
551 end\
552 tLines[y] = string.sub(sLine,1,x-1)\
553 table.insert( tLines, y+1, string.rep(' ',spaces)..string.sub(sLine,x) )\
554 redrawText()\
555 \
556 x = spaces+1\
557 y = y + 1\
558 setCursor( x, y )\
559 elseif bMenu then\
560 -- Menu selection\
561 doMenuItem( nMenuItem )\
562 end\
563 elseif param == keys.leftCtrl or param == keys.rightCtrl then\
564 -- Menu toggle\
565 bMenu = not bMenu\
566 if bMenu then\
567 term.setCursorBlink( false )\
568 else\
569 term.setCursorBlink( true )\
570 end\
571 redrawMenu()\
572 end\
573 \
574 elseif sEvent == \"char\" then\
575 if not bMenu and not bReadOnly then\
576 -- Input text\
577 local sLine = tLines[y]\
578 tLines[y] = string.sub(sLine,1,x-1) .. param .. string.sub(sLine,x)\
579 redrawLine(y)\
580 \
581 x = x + 1\
582 setCursor( x, y )\
583 elseif bMenu then\
584 -- Select menu items\
585 for n,sMenuItem in ipairs( tMenuItems ) do\
586 if string.lower(string.sub(sMenuItem,1,1)) == string.lower(param) then\
587 doMenuItem( n )\
588 break\
589 end\
590 end\
591 end\
592\
593 elseif sEvent == \"paste\" then\
594 if not bMenu and not bReadOnly then\
595 -- Input text\
596 local sLine = tLines[y]\
597 tLines[y] = string.sub(sLine,1,x-1) .. param .. string.sub(sLine,x)\
598 redrawLine(y)\
599\
600 x = x + string.len( param )\
601 setCursor( x, y )\
602 end\
603 \
604 elseif sEvent == \"mouse_click\" then\
605 if not bMenu then\
606 if param == 1 then\
607 -- Left click\
608 local cx,cy = param2, param3\
609 if cy < h then\
610 y = math.min( math.max( scrollY + cy, 1 ), #tLines )\
611 x = math.min( math.max( scrollX + cx, 1 ), string.len( tLines[y] ) + 1 )\
612 setCursor( x, y )\
613 end\
614 end\
615 end\
616 \
617 elseif sEvent == \"mouse_scroll\" then\
618 if not bMenu then\
619 if param == -1 then\
620 -- Scroll up\
621 if scrollY > 0 then\
622 -- Move cursor up\
623 scrollY = scrollY - 1\
624 redrawText()\
625 end\
626 \
627 elseif param == 1 then\
628 -- Scroll down\
629 local nMaxScroll = #tLines - (h-1)\
630 if scrollY < nMaxScroll then\
631 -- Move cursor down\
632 scrollY = scrollY + 1\
633 redrawText()\
634 end\
635 \
636 end\
637 end\
638\
639 elseif sEvent == \"term_resize\" then\
640 w,h = term.getSize()\
641 setCursor( x, y )\
642 redrawMenu()\
643 redrawText()\
644\
645 end\
646end\
647\
648-- Cleanup\
649term.clear()\
650term.setCursorBlink( false )\
651term.setCursorPos( 1, 1 )",
652 ls = "shell.run(\"/bin/list\")\
653",
654 list = "\
655local tArgs = { ... }\
656\
657-- Get all the files in the directory\
658local sDir = shell.dir()\
659if tArgs[1] ~= nil then\
660 sDir = shell.resolve( tArgs[1] )\
661end\
662\
663-- Sort into dirs/files, and calculate column count\
664local tAll = fs.list( sDir )\
665local tFiles = {}\
666local tDirs = {}\
667local fFiles = {}\
668\
669for n, sItem in pairs( tAll ) do\
670 if string.sub( sItem, 1, 1 ) ~= \".\" then\
671 local sPath = fs.combine( sDir, sItem )\
672 if fs.isDir( sPath ) then\
673 if sPath ~= \"rom\" then\
674 table.insert( tDirs, sItem )\
675 end\
676 else\
677 local ffile = false\
678 if #sItem >= 3 then\
679 if sItem:sub(#sItem-2,#sItem) == \".ff\" then\
680 table.insert( fFiles, sItem )\
681 ffile = true\
682 end\
683 end\
684 if not ffile then\
685 table.insert( tFiles, sItem )\
686 end\
687 end\
688 end\
689end\
690table.sort( tDirs )\
691table.sort( tFiles )\
692\
693if term.isColour() then\
694 textutils.pagedTabulate( colors.blue, tDirs, colors.white, tFiles, colors.red, fFiles )\
695else\
696 textutils.pagedTabulate( tDirs, tFiles )\
697end\
698",
699 archive = "local tArgs = { ... }\
700\
701function saveFile( file, data )\
702 local f = fs.open( file, \"w\" )\
703 f.write( data )\
704 f.close( )\
705end\
706\
707function readFile( file )\
708 if fs.exists( file ) then\
709 local f = fs.open( file, \"r\" )\
710 local inside = f.readAll( )\
711 f.close()\
712 return inside\
713 end\
714end\
715\
716function tableToFile( t, folder )\
717 if not fs.exists( folder ) then fs.makeDir( folder ) end\
718 \
719 for k, v in pairs( t ) do\
720 if type( v ) == \"table\" then\
721 tableToFile( v, folder..\"/\"..k )\
722 end\
723 if type( v ) == \"string\" then\
724 saveFile( folder..\"/\"..k, v )\
725 end\
726 end\
727end\
728\
729function string.starts(String,Start)\
730 return string.sub(String,1,string.len(Start))==Start\
731end\
732\
733function filelistToTable( folder )\
734 local toReturn = { }\
735 local t = fs.list( folder )\
736 for i = 1, #t do\
737 if not string.starts(t[i],\"rom/\") then\
738 if fs.isDir( folder..\"/\"..t[i] ) then\
739 toReturn[t[i]] = filelistToTable( folder..\"/\"..t[i] )\
740 else\
741 toReturn[t[i]] = readFile( folder..\"/\"..t[i] )\
742 end\
743 end\
744 end\
745 return toReturn\
746end\
747\
748function printUsage( )\
749 print \"archive pack <folder> <archive>\"\
750 print \"archive compress <folder> <archive>\"\
751 print \"archive unpack <archive> <folder>\"\
752 print \"archive extract <archive> <folder>\"\
753 print \"archive installer <archive> <installer>\"\
754 print \"archive selfextract <archive> <installer>\"\
755end\
756\
757if tArgs[1] == \"pack\" or tArgs[1] == \"compress\" then\
758 if #tArgs < 3 then printUsage( ) return end\
759 local Archive = { }\
760 \
761 if fs.exists( tArgs[2] ) then\
762 print \"done prepairing, making archive\" \
763 Archive = filelistToTable( tArgs[2] )\
764 print \"done making archive now saving\"\
765 saveFile( tArgs[3], textutils.serialize( Archive ) )\
766 print \"done saving archive\"\
767 else\
768 print \"folder does not exist\"\
769 end\
770 \
771end\
772\
773if tArgs[1] == \"unpack\" or tArgs[1] == \"extract\" then\
774 if #tArgs < 3 then printUsage( ) return end\
775 \
776 print \"unpacking/extracting...\"\
777 tableToFile( textutils.unserialize( readFile( tArgs[2] ) ), tArgs[3] ) \
778 print \"unpacking/extracting complete\" \
779 \
780end\
781\
782if tArgs[1] == \"installer\" or tArgs[1] == \"selfextract\" then\
783 print( \"how is should the archive/program be called?\" )\
784 local name = read( )\
785 \
786 print( \"what is the folder to install extract it in? leave blank if you want to let the user enter one\" )\
787 local instdir = read( )\
788 \
789 print( \"what is the message for installing it?\" )\
790 local msg = read( )\
791 \
792 print( \"what os the message when its done?\")\
793 local msgdone = read( )\
794 \
795 print( \"what program should it execute when its done? leave blank for none\" )\
796 local doneexe = read( )\
797 \
798 local s = [[\
799 local archive = ]]..readFile( tArgs[2] )..[[ \
800 local installfolder = ']]..instdir..[['\
801 local name = ']]..name..[[' \
802 local msg = ']]..msg..[[' \
803 local msgdone = ']]..msgdone..[[' \
804 local doneexe = ']]..doneexe..[[' \
805 \
806 function saveFile( file, data )\
807 local f = fs.open( file, 'w' )\
808 f.write( data )\
809 f.close( )\
810 end\
811 \
812 function tableToFile( t, folder )\
813 if not fs.exists( folder ) then fs.makeDir( folder ) end\
814 for k, v in pairs( t ) do\
815 if type( v ) == 'table' then\
816 tableToFile( v, folder..'/'..k )\
817 end\
818 if type( v ) == 'string' then\
819 saveFile( folder..'/'..k, v )\
820 end\
821 end\
822 end\
823 \
824 if installfolder == '' then\
825 print 'please enter the folder where the archive is going to be installed in'\
826 installfolder = read( )\
827 end\
828 print( msg ) \
829 tableToFile( archive, installfolder )\
830 print( msgdone )\
831 if doneexe ~= \"\" then shell.run( doneexe ) end\
832 ]]\
833 \
834 local handle = io.open( tArgs[3], \"w\" )\
835 handle:write( s )\
836 handle:close( )\
837 print \"done making installer/self extractor\"\
838end",
839 clear = "term.setBackgroundColor(colors.black)\
840term.setTextColor(colors.white)\
841term.clear()\
842term.setCursorPos(1,1)\
843",
844 logout = "tArgs = { ... }\
845if #tArgs == 1 then\
846 if tArgs[1]:lower() == \"-s\" then\
847 _G[\"exitcmd\"] = true\
848 end\
849end\
850\
851\
852",
853 },
854 dev = {},
855 opt = {},
856 lib = {},
857 net = {},
858 mnt = {},
859 rom = {
860 programs = {
861 exit = "shell.exit()\
862",
863 monitor = "\
864function printUsage()\
865 print( \"Usage: monitor <name> <program> <arguments>\" )\
866 return\
867end\
868\
869local tArgs = { ... }\
870if #tArgs < 2 then\
871 printUsage()\
872 return\
873end\
874\
875local sName = tArgs[1]\
876if peripheral.getType( sName ) ~= \"monitor\" then\
877 print( \"No monitor named \".. sName )\
878 return\
879end\
880\
881local sProgram = tArgs[2]\
882local sPath = shell.resolveProgram( sProgram )\
883if sPath == nil then\
884 print( \"No such program: \"..sProgram )\
885 return\
886end\
887\
888print( \"Running \"..sProgram..\" on monitor \"..sName )\
889\
890local monitor = peripheral.wrap( sName )\
891local previousTerm = term.redirect( monitor )\
892\
893local co = coroutine.create( function()\
894 shell.run( sProgram, unpack( tArgs, 3 ) )\
895end )\
896\
897local function resume( ... )\
898 local ok, param = coroutine.resume( co, ... )\
899 if not ok then\
900 printError( param )\
901 end\
902 return param\
903end\
904\
905local ok, param = pcall( function()\
906 local sFilter = resume()\
907 while coroutine.status( co ) ~= \"dead\" do\
908 local tEvent = { os.pullEventRaw() }\
909 if sFilter == nil or tEvent[1] == sFilter or tEvent[1] == \"terminate\" then\
910 sFilter = resume( unpack( tEvent ) )\
911 end\
912 if coroutine.status( co ) ~= \"dead\" and (sFilter == nil or sFilter == \"mouse_click\") then\
913 if tEvent[1] == \"monitor_touch\" and tEvent[2] == sName then\
914 sFilter = resume( \"mouse_click\", 1, unpack( tEvent, 3 ) )\
915 end\
916 end\
917 if coroutine.status( co ) ~= \"dead\" and (sFilter == nil or sFilter == \"term_resize\") then\
918 if tEvent[1] == \"monitor_resize\" and tEvent[2] == sName then\
919 sFilter = resume( \"term_resize\" )\
920 end\
921 end\
922 end\
923end )\
924\
925term.redirect( previousTerm )\
926if not ok then\
927 printError( param )\
928end\
929 \
930",
931 copy = "\
932local tArgs = { ... }\
933if #tArgs < 2 then\
934 print( \"Usage: cp <source> <destination>\" )\
935 return\
936end\
937\
938local sSource = shell.resolve( tArgs[1] )\
939local sDest = shell.resolve( tArgs[2] )\
940local tFiles = fs.find( sSource )\
941if #tFiles > 0 then\
942 for n,sFile in ipairs( tFiles ) do\
943 if fs.isDir( sDest ) then\
944 fs.copy( sFile, fs.combine( sDest, fs.getName(sFile) ) )\
945 elseif #tFiles == 1 then\
946 fs.copy( sFile, sDest )\
947 else\
948 printError( \"Cannot overwrite file multiple times\" )\
949 return\
950 end\
951 end\
952else\
953 printError( \"No matching files\" )\
954end",
955 list = "\
956local tArgs = { ... }\
957\
958-- Get all the files in the directory\
959local sDir = shell.dir()\
960if tArgs[1] ~= nil then\
961 sDir = shell.resolve( tArgs[1] )\
962end\
963\
964-- Sort into dirs/files, and calculate column count\
965local tAll = fs.list( sDir )\
966local tFiles = {}\
967local tDirs = {}\
968\
969for n, sItem in pairs( tAll ) do\
970 if string.sub( sItem, 1, 1 ) ~= \".\" then\
971 local sPath = fs.combine( sDir, sItem )\
972 if fs.isDir( sPath ) then\
973 table.insert( tDirs, sItem )\
974 else\
975 table.insert( tFiles, sItem )\
976 end\
977 end\
978end\
979table.sort( tDirs )\
980table.sort( tFiles )\
981\
982if term.isColour() then\
983 textutils.pagedTabulate( colors.green, tDirs, colors.white, tFiles )\
984else\
985 textutils.pagedTabulate( tDirs, tFiles )\
986end\
987",
988 command = {
989 exec = "\
990local tArgs = { ... }\
991if not commands then\
992 printError( \"Requires a Command Computer.\" )\
993 return\
994end\
995if #tArgs == 0 then\
996 printError( \"Usage: exec <command>\" )\
997 return\
998end\
999\
1000local function printSuccess( text )\
1001 if term.isColor() then\
1002 term.setTextColor( colors.green )\
1003 end\
1004 print( text )\
1005 term.setTextColor( colors.white )\
1006end\
1007\
1008local sCommand = string.lower( tArgs[1] )\
1009for n=2,#tArgs do\
1010 sCommand = sCommand .. \" \" .. tArgs[n]\
1011end\
1012\
1013local bResult, tOutput = commands.exec( sCommand )\
1014if bResult then\
1015 printSuccess( \"Success\" )\
1016 if #tOutput > 0 then\
1017 for n=1,#tOutput do\
1018 print( tOutput[n] )\
1019 end\
1020 end\
1021else\
1022 printError( \"Failed\" )\
1023 if #tOutput > 0 then\
1024 for n=1,#tOutput do\
1025 print( tOutput[n] )\
1026 end\
1027 end\
1028end\
1029",
1030 commands = "\
1031if not commands then\
1032 printError( \"Requires a Command Computer.\" )\
1033 return\
1034end\
1035\
1036local tCommands = commands.list()\
1037table.sort( tCommands )\
1038\
1039if term.isColor() then\
1040 term.setTextColor( colors.green )\
1041end\
1042print( \"Available commands:\" )\
1043term.setTextColor( colors.white )\
1044\
1045textutils.pagedTabulate( tCommands )\
1046",
1047 },
1048 move = "\
1049local tArgs = { ... }\
1050if #tArgs < 2 then\
1051 print( \"Usage: mv <source> <destination>\" )\
1052 return\
1053end\
1054\
1055local sSource = shell.resolve( tArgs[1] )\
1056local sDest = shell.resolve( tArgs[2] )\
1057local tFiles = fs.find( sSource )\
1058if #tFiles > 0 then\
1059 for n,sFile in ipairs( tFiles ) do\
1060 if fs.isDir( sDest ) then\
1061 fs.move( sFile, fs.combine( sDest, fs.getName(sFile) ) )\
1062 elseif #tFiles == 1 then\
1063 fs.move( sFile, sDest )\
1064 else\
1065 printError( \"Cannot overwrite file multiple times\" )\
1066 return\
1067 end\
1068 end\
1069else\
1070 printError( \"No matching files\" )\
1071end\
1072",
1073 edit = "-- Get file to edit\
1074local tArgs = { ... }\
1075if #tArgs == 0 then\
1076 print( \"Usage: edit <path>\" )\
1077 return\
1078end\
1079\
1080-- Error checking\
1081local sPath = shell.resolve( tArgs[1] )\
1082local bReadOnly = fs.isReadOnly( sPath )\
1083if fs.exists( sPath ) and fs.isDir( sPath ) then\
1084 print( \"Cannot edit a directory.\" )\
1085 return\
1086end\
1087\
1088local x,y = 1,1\
1089local w,h = term.getSize()\
1090local scrollX, scrollY = 0,0\
1091\
1092local tLines = {}\
1093local bRunning = true\
1094\
1095-- Colours\
1096local highlightColour, keywordColour, commentColour, textColour, bgColour\
1097if term.isColour() then\
1098 bgColour = colours.black\
1099 textColour = colours.white\
1100 highlightColour = colours.yellow\
1101 keywordColour = colours.yellow\
1102 commentColour = colours.green\
1103 stringColour = colours.red\
1104else\
1105 bgColour = colours.black\
1106 textColour = colours.white\
1107 highlightColour = colours.white\
1108 keywordColour = colours.white\
1109 commentColour = colours.white\
1110 stringColour = colours.white\
1111end\
1112\
1113-- Menus\
1114local bMenu = false\
1115local nMenuItem = 1\
1116local tMenuItems\
1117if bReadOnly then\
1118 tMenuItems = { \"Exit\", \"Print\" }\
1119else\
1120 tMenuItems = { \"Save\", \"Exit\", \"Print\" }\
1121end\
1122 \
1123local sStatus = \"Press Ctrl to access menu\"\
1124if string.len( sStatus ) > w - 5 then\
1125 sStatus = \"Press Ctrl for menu\"\
1126end\
1127\
1128local function load( _sPath )\
1129 tLines = {}\
1130 if fs.exists( _sPath ) then\
1131 local file = io.open( _sPath, \"r\" )\
1132 local sLine = file:read()\
1133 while sLine do\
1134 table.insert( tLines, sLine )\
1135 sLine = file:read()\
1136 end\
1137 file:close()\
1138 end\
1139 \
1140 if #tLines == 0 then\
1141 table.insert( tLines, \"\" )\
1142 end\
1143end\
1144\
1145local function save( _sPath )\
1146 -- Create intervening folder\
1147 local sDir = sPath:sub(1, sPath:len() - fs.getName(sPath):len() )\
1148 if not fs.exists( sDir ) then\
1149 fs.makeDir( sDir )\
1150 end\
1151\
1152 -- Save\
1153 local file = nil\
1154 local function innerSave()\
1155 file = fs.open( _sPath, \"w\" )\
1156 if file then\
1157 for n, sLine in ipairs( tLines ) do\
1158 file.write( sLine .. \"\\n\" )\
1159 end\
1160 else\
1161 error( \"Failed to open \".._sPath )\
1162 end\
1163 end\
1164 \
1165 local ok = pcall( innerSave )\
1166 if file then \
1167 file.close()\
1168 end\
1169 return ok\
1170end\
1171\
1172local tKeywords = {\
1173 [\"and\"] = true,\
1174 [\"break\"] = true,\
1175 [\"do\"] = true,\
1176 [\"else\"] = true,\
1177 [\"elseif\"] = true,\
1178 [\"end\"] = true,\
1179 [\"false\"] = true,\
1180 [\"for\"] = true,\
1181 [\"function\"] = true,\
1182 [\"if\"] = true,\
1183 [\"in\"] = true,\
1184 [\"local\"] = true,\
1185 [\"nil\"] = true,\
1186 [\"not\"] = true,\
1187 [\"or\"] = true,\
1188 [\"repeat\"] = true,\
1189 [\"return\"] = true,\
1190 [\"then\"] = true,\
1191 [\"true\"] = true,\
1192 [\"until\"]= true,\
1193 [\"while\"] = true,\
1194}\
1195\
1196local function tryWrite( sLine, regex, colour )\
1197 local match = string.match( sLine, regex )\
1198 if match then\
1199 if type(colour) == \"number\" then\
1200 term.setTextColour( colour )\
1201 else\
1202 term.setTextColour( colour(match) )\
1203 end\
1204 term.write( match )\
1205 term.setTextColour( textColour )\
1206 return string.sub( sLine, string.len(match) + 1 )\
1207 end\
1208 return nil\
1209end\
1210\
1211local function writeHighlighted( sLine )\
1212 while string.len(sLine) > 0 do \
1213 sLine = \
1214 tryWrite( sLine, \"^%-%-%[%[.-%]%]\", commentColour ) or\
1215 tryWrite( sLine, \"^%-%-.*\", commentColour ) or\
1216 tryWrite( sLine, \"^\\\".-[^\\\\]\\\"\", stringColour ) or\
1217 tryWrite( sLine, \"^\\'.-[^\\\\]\\'\", stringColour ) or\
1218 tryWrite( sLine, \"^%[%[.-%]%]\", stringColour ) or\
1219 tryWrite( sLine, \"^[%w_]+\", function( match )\
1220 if tKeywords[ match ] then\
1221 return keywordColour\
1222 end\
1223 return textColour\
1224 end ) or\
1225 tryWrite( sLine, \"^[^%w_]\", textColour )\
1226 end\
1227end\
1228\
1229local function redrawText()\
1230 for y=1,h-1 do\
1231 term.setCursorPos( 1 - scrollX, y )\
1232 term.clearLine()\
1233\
1234 local sLine = tLines[ y + scrollY ]\
1235 if sLine ~= nil then\
1236 writeHighlighted( sLine )\
1237 end\
1238 end\
1239 term.setCursorPos( x - scrollX, y - scrollY )\
1240end\
1241\
1242local function redrawLine(_nY)\
1243 local sLine = tLines[_nY]\
1244 term.setCursorPos( 1 - scrollX, _nY - scrollY )\
1245 term.clearLine()\
1246 writeHighlighted( sLine )\
1247 term.setCursorPos( x - scrollX, _nY - scrollY )\
1248end\
1249\
1250local function redrawMenu()\
1251 -- Clear line\
1252 term.setCursorPos( 1, h )\
1253 term.clearLine()\
1254\
1255 -- Draw line numbers\
1256 term.setCursorPos( w - string.len( \"Ln \"..y ) + 1, h )\
1257 term.setTextColour( highlightColour )\
1258 term.write( \"Ln \" )\
1259 term.setTextColour( textColour )\
1260 term.write( y )\
1261\
1262 term.setCursorPos( 1, h )\
1263 if bMenu then\
1264 -- Draw menu\
1265 term.setTextColour( textColour )\
1266 for nItem,sItem in pairs( tMenuItems ) do\
1267 if nItem == nMenuItem then\
1268 term.setTextColour( highlightColour )\
1269 term.write( \"[\" )\
1270 term.setTextColour( textColour )\
1271 term.write( sItem )\
1272 term.setTextColour( highlightColour )\
1273 term.write( \"]\" )\
1274 term.setTextColour( textColour )\
1275 else\
1276 term.write( \" \"..sItem..\" \" )\
1277 end\
1278 end\
1279 else\
1280 -- Draw status\
1281 term.setTextColour( highlightColour )\
1282 term.write( sStatus )\
1283 term.setTextColour( textColour )\
1284 end\
1285\
1286 -- Reset cursor\
1287 term.setCursorPos( x - scrollX, y - scrollY )\
1288end\
1289\
1290local tMenuFuncs = { \
1291 Save=function()\
1292 if bReadOnly then\
1293 sStatus = \"Access denied\"\
1294 else\
1295 local ok, err = save( sPath )\
1296 if ok then\
1297 sStatus=\"Saved to \"..sPath\
1298 else\
1299 sStatus=\"Error saving to \"..sPath\
1300 end\
1301 end\
1302 redrawMenu()\
1303 end,\
1304 Print=function()\
1305 local printer = peripheral.find( \"printer\" )\
1306 if not printer then\
1307 sStatus = \"No printer attached\"\
1308 return\
1309 end\
1310\
1311 local nPage = 0\
1312 local sName = fs.getName( sPath )\
1313 if printer.getInkLevel() < 1 then\
1314 sStatus = \"Printer out of ink\"\
1315 return\
1316 elseif printer.getPaperLevel() < 1 then\
1317 sStatus = \"Printer out of paper\"\
1318 return\
1319 end\
1320\
1321 local screenTerminal = term.current()\
1322 local printerTerminal = {\
1323 getCursorPos = printer.getCursorPos,\
1324 setCursorPos = printer.setCursorPos,\
1325 getSize = printer.getPageSize,\
1326 write = printer.write,\
1327 }\
1328 printerTerminal.scroll = function()\
1329 if nPage == 1 then\
1330 printer.setPageTitle( sName..\" (page \"..nPage..\")\" ) \
1331 end\
1332 \
1333 while not printer.newPage() do\
1334 if printer.getInkLevel() < 1 then\
1335 sStatus = \"Printer out of ink, please refill\"\
1336 elseif printer.getPaperLevel() < 1 then\
1337 sStatus = \"Printer out of paper, please refill\"\
1338 else\
1339 sStatus = \"Printer output tray full, please empty\"\
1340 end\
1341 \
1342 term.redirect( screenTerminal )\
1343 redrawMenu()\
1344 term.redirect( printerTerminal )\
1345 \
1346 local timer = os.startTimer(0.5)\
1347 sleep(0.5)\
1348 end\
1349\
1350 nPage = nPage + 1\
1351 if nPage == 1 then\
1352 printer.setPageTitle( sName )\
1353 else\
1354 printer.setPageTitle( sName..\" (page \"..nPage..\")\" )\
1355 end\
1356 end\
1357 \
1358 bMenu = false\
1359 term.redirect( printerTerminal )\
1360 local ok, error = pcall( function()\
1361 term.scroll()\
1362 for n, sLine in ipairs( tLines ) do\
1363 print( sLine )\
1364 end\
1365 end )\
1366 term.redirect( screenTerminal )\
1367 if not ok then\
1368 print( error )\
1369 end\
1370 \
1371 while not printer.endPage() do\
1372 sStatus = \"Printer output tray full, please empty\"\
1373 redrawMenu()\
1374 sleep( 0.5 )\
1375 end\
1376 bMenu = true\
1377 \
1378 if nPage > 1 then\
1379 sStatus = \"Printed \"..nPage..\" Pages\"\
1380 else\
1381 sStatus = \"Printed 1 Page\"\
1382 end\
1383 redrawMenu()\
1384 end,\
1385 Exit=function()\
1386 bRunning = false\
1387 end\
1388}\
1389\
1390local function doMenuItem( _n )\
1391 tMenuFuncs[tMenuItems[_n]]()\
1392 if bMenu then\
1393 bMenu = false\
1394 term.setCursorBlink( true )\
1395 end\
1396 redrawMenu()\
1397end\
1398\
1399local function setCursor( x, y )\
1400 local screenX = x - scrollX\
1401 local screenY = y - scrollY\
1402 \
1403 local bRedraw = false\
1404 if screenX < 1 then\
1405 scrollX = x - 1\
1406 screenX = 1\
1407 bRedraw = true\
1408 elseif screenX > w then\
1409 scrollX = x - w\
1410 screenX = w\
1411 bRedraw = true\
1412 end\
1413 \
1414 if screenY < 1 then\
1415 scrollY = y - 1\
1416 screenY = 1\
1417 bRedraw = true\
1418 elseif screenY > h-1 then\
1419 scrollY = y - (h-1)\
1420 screenY = h-1\
1421 bRedraw = true\
1422 end\
1423 \
1424 if bRedraw then\
1425 redrawText()\
1426 end\
1427 term.setCursorPos( screenX, screenY )\
1428 \
1429 -- Statusbar now pertains to menu, it would probably be safe to redraw the menu on every key event.\
1430 redrawMenu()\
1431end\
1432\
1433-- Actual program functionality begins\
1434load(sPath)\
1435\
1436term.setBackgroundColour( bgColour )\
1437term.clear()\
1438term.setCursorPos(x,y)\
1439term.setCursorBlink( true )\
1440\
1441redrawText()\
1442redrawMenu()\
1443\
1444-- Handle input\
1445while bRunning do\
1446 local sEvent, param, param2, param3 = os.pullEvent()\
1447 if sEvent == \"key\" then\
1448 if param == keys.up then\
1449 -- Up\
1450 if not bMenu then\
1451 if y > 1 then\
1452 -- Move cursor up\
1453 y = y - 1\
1454 x = math.min( x, string.len( tLines[y] ) + 1 )\
1455 setCursor( x, y )\
1456 end\
1457 end\
1458 elseif param == keys.down then\
1459 -- Down\
1460 if not bMenu then\
1461 -- Move cursor down\
1462 if y < #tLines then\
1463 y = y + 1\
1464 x = math.min( x, string.len( tLines[y] ) + 1 )\
1465 setCursor( x, y )\
1466 end\
1467 end\
1468 elseif param == keys.tab then\
1469 -- Tab\
1470 if not bMenu and not bReadOnly then\
1471 -- Indent line\
1472 tLines[y]=\" \"..tLines[y]\
1473 x = x + 2\
1474 setCursor( x, y )\
1475 redrawLine(y)\
1476 end\
1477 elseif param == keys.pageUp then\
1478 -- Page Up\
1479 if not bMenu then\
1480 -- Move up a page\
1481 if y - (h - 1) >= 1 then\
1482 y = y - (h - 1)\
1483 else\
1484 y = 1\
1485 end\
1486 x = math.min( x, string.len( tLines[y] ) + 1 )\
1487 setCursor( x, y )\
1488 end\
1489 elseif param == keys.pageDown then\
1490 -- Page Down\
1491 if not bMenu then\
1492 -- Move down a page\
1493 if y + (h - 1) <= #tLines then\
1494 y = y + (h - 1)\
1495 else\
1496 y = #tLines\
1497 end\
1498 x = math.min( x, string.len( tLines[y] ) + 1 )\
1499 setCursor( x, y )\
1500 end\
1501 elseif param == keys.home then\
1502 -- Home\
1503 if not bMenu then\
1504 -- Move cursor to the beginning\
1505 x=1\
1506 setCursor(x,y)\
1507 end\
1508 elseif param == keys[\"end\"] then\
1509 -- End\
1510 if not bMenu then\
1511 -- Move cursor to the end\
1512 x = string.len( tLines[y] ) + 1\
1513 setCursor(x,y)\
1514 end\
1515 elseif param == keys.left then\
1516 -- Left\
1517 if not bMenu then\
1518 if x > 1 then\
1519 -- Move cursor left\
1520 x = x - 1\
1521 elseif x==1 and y>1 then\
1522 x = string.len( tLines[y-1] ) + 1\
1523 y = y - 1\
1524 end\
1525 setCursor( x, y )\
1526 else\
1527 -- Move menu left\
1528 nMenuItem = nMenuItem - 1\
1529 if nMenuItem < 1 then\
1530 nMenuItem = #tMenuItems\
1531 end\
1532 redrawMenu()\
1533 end\
1534 elseif param == keys.right then\
1535 -- Right\
1536 if not bMenu then\
1537 if x < string.len( tLines[y] ) + 1 then\
1538 -- Move cursor right\
1539 x = x + 1\
1540 elseif x==string.len( tLines[y] ) + 1 and y<#tLines then\
1541 x = 1\
1542 y = y + 1\
1543 end\
1544 setCursor( x, y )\
1545 else\
1546 -- Move menu right\
1547 nMenuItem = nMenuItem + 1\
1548 if nMenuItem > #tMenuItems then\
1549 nMenuItem = 1\
1550 end\
1551 redrawMenu()\
1552 end\
1553 elseif param == keys.delete then\
1554 -- Delete\
1555 if not bMenu and not bReadOnly then\
1556 if x < string.len( tLines[y] ) + 1 then\
1557 local sLine = tLines[y]\
1558 tLines[y] = string.sub(sLine,1,x-1) .. string.sub(sLine,x+1)\
1559 redrawLine(y)\
1560 elseif y<#tLines then\
1561 tLines[y] = tLines[y] .. tLines[y+1]\
1562 table.remove( tLines, y+1 )\
1563 redrawText()\
1564 redrawMenu()\
1565 end\
1566 end\
1567 elseif param == keys.backspace then\
1568 -- Backspace\
1569 if not bMenu and not bReadOnly then\
1570 if x > 1 then\
1571 -- Remove character\
1572 local sLine = tLines[y]\
1573 tLines[y] = string.sub(sLine,1,x-2) .. string.sub(sLine,x)\
1574 redrawLine(y)\
1575 \
1576 x = x - 1\
1577 setCursor( x, y )\
1578 elseif y > 1 then\
1579 -- Remove newline\
1580 local sPrevLen = string.len( tLines[y-1] )\
1581 tLines[y-1] = tLines[y-1] .. tLines[y]\
1582 table.remove( tLines, y )\
1583 redrawText()\
1584 \
1585 x = sPrevLen + 1\
1586 y = y - 1\
1587 setCursor( x, y )\
1588 end\
1589 end\
1590 elseif param == keys.enter then\
1591 -- Enter\
1592 if not bMenu and not bReadOnly then\
1593 -- Newline\
1594 local sLine = tLines[y]\
1595 local _,spaces=string.find(sLine,\"^[ ]+\")\
1596 if not spaces then\
1597 spaces=0\
1598 end\
1599 tLines[y] = string.sub(sLine,1,x-1)\
1600 table.insert( tLines, y+1, string.rep(' ',spaces)..string.sub(sLine,x) )\
1601 redrawText()\
1602 \
1603 x = spaces+1\
1604 y = y + 1\
1605 setCursor( x, y )\
1606 elseif bMenu then\
1607 -- Menu selection\
1608 doMenuItem( nMenuItem )\
1609 end\
1610 elseif param == keys.leftCtrl or param == keys.rightCtrl then\
1611 -- Menu toggle\
1612 bMenu = not bMenu\
1613 if bMenu then\
1614 term.setCursorBlink( false )\
1615 else\
1616 term.setCursorBlink( true )\
1617 end\
1618 redrawMenu()\
1619 end\
1620 \
1621 elseif sEvent == \"char\" then\
1622 if not bMenu and not bReadOnly then\
1623 -- Input text\
1624 local sLine = tLines[y]\
1625 tLines[y] = string.sub(sLine,1,x-1) .. param .. string.sub(sLine,x)\
1626 redrawLine(y)\
1627 \
1628 x = x + 1\
1629 setCursor( x, y )\
1630 elseif bMenu then\
1631 -- Select menu items\
1632 for n,sMenuItem in ipairs( tMenuItems ) do\
1633 if string.lower(string.sub(sMenuItem,1,1)) == string.lower(param) then\
1634 doMenuItem( n )\
1635 break\
1636 end\
1637 end\
1638 end\
1639\
1640 elseif sEvent == \"paste\" then\
1641 if not bMenu and not bReadOnly then\
1642 -- Input text\
1643 local sLine = tLines[y]\
1644 tLines[y] = string.sub(sLine,1,x-1) .. param .. string.sub(sLine,x)\
1645 redrawLine(y)\
1646\
1647 x = x + string.len( param )\
1648 setCursor( x, y )\
1649 end\
1650 \
1651 elseif sEvent == \"mouse_click\" then\
1652 if not bMenu then\
1653 if param == 1 then\
1654 -- Left click\
1655 local cx,cy = param2, param3\
1656 if cy < h then\
1657 y = math.min( math.max( scrollY + cy, 1 ), #tLines )\
1658 x = math.min( math.max( scrollX + cx, 1 ), string.len( tLines[y] ) + 1 )\
1659 setCursor( x, y )\
1660 end\
1661 end\
1662 end\
1663 \
1664 elseif sEvent == \"mouse_scroll\" then\
1665 if not bMenu then\
1666 if param == -1 then\
1667 -- Scroll up\
1668 if scrollY > 0 then\
1669 -- Move cursor up\
1670 scrollY = scrollY - 1\
1671 redrawText()\
1672 end\
1673 \
1674 elseif param == 1 then\
1675 -- Scroll down\
1676 local nMaxScroll = #tLines - (h-1)\
1677 if scrollY < nMaxScroll then\
1678 -- Move cursor down\
1679 scrollY = scrollY + 1\
1680 redrawText()\
1681 end\
1682 \
1683 end\
1684 end\
1685\
1686 elseif sEvent == \"term_resize\" then\
1687 w,h = term.getSize()\
1688 setCursor( x, y )\
1689 redrawMenu()\
1690 redrawText()\
1691\
1692 end\
1693end\
1694\
1695-- Cleanup\
1696term.clear()\
1697term.setCursorBlink( false )\
1698term.setCursorPos( 1, 1 )",
1699 reboot = "if term.isColour() then\
1700 term.setTextColour( colours.yellow )\
1701end\
1702print( \"Goodbye\" )\
1703term.setTextColour( colours.white )\
1704\
1705sleep( 1 )\
1706os.reboot()\
1707",
1708 shutdown = "if term.isColour() then\
1709 term.setTextColour( colours.yellow )\
1710end\
1711print( \"Goodbye\" )\
1712term.setTextColour( colours.white )\
1713\
1714sleep( 1 )\
1715os.shutdown()\
1716",
1717 redstone = "\
1718local tArgs = { ... }\
1719\
1720local function printUsage()\
1721 print( \"Usages:\" )\
1722 print( \"redstone probe\" )\
1723 print( \"redstone set <side> <value>\" )\
1724 print( \"redstone set <side> <color> <value>\" )\
1725 print( \"redstone pulse <side> <count> <period>\" )\
1726end\
1727\
1728local sCommand = tArgs[1]\
1729if sCommand == \"probe\" then\
1730 -- \"redstone probe\"\
1731 -- Regular input\
1732 print( \"Redstone inputs: \" )\
1733\
1734 local count = 0\
1735 local bundledCount = 0\
1736 for n,sSide in ipairs( redstone.getSides() ) do\
1737 if redstone.getBundledInput( sSide ) > 0 then\
1738 bundledCount = bundledCount + 1\
1739 end\
1740 if redstone.getInput( sSide ) then\
1741 if count > 0 then\
1742 io.write( \", \" )\
1743 end\
1744 io.write( sSide )\
1745 count = count + 1\
1746 end\
1747 end\
1748 if count > 0 then\
1749 print( \".\" )\
1750 else\
1751 print( \"None.\" )\
1752 end\
1753\
1754 -- Bundled input\
1755 if bundledCount > 0 then\
1756 print()\
1757 print( \"Bundled inputs:\" )\
1758 for i,sSide in ipairs( redstone.getSides() ) do\
1759 local nInput = redstone.getBundledInput( sSide )\
1760 if nInput ~= 0 then\
1761 write( sSide..\": \" )\
1762 local count = 0\
1763 for sColour,nColour in pairs( colors ) do\
1764 if type( nColour ) == \"number\" and colors.test( nInput, nColour ) then\
1765 if count > 0 then\
1766 write( \", \" )\
1767 end\
1768 if term.isColour() then\
1769 term.setTextColour( nColour )\
1770 end\
1771 write( sColour )\
1772 if term.isColour() then\
1773 term.setTextColour( colours.white )\
1774 end\
1775 count = count + 1\
1776 end\
1777 end\
1778 print( \".\" )\
1779 end\
1780 end\
1781 end\
1782\
1783elseif sCommand == \"pulse\" then\
1784 -- \"redstone pulse\"\
1785 local sSide = tArgs[2]\
1786 local nCount = tonumber( tArgs[3] ) or 1\
1787 local nPeriod = tonumber( tArgs[4] ) or 0.5\
1788 for n=1,nCount do\
1789 redstone.setOutput( sSide, true )\
1790 sleep( nPeriod / 2 )\
1791 redstone.setOutput( sSide, false )\
1792 sleep( nPeriod / 2 )\
1793 end\
1794\
1795elseif sCommand == \"set\" then\
1796 -- \"redstone set\"\
1797 local sSide = tArgs[2]\
1798 if #tArgs > 3 then\
1799 -- Bundled cable output\
1800 local sColour = tArgs[3]\
1801 local nColour = colors[sColour] or colours[sColour]\
1802 if type(nColour) ~= \"number\" then\
1803 printError( \"No such color\" )\
1804 return\
1805 end\
1806\
1807 local sValue = tArgs[4]\
1808 if sValue == \"true\" then\
1809 rs.setBundledOutput( sSide, colors.combine( rs.getBundledOutput( sSide ), nColour ) )\
1810 elseif sValue == \"false\" then\
1811 rs.setBundledOutput( sSide, colors.subtract( rs.getBundledOutput( sSide ), nColour ) )\
1812 else\
1813 print( \"Value must be boolean\" )\
1814 end\
1815 else\
1816 -- Regular output\
1817 local sValue = tArgs[3]\
1818 local nValue = tonumber(sValue)\
1819 if sValue == \"true\" then\
1820 rs.setOutput( sSide, true )\
1821 elseif sValue == \"false\" then\
1822 rs.setOutput( sSide, false )\
1823 elseif nValue and nValue >= 0 and nValue <= 15 then\
1824 rs.setAnalogOutput( sSide, nValue )\
1825 else\
1826 print( \"Value must be boolean or 0-15\" )\
1827 end\
1828 end\
1829\
1830else\
1831 -- Something else\
1832 printUsage()\
1833\
1834end\
1835",
1836 http = {
1837 pastebin = "\
1838local function printUsage()\
1839 print( \"Usages:\" )\
1840 print( \"pastebin put <filename>\" )\
1841 print( \"pastebin get <code> <filename>\" )\
1842 print( \"pastebin run <code> <arguments>\" )\
1843end\
1844 \
1845local tArgs = { ... }\
1846if #tArgs < 2 then\
1847 printUsage()\
1848 return\
1849end\
1850 \
1851if not http then\
1852 printError( \"Pastebin requires http API\" )\
1853 printError( \"Set http_enable to true in ComputerCraft.cfg\" )\
1854 return\
1855end\
1856 \
1857local function get(paste)\
1858 write( \"Connecting to pastebin.com... \" )\
1859 local response = http.get(\
1860 \"http://pastebin.com/raw.php?i=\"..textutils.urlEncode( paste )\
1861 )\
1862 \
1863 if response then\
1864 print( \"Success.\" )\
1865 \
1866 local sResponse = response.readAll()\
1867 response.close()\
1868 return sResponse\
1869 else\
1870 printError( \"Failed.\" )\
1871 end\
1872end\
1873 \
1874local sCommand = tArgs[1]\
1875if sCommand == \"put\" then\
1876 -- Upload a file to pastebin.com\
1877 -- Determine file to upload\
1878 local sFile = tArgs[2]\
1879 local sPath = shell.resolve( sFile )\
1880 if not fs.exists( sPath ) or fs.isDir( sPath ) then\
1881 print( \"No such file\" )\
1882 return\
1883 end\
1884 \
1885 -- Read in the file\
1886 local sName = fs.getName( sPath )\
1887 local file = fs.open( sPath, \"r\" )\
1888 local sText = file.readAll()\
1889 file.close()\
1890 \
1891 -- POST the contents to pastebin\
1892 write( \"Connecting to pastebin.com... \" )\
1893 local key = \"0ec2eb25b6166c0c27a394ae118ad829\"\
1894 local response = http.post(\
1895 \"http://pastebin.com/api/api_post.php\", \
1896 \"api_option=paste&\"..\
1897 \"api_dev_key=\"..key..\"&\"..\
1898 \"api_paste_format=lua&\"..\
1899 \"api_paste_name=\"..textutils.urlEncode(sName)..\"&\"..\
1900 \"api_paste_code=\"..textutils.urlEncode(sText)\
1901 )\
1902 \
1903 if response then\
1904 print( \"Success.\" )\
1905 \
1906 local sResponse = response.readAll()\
1907 response.close()\
1908 \
1909 local sCode = string.match( sResponse, \"[^/]+$\" )\
1910 print( \"Uploaded as \"..sResponse )\
1911 print( \"Run \\\"pastebin get \"..sCode..\"\\\" to download anywhere\" )\
1912 \
1913 else\
1914 print( \"Failed.\" )\
1915 end\
1916 \
1917elseif sCommand == \"get\" then\
1918 -- Download a file from pastebin.com\
1919 if #tArgs < 3 then\
1920 printUsage()\
1921 return\
1922 end\
1923 \
1924 -- Determine file to download\
1925 local sCode = tArgs[2]\
1926 local sFile = tArgs[3]\
1927 local sPath = shell.resolve( sFile )\
1928 if fs.exists( sPath ) then\
1929 print( \"File already exists\" )\
1930 return\
1931 end\
1932 \
1933 -- GET the contents from pastebin\
1934 local res = get(sCode)\
1935 if res then \
1936 local file = fs.open( sPath, \"w\" )\
1937 file.write( res )\
1938 file.close()\
1939 \
1940 print( \"Downloaded as \"..sFile )\
1941 end \
1942elseif sCommand == \"run\" then\
1943 local sCode = tArgs[2]\
1944 \
1945 local res = get(sCode)\
1946 if res then\
1947 local func, err = loadstring(res)\
1948 if not func then\
1949 printError( err )\
1950 return\
1951 end\
1952 setfenv(func, getfenv())\
1953 local success, msg = pcall(func, unpack(tArgs, 3))\
1954 if not success then\
1955 printError( msg )\
1956 end\
1957 end\
1958else\
1959 printUsage()\
1960 return\
1961end",
1962 },
1963 programs = "\
1964local bAll = false\
1965local tArgs = { ... }\
1966if #tArgs > 0 and tArgs[1] == \"all\" then\
1967 bAll = true\
1968end\
1969\
1970local tPrograms = shell.programs( bAll )\
1971textutils.pagedTabulate( tPrograms )\
1972",
1973 pocket = {
1974 falling = "--[[\
1975Falling - Based on Tetris by Alexey Pajitnov\
1976This version written by Gopher, at the request of Dan200, for\
1977ComputerCraft v1.6. No particular rights are reserved.\
1978--]]\
1979\
1980local function colorass(c,bw)\
1981 return term.isColor() and c or bw\
1982end\
1983\
1984local block_s1= {\
1985 {\
1986 { 1,0,0,0, },\
1987 { 1,1,0,0, },\
1988 { 0,1,0,0, },\
1989 { 0,0,0,0, },\
1990 },\
1991 {\
1992 { 0,0,0,0, },\
1993 { 0,1,1,0, },\
1994 { 1,1,0,0, },\
1995 { 0,0,0,0, },\
1996 },\
1997 ch=colorass(\" \",\"{}\"),\
1998 fg=colorass(colors.blue,colors.black),\
1999 bg=colorass(colors.cyan,colors.white),\
2000 }\
2001local block_s2= {\
2002 {\
2003 { 0,1,0,0, },\
2004 { 1,1,0,0, },\
2005 { 1,0,0,0, },\
2006 { 0,0,0,0, },\
2007 },\
2008 {\
2009 { 0,0,0,0, },\
2010 { 1,1,0,0, },\
2011 { 0,1,1,0, },\
2012 { 0,0,0,0, },\
2013 },\
2014 ch=colorass(\" \",\"{}\"),\
2015 fg=colorass(colors.green,colors.black),\
2016 bg=colorass(colors.lime,colors.white),\
2017 }\
2018local block_line = {\
2019 {\
2020 { 0,1,0,0, },\
2021 { 0,1,0,0, },\
2022 { 0,1,0,0, },\
2023 { 0,1,0,0, },\
2024 },\
2025 {\
2026 { 0,0,0,0, },\
2027 { 1,1,1,1, },\
2028 { 0,0,0,0, },\
2029 { 0,0,0,0, },\
2030 },\
2031 ch=colorass(\" \",\"[]\"),\
2032 fg=colorass(colors.pink,colors.black),\
2033 bg=colorass(colors.red,colors.white),\
2034 }\
2035local block_square = {\
2036 {\
2037 { 1,1,0,0, },\
2038 { 1,1,0,0, },\
2039 { 0,0,0,0, },\
2040 { 0,0,0,0, },\
2041 },\
2042 ch=colorass(\" \",\"[]\"),\
2043 fg=colorass(colors.lightBlue,colors.black),\
2044 bg=colorass(colors.blue,colors.white),\
2045 }\
2046local block_L1 = {\
2047 {\
2048 { 1,1,0,0, },\
2049 { 0,1,0,0, },\
2050 { 0,1,0,0, },\
2051 { 0,0,0,0, },\
2052 },\
2053 {\
2054 { 0,0,0,0, },\
2055 { 1,1,1,0, },\
2056 { 1,0,0,0, },\
2057 { 0,0,0,0, },\
2058 },\
2059 {\
2060 { 0,1,0,0, },\
2061 { 0,1,0,0, },\
2062 { 0,1,1,0, },\
2063 { 0,0,0,0, },\
2064 },\
2065 {\
2066 { 0,0,1,0, },\
2067 { 1,1,1,0, },\
2068 { 0,0,0,0, },\
2069 { 0,0,0,0, },\
2070 },\
2071 ch=colorass(\" \",\"()\"),\
2072 fg=colorass(colors.orange,colors.black),\
2073 bg=colorass(colors.yellow,colors.white),\
2074 }\
2075local block_L2 = {\
2076 {\
2077 { 0,1,0,0, },\
2078 { 0,1,0,0, },\
2079 { 1,1,0,0, },\
2080 { 0,0,0,0, },\
2081 },\
2082 {\
2083 { 0,0,0,0, },\
2084 { 1,1,1,0, },\
2085 { 0,0,1,0, },\
2086 { 0,0,0,0, },\
2087 },\
2088 {\
2089 { 0,1,1,0, },\
2090 { 0,1,0,0, },\
2091 { 0,1,0,0, },\
2092 { 0,0,0,0, },\
2093 },\
2094 {\
2095 { 1,0,0,0, },\
2096 { 1,1,1,0, },\
2097 { 0,0,0,0, },\
2098 { 0,0,0,0, },\
2099 },\
2100 ch=colorass(\" \",\"()\"),\
2101 fg=colorass(colors.brown,colors.black),\
2102 bg=colorass(colors.orange,colors.white),\
2103 }\
2104local block_T = {\
2105 {\
2106 { 0,1,0,0, },\
2107 { 1,1,0,0, },\
2108 { 0,1,0,0, },\
2109 { 0,0,0,0, },\
2110 },\
2111 {\
2112 { 0,0,0,0, },\
2113 { 1,1,1,0, },\
2114 { 0,1,0,0, },\
2115 { 0,0,0,0, },\
2116 },\
2117 {\
2118 { 0,1,0,0, },\
2119 { 0,1,1,0, },\
2120 { 0,1,0,0, },\
2121 { 0,0,0,0, },\
2122 },\
2123 {\
2124 { 0,1,0,0, },\
2125 { 1,1,1,0, },\
2126 { 0,0,0,0, },\
2127 { 0,0,0,0, },\
2128 },\
2129 ch=colorass(\" \",\"<>\"),\
2130 fg=colorass(colors.cyan,colors.black),\
2131 bg=colorass(colors.purple,colors.white),\
2132 }\
2133\
2134local blocks={ block_line, block_square, block_s1, block_s2, block_L1, block_L2, block_T}\
2135\
2136local points={4,10,30,120}\
2137\
2138local function lpad(text,amt)\
2139 text=tostring(text)\
2140 return string.rep(\" \",amt-#text)..text\
2141end\
2142\
2143local width,height=term.getSize()\
2144\
2145if height<19 or width<26 then\
2146 print(\"Your screen is too small to play :(\")\
2147 return\
2148end\
2149\
2150\
2151local speedsByLevel={\
2152 1.2,\
2153 1.0,\
2154 .8,\
2155 .65,\
2156 .5,\
2157 .4,\
2158 .3,\
2159 .25,\
2160 .2,\
2161 .15,\
2162 .1,\
2163 .05,}\
2164\
2165local level=1\
2166\
2167local function playGame()\
2168 local score=0\
2169 local lines=0\
2170 local initialLevel=level\
2171 local next=blocks[math.random(1,#blocks)]\
2172\
2173 local pit={}\
2174\
2175\
2176 local heightAdjust=0\
2177\
2178 if height<=19 then\
2179 heightAdjust=1\
2180 end\
2181\
2182\
2183\
2184 local function drawScreen()\
2185 term.setTextColor(colors.white)\
2186 term.setBackgroundColor(colors.black)\
2187 term.clear()\
2188\
2189 term.setTextColor(colors.black)\
2190 term.setBackgroundColor(colorass(colors.lightGray, colors.white))\
2191 term.setCursorPos(22,2)\
2192 term.write(\"Score\") --score\
2193 term.setCursorPos(22,5)\
2194 term.write(\"Level\") --level\
2195 term.setCursorPos(22,8)\
2196 term.write(\"Lines\") --lines\
2197 term.setCursorPos(22,12)\
2198 term.write(\"Next\") --next\
2199\
2200 term.setCursorPos(21,1)\
2201 term.write(\" \")\
2202 term.setCursorPos(21,2)\
2203 term.write(\" \") --score\
2204 term.setCursorPos(21,3)\
2205 term.write(\" \")\
2206 term.setCursorPos(21,4)\
2207 term.write(\" \")\
2208 term.setCursorPos(21,5)\
2209 term.write(\" \") --level\
2210 term.setCursorPos(21,6)\
2211 term.write(\" \")\
2212 term.setCursorPos(21,7)\
2213 term.write(\" \")\
2214 term.setCursorPos(21,8)\
2215 term.write(\" \") --lines\
2216 term.setCursorPos(21,9)\
2217 term.write(\" \")\
2218 term.setCursorPos(21,10)\
2219 term.write(\" \")\
2220 term.setCursorPos(21,11)\
2221 term.write(\" \")\
2222 term.setCursorPos(21,12)\
2223 term.write(\" \") --next\
2224 term.setCursorPos(26,12)\
2225 term.write(\" \") --next\
2226 term.setCursorPos(21,13)\
2227 term.write(\" \")\
2228 term.setCursorPos(21,14)\
2229 term.write(\" \")\
2230 term.setCursorPos(21,15)\
2231 term.write(\" \")\
2232 term.setCursorPos(21,16)\
2233 term.write(\" \")\
2234 term.setCursorPos(21,17)\
2235 term.write(\" \")\
2236 term.setCursorPos(21,18)\
2237 term.write(\" \")\
2238 term.setCursorPos(21,19)\
2239 term.write(\" \")\
2240 term.setCursorPos(21,20)\
2241 term.write(\" \")\
2242 end\
2243\
2244 local function updateNumbers()\
2245 term.setTextColor(colors.white)\
2246 term.setBackgroundColor(colors.black)\
2247\
2248 term.setCursorPos(22,3)\
2249 term.write(lpad(score,5)) --score\
2250 term.setCursorPos(22,6)\
2251 term.write(lpad(level,5)) --level\
2252 term.setCursorPos(22,9)\
2253 term.write(lpad(lines,5)) --lines\
2254 end\
2255\
2256 local function drawBlockAt(block,xp,yp,rot)\
2257 term.setTextColor(block.fg)\
2258 term.setBackgroundColor(block.bg)\
2259 for y=1,4 do\
2260 for x=1,4 do\
2261 if block[rot][y][x]==1 then\
2262 term.setCursorPos((xp+x)*2-3,yp+y-1-heightAdjust)\
2263 term.write(block.ch)\
2264 end\
2265 end\
2266 end\
2267 end\
2268\
2269 local function eraseBlockAt(block,xp,yp,rot)\
2270 term.setTextColor(colors.white)\
2271 term.setBackgroundColor(colors.black)\
2272 for y=1,4 do\
2273 for x=1,4 do\
2274 if block[rot][y][x]==1 then\
2275 term.setCursorPos((xp+x)*2-3,yp+y-1-heightAdjust)\
2276 term.write(\" \")\
2277 end\
2278 end\
2279 end\
2280 end\
2281\
2282 local function testBlockAt(block,xp,yp,rot)\
2283 for y=1,4 do\
2284 local ty=yp+y-1\
2285 for x=1,4 do\
2286 local tx=xp+x-1\
2287 if block[rot][y][x]==1 then\
2288 if tx>10 or tx<1 or ty>20 or pit[ty][tx]~=0 then\
2289 return true\
2290 end\
2291 end\
2292 end\
2293 end\
2294 end\
2295\
2296 local function pitBlock(block,xp,yp,rot)\
2297 for y=1,4 do\
2298 for x=1,4 do\
2299 if block[rot][y][x]==1 then\
2300 pit[yp+y-1][xp+x-1]=block\
2301 end\
2302 end\
2303 end\
2304 end\
2305\
2306\
2307 local function clearPit()\
2308 for row=1,20 do\
2309 pit[row]={}\
2310 for col=1,10 do\
2311 pit[row][col]=0\
2312 end\
2313 end\
2314 end\
2315\
2316\
2317\
2318 drawScreen()\
2319 updateNumbers()\
2320\
2321 --declare & init the pit\
2322 clearPit()\
2323\
2324\
2325\
2326 local halt=false\
2327 local dropSpeed=speedsByLevel[math.min(level,12)]\
2328\
2329\
2330 local curBlock=next\
2331 next=blocks[math.random(1,7)]\
2332\
2333 local curX, curY, curRot=4, 1, 1\
2334 local dropTimer=os.startTimer(dropSpeed)\
2335\
2336 drawBlockAt(next,11.5,15+heightAdjust,1)\
2337 drawBlockAt(curBlock,curX,curY,curRot)\
2338\
2339 local function redrawPit()\
2340 for r=1+heightAdjust,20 do\
2341 term.setCursorPos(1,r-heightAdjust)\
2342 for c=1,10 do\
2343 if pit[r][c]==0 then\
2344 term.setTextColor(colors.black)\
2345 term.setBackgroundColor(colors.black)\
2346 term.write(\" \")\
2347 else\
2348 term.setTextColor(pit[r][c].fg)\
2349 term.setBackgroundColor(pit[r][c].bg)\
2350 term.write(pit[r][c].ch)\
2351 end\
2352 end\
2353 end\
2354 end\
2355\
2356 local function hidePit()\
2357 for r=1+heightAdjust,20 do\
2358 term.setCursorPos(1,r-heightAdjust)\
2359 term.setTextColor(colors.black)\
2360 term.setBackgroundColor(colors.black)\
2361 term.write(\" \")\
2362 end\
2363 end\
2364\
2365 local function msgBox(message)\
2366 local x=math.floor((17-#message)/2)\
2367 term.setBackgroundColor(colorass(colors.lightGray,colors.white))\
2368 term.setTextColor(colors.black)\
2369 term.setCursorPos(x,9)\
2370 term.write(\"+\"..string.rep(\"-\",#message+2)..\"+\")\
2371 term.setCursorPos(x,10)\
2372 term.write(\"|\")\
2373 term.setCursorPos(x+#message+3,10)\
2374 term.write(\"|\")\
2375 term.setCursorPos(x,11)\
2376 term.write(\"+\"..string.rep(\"-\",#message+2)..\"+\")\
2377 term.setTextColor(colors.white)\
2378 term.setBackgroundColor(colors.black)\
2379 term.setCursorPos(x+1,10)\
2380 term.write(\" \"..message..\" \")\
2381 end\
2382\
2383 local function clearRows()\
2384 local rows={}\
2385 for r=1,20 do\
2386 local count=0\
2387 for c=1,10 do\
2388 if pit[r][c]~=0 then\
2389 count=count+1\
2390 else\
2391 break\
2392 end\
2393 end\
2394 if count==10 then\
2395 rows[#rows+1]=r\
2396 end\
2397 end\
2398\
2399 if #rows>0 then\
2400 for i=1,4 do\
2401 sleep(.1)\
2402 for r=1,#rows do\
2403 r=rows[r]\
2404 term.setCursorPos(1,r-heightAdjust)\
2405 for c=1,10 do\
2406 term.setTextColor(pit[r][c].bg)\
2407 term.setBackgroundColor(pit[r][c].fg)\
2408 term.write(pit[r][c].ch)\
2409 end\
2410 end\
2411 sleep(.1)\
2412 for r=1,#rows do\
2413 r=rows[r]\
2414 term.setCursorPos(1,r-heightAdjust)\
2415 for c=1,10 do\
2416 term.setTextColor(pit[r][c].fg)\
2417 term.setBackgroundColor(pit[r][c].bg)\
2418 term.write(pit[r][c].ch)\
2419 end\
2420 end\
2421 end\
2422 --now remove the rows and drop everythign else\
2423 term.setBackgroundColor(colors.black)\
2424 for r=1,#rows do\
2425 r=rows[r]\
2426 term.setCursorPos(1,r-heightAdjust)\
2427 term.write(\" \")\
2428 end\
2429 sleep(.25)\
2430 for r=1,#rows do\
2431 table.remove(pit,rows[r])\
2432 table.insert(pit,1,{0,0,0,0,0,0,0,0,0,0})\
2433 end\
2434 redrawPit()\
2435 lines=lines+#rows\
2436 score=score+points[#rows]*math.min(level,20)\
2437 level=math.floor(lines/10)+initialLevel\
2438 dropSpeed=speedsByLevel[math.min(level,12)]\
2439 updateNumbers()\
2440 end\
2441 sleep(.25)\
2442 end\
2443\
2444 local function blockFall()\
2445 local result = false\
2446 if testBlockAt(curBlock,curX,curY+1,curRot) then\
2447 pitBlock(curBlock,curX,curY,curRot)\
2448 --detect rows that clear\
2449 clearRows(rows)\
2450\
2451 curBlock=next\
2452 curX=4\
2453 curY=1\
2454 curRot=1\
2455 if testBlockAt(curBlock,curX,curY,curRot) then\
2456 halt=true\
2457 end\
2458 drawBlockAt(curBlock,curX,curY,curRot)\
2459 eraseBlockAt(next,11.5,15+heightAdjust,1)\
2460 next=blocks[math.random(1,7)]\
2461 drawBlockAt(next,11.5,15+heightAdjust,1)\
2462 return true\
2463 else\
2464 eraseBlockAt(curBlock,curX,curY,curRot)\
2465 curY=curY+1\
2466 drawBlockAt(curBlock,curX,curY,curRot)\
2467 return false\
2468 end\
2469 end\
2470\
2471\
2472 while not halt do\
2473 local e={os.pullEvent()}\
2474 if e[1]==\"timer\" then\
2475 if e[2]==dropTimer then\
2476 blockFall()\
2477 dropTimer=os.startTimer(dropSpeed)\
2478 end\
2479 elseif e[1]==\"key\" then\
2480 local key=e[2]\
2481 local dx,dy,dr=0,0,0\
2482 if key==keys.left or key==keys.a then\
2483 dx=-1\
2484 elseif key==keys.right or key==keys.d then\
2485 dx=1\
2486 elseif key==keys.up or key==keys.w then\
2487 dr=1\
2488 elseif key==keys.down or key==keys.s then\
2489 while not blockFall() do end\
2490 dropTimer=os.startTimer(dropSpeed)\
2491 elseif key==keys.space then\
2492 hidePit()\
2493 msgBox(\"Paused\")\
2494 while ({os.pullEvent(\"key\")})[2]~=keys.space do end\
2495 redrawPit()\
2496 drawBlockAt(curBlock,curX,curY,curRot)\
2497 dropTimer=os.startTimer(dropSpeed)\
2498 end\
2499 if dx+dr~=0 then\
2500 if not testBlockAt(curBlock,curX+dx,curY+dy,(dr>0 and curRot%#curBlock+dr or curRot)) then\
2501 eraseBlockAt(curBlock,curX,curY,curRot)\
2502 curX=curX+dx\
2503 curY=curY+dy\
2504 curRot=dr==0 and curRot or (curRot%#curBlock+dr)\
2505 drawBlockAt(curBlock,curX,curY,curRot)\
2506 end\
2507 end\
2508 elseif e[1]==\"term_resize\" then\
2509 local w,h=term.getSize()\
2510 if h==20 then\
2511 heightAdjust=0\
2512 else\
2513 heightAdjust=1\
2514 end\
2515 redrawPit()\
2516 drawBlockAt(curBlock,curX,curY,curRot)\
2517 end\
2518 end\
2519\
2520 msgBox(\"Game Over!\")\
2521 while true do\
2522 local _,k=os.pullEvent(\"key\")\
2523 if k==keys.space or k==keys.enter then\
2524 break\
2525 end\
2526 end\
2527\
2528 level = math.min(level,9)\
2529end\
2530\
2531\
2532local selected=1\
2533local playersDetected=false\
2534\
2535local function drawMenu()\
2536 term.setBackgroundColor(colors.black)\
2537 term.setTextColor(colorass(colors.red,colors.white))\
2538 term.clear()\
2539\
2540 local cx,cy=math.floor(width/2),math.floor(height/2)\
2541\
2542 term.setCursorPos(cx-6,cy-2)\
2543 term.write(\"F A L L I N G\")\
2544\
2545 if playersDetected then\
2546 if selected==0 then\
2547 term.setTextColor(colorass(colors.blue,colors.black))\
2548 term.setBackgroundColor(colorass(colors.gray,colors.white))\
2549 else\
2550 term.setTextColor(colorass(colors.lightBlue,colors.white))\
2551 term.setBackgroundColor(colors.black)\
2552 end\
2553 term.setCursorPos(cx-12,cy)\
2554 term.write(\" Play head-to-head game! \")\
2555 end\
2556\
2557 term.setCursorPos(cx-10,cy+1)\
2558 if selected==1 then\
2559 term.setTextColor(colorass(colors.blue,colors.black))\
2560 term.setBackgroundColor(colorass(colors.lightGray,colors.white))\
2561 else\
2562 term.setTextColor(colorass(colors.lightBlue,colors.white))\
2563 term.setBackgroundColor(colors.black)\
2564 end\
2565 term.write(\" Play from level: <\" .. level .. \"> \")\
2566\
2567 term.setCursorPos(cx-3,cy+3)\
2568 if selected==2 then\
2569 term.setTextColor(colorass(colors.blue,colors.black))\
2570 term.setBackgroundColor(colorass(colors.lightGray,colors.white))\
2571 else\
2572 term.setTextColor(colorass(colors.lightBlue,colors.white))\
2573 term.setBackgroundColor(colors.black)\
2574 end\
2575 term.write(\" Quit \")\
2576end\
2577\
2578\
2579local function runMenu()\
2580 drawMenu()\
2581\
2582 while true do\
2583 local event={os.pullEvent()}\
2584 if event[1]==\"key\" then\
2585 local key=event[2]\
2586 if key==keys.right or key==keys.d and selected==1 then\
2587 level=math.min(level+1,9)\
2588 drawMenu()\
2589 elseif key==keys.left or key==keys.a and selected==1 then\
2590 level=math.max(level-1,1)\
2591 drawMenu()\
2592 elseif key>=keys.one and key<=keys.nine and selected==1 then\
2593 level=(key-keys.one) + 1\
2594 drawMenu()\
2595 elseif key==keys.up or key==keys.w then\
2596 selected=selected-1\
2597 if selected==0 then\
2598 selected=2\
2599 end\
2600 drawMenu()\
2601 elseif key==keys.down or key==keys.s then\
2602 selected=selected%2+1\
2603 drawMenu()\
2604 elseif key==keys.enter or key==keys.space then\
2605 break --begin play!\
2606 end\
2607 end\
2608 end\
2609end\
2610\
2611while true do\
2612 runMenu()\
2613 if selected==2 then\
2614 break\
2615 end\
2616\
2617 playGame()\
2618end\
2619\
2620\
2621term.setTextColor(colors.white)\
2622term.setBackgroundColor(colors.black)\
2623term.clear()\
2624term.setCursorPos(1,1)",
2625 },
2626 label = "\
2627local function printUsage()\
2628 print( \"Usages:\" )\
2629 print( \"label get\" )\
2630 print( \"label get <drive>\" )\
2631 print( \"label set <text>\" )\
2632 print( \"label set <drive> <text>\" )\
2633 print( \"label clear\" )\
2634 print( \"label clear <drive>\" )\
2635end\
2636\
2637local function checkDrive( sDrive )\
2638 if peripheral.getType( sDrive ) == \"drive\" then\
2639 -- Check the disk exists\
2640 local bData = disk.hasData( sDrive )\
2641 if not bData then\
2642 print( \"No disk in \"..sDrive..\" drive\" )\
2643 return false\
2644 end\
2645 else\
2646 print( \"No disk drive named \"..sDrive )\
2647 return false\
2648 end\
2649 return true\
2650end\
2651\
2652local function get( sDrive )\
2653 if sDrive ~= nil then\
2654 if checkDrive( sDrive ) then\
2655 local sLabel = disk.getLabel( sDrive )\
2656 if sLabel then\
2657 print( \"Disk label is \\\"\"..sLabel..\"\\\"\" )\
2658 else\
2659 print( \"No Disk label\" )\
2660 end\
2661 end\
2662 else\
2663 local sLabel = os.getComputerLabel()\
2664 if sLabel then\
2665 print( \"Computer label is \\\"\"..sLabel..\"\\\"\" )\
2666 else\
2667 print( \"No Computer label\" )\
2668 end\
2669 end\
2670end\
2671\
2672local function set( sDrive, sText )\
2673 if sDrive ~= nil then\
2674 if checkDrive( sDrive ) then\
2675 disk.setLabel( sDrive, sText )\
2676 local sLabel = disk.getLabel( sDrive )\
2677 if sLabel then\
2678 print( \"Disk label set to \\\"\"..sLabel..\"\\\"\" )\
2679 else\
2680 print( \"Disk label cleared\" )\
2681 end\
2682 end\
2683 else\
2684 os.setComputerLabel( sText )\
2685 local sLabel = os.getComputerLabel()\
2686 if sLabel then\
2687 print( \"Computer label set to \\\"\"..sLabel..\"\\\"\" )\
2688 else\
2689 print( \"Computer label cleared\" )\
2690 end\
2691 end\
2692end\
2693\
2694local tArgs = { ... }\
2695local sCommand = tArgs[1]\
2696if sCommand == \"get\" then\
2697 -- Get a label\
2698 if #tArgs == 1 then\
2699 get( nil )\
2700 elseif #tArgs == 2 then\
2701 get( tArgs[2] )\
2702 else\
2703 printUsage()\
2704 end\
2705elseif sCommand == \"set\" then\
2706 -- Set a label\
2707 if #tArgs == 2 then\
2708 set( nil, tArgs[2] )\
2709 elseif #tArgs == 3 then\
2710 set( tArgs[2], tArgs[3] )\
2711 else\
2712 printUsage()\
2713 end\
2714elseif sCommand == \"clear\" then\
2715 -- Clear a label\
2716 if #tArgs == 1 then\
2717 set( nil, nil )\
2718 elseif #tArgs == 2 then\
2719 set( tArgs[2], nil )\
2720 else\
2721 printUsage()\
2722 end\
2723else\
2724 printUsage()\
2725end\
2726",
2727 drive = "local tArgs = { ... }\
2728\
2729-- Get where a directory is mounted\
2730local sPath = shell.dir()\
2731if tArgs[1] ~= nil then\
2732 sPath = shell.resolve( tArgs[1] )\
2733end\
2734\
2735if fs.exists( sPath ) then\
2736 write( fs.getDrive( sPath ) .. \" (\" )\
2737 local nSpace = fs.getFreeSpace( sPath )\
2738 if nSpace >= 1000 * 1000 then\
2739 print( (math.floor( nSpace / (100 * 1000) ) / 10) .. \"MB remaining)\" )\
2740 elseif nSpace >= 1000 then\
2741 print( (math.floor( nSpace / 100 ) / 10) .. \"KB remaining)\" )\
2742 else\
2743 print( nSpace .. \"B remaining)\" )\
2744 end\
2745else\
2746 print( \"No such path\" )\
2747end\
2748",
2749 help = "tArgs = { ... }\
2750if #tArgs > 0 then\
2751 sTopic = tArgs[1]\
2752else\
2753 sTopic = \"intro\"\
2754end\
2755\
2756if sTopic == \"index\" then\
2757 print( \"Help topics availiable:\" )\
2758 local tTopics = help.topics()\
2759 textutils.pagedTabulate( tTopics )\
2760 return\
2761end\
2762 \
2763local w,h = term.getSize()\
2764local sFile = help.lookup( sTopic )\
2765local file = ((sFile ~= nil) and io.open( sFile )) or nil\
2766local nLinesPrinted = 0\
2767if file then\
2768 local sLine = file:read()\
2769 local nLines = 0\
2770 while sLine do\
2771 nLines = nLines + textutils.pagedPrint( sLine, (h-3) - nLines )\
2772 sLine = file:read()\
2773 end\
2774 file:close()\
2775else\
2776 print( \"No help available\" )\
2777end\
2778",
2779 apis = "\
2780local tApis = {}\
2781for k,v in pairs( _G ) do\
2782 if type(k) == \"string\" and type(v) == \"table\" and k ~= \"_G\" then\
2783 table.insert( tApis, k )\
2784 end\
2785end\
2786table.insert( tApis, \"shell\" )\
2787table.sort( tApis )\
2788\
2789textutils.pagedTabulate( tApis )\
2790",
2791 alias = "\
2792local tArgs = { ... }\
2793if #tArgs > 2 then\
2794 print( \"Usage: alias <alias> <program>\" )\
2795 return\
2796end\
2797\
2798local sAlias = tArgs[1]\
2799local sProgram = tArgs[2]\
2800\
2801if sAlias and sProgram then\
2802 -- Set alias\
2803 shell.setAlias( sAlias, sProgram )\
2804elseif sAlias then\
2805 -- Clear alias\
2806 shell.clearAlias( sAlias )\
2807else\
2808 -- List aliases\
2809 local tAliases = shell.aliases()\
2810 local tList = {}\
2811 for sAlias, sCommand in pairs( tAliases ) do\
2812 table.insert( tList, sAlias )\
2813 end\
2814 table.sort( tList )\
2815 textutils.pagedTabulate( tList )\
2816end\
2817 ",
2818 gps = "\
2819local function printUsage()\
2820 print( \"Usages:\" )\
2821 print( \"gps host\" )\
2822 print( \"gps host <x> <y> <z>\" )\
2823 print( \"gps locate\" )\
2824end\
2825\
2826local tArgs = { ... }\
2827if #tArgs < 1 then\
2828 printUsage()\
2829 return\
2830end\
2831 \
2832 local sCommand = tArgs[1]\
2833if sCommand == \"locate\" then\
2834 -- \"gps locate\"\
2835 -- Just locate this computer (this will print the results)\
2836 gps.locate( 2, true )\
2837 \
2838elseif sCommand == \"host\" then\
2839 -- \"gps host\"\
2840 -- Act as a GPS host\
2841 if pocket then\
2842 print( \"GPS Hosts must be stationary\" )\
2843 return\
2844 end\
2845\
2846 -- Find a modem\
2847 local sModemSide = nil\
2848 for n,sSide in ipairs( rs.getSides() ) do\
2849 if peripheral.getType( sSide ) == \"modem\" and peripheral.call( sSide, \"isWireless\" ) then \
2850 sModemSide = sSide\
2851 break\
2852 end\
2853 end\
2854\
2855 if sModemSide == nil then\
2856 print( \"No wireless modems found. 1 required.\" )\
2857 return\
2858 end\
2859\
2860 -- Determine position\
2861 local x,y,z\
2862 if #tArgs >= 4 then\
2863 -- Position is manually specified\
2864 x = tonumber(tArgs[2])\
2865 y = tonumber(tArgs[3])\
2866 z = tonumber(tArgs[4])\
2867 if x == nil or y == nil or z == nil then\
2868 printUsage()\
2869 return\
2870 end\
2871 print( \"Position is \"..x..\",\"..y..\",\"..z )\
2872 else\
2873 -- Position is to be determined using locate \
2874 x,y,z = gps.locate( 2, true )\
2875 if x == nil then\
2876 print( \"Run \\\"gps host <x> <y> <z>\\\" to set position manually\" )\
2877 if bCloseChannel then\
2878 print( \"Closing GPS channel\" )\
2879 modem.close( gps.CHANNEL_GPS )\
2880 end\
2881 return\
2882 end\
2883 end\
2884 \
2885 -- Open a channel\
2886 local modem = peripheral.wrap( sModemSide )\
2887 print( \"Opening channel on modem \"..sModemSide )\
2888 modem.open( gps.CHANNEL_GPS )\
2889\
2890 -- Serve requests indefinately\
2891 local nServed = 0\
2892 while true do\
2893 local e, p1, p2, p3, p4, p5 = os.pullEvent( \"modem_message\" )\
2894 if e == \"modem_message\" then\
2895 -- We received a message from a modem\
2896 local sSide, sChannel, sReplyChannel, sMessage, nDistance = p1, p2, p3, p4, p5\
2897 if sSide == sModemSide and sChannel == gps.CHANNEL_GPS and sMessage == \"PING\" then\
2898 -- We received a ping message on the GPS channel, send a response\
2899 modem.transmit( sReplyChannel, gps.CHANNEL_GPS, { x, y, z } )\
2900 \
2901 -- Print the number of requests handled\
2902 nServed = nServed + 1\
2903 if nServed > 1 then\
2904 local x,y = term.getCursorPos()\
2905 term.setCursorPos(1,y-1)\
2906 end\
2907 print( nServed..\" GPS requests served\" )\
2908 end\
2909 end\
2910 end\
2911\
2912 -- Close the channel\
2913 print( \"Closing channel\" )\
2914 modem.close( gps.CHANNEL_GPS )\
2915\
2916else\
2917 -- \"gps somethingelse\"\
2918 -- Error\
2919 printUsage()\
2920 \
2921end\
2922",
2923 delete = "\
2924local tArgs = { ... }\
2925if #tArgs < 1 then\
2926 print( \"Usage: rm <path>\" )\
2927 return\
2928end\
2929\
2930local sPath = shell.resolve( tArgs[1] )\
2931local tFiles = fs.find( sPath )\
2932if #tFiles > 0 then\
2933 for n,sFile in ipairs( tFiles ) do\
2934 fs.delete( sFile )\
2935 end\
2936else\
2937 printError( \"No matching files\" )\
2938end",
2939 lua = "\
2940local tArgs = { ... }\
2941if #tArgs > 0 then\
2942 print( \"This is an interactive Lua prompt.\" )\
2943 print( \"To run a lua program, just type its name.\" )\
2944 return\
2945end\
2946\
2947local bRunning = true\
2948local tCommandHistory = {}\
2949local tEnv = {\
2950 [\"exit\"] = function()\
2951 bRunning = false\
2952 end,\
2953 [\"_echo\"] = function( ... )\
2954 return ...\
2955 end,\
2956}\
2957setmetatable( tEnv, { __index = getfenv() } )\
2958\
2959if term.isColour() then\
2960 term.setTextColour( colours.yellow )\
2961end\
2962print( \"Interactive Lua prompt.\" )\
2963print( \"Call exit() to exit.\" )\
2964term.setTextColour( colours.white )\
2965\
2966while bRunning do\
2967 --if term.isColour() then\
2968 -- term.setTextColour( colours.yellow )\
2969 --end\
2970 write( \"lua> \" )\
2971 --term.setTextColour( colours.white )\
2972 \
2973 local s = read( nil, tCommandHistory )\
2974 table.insert( tCommandHistory, s )\
2975 \
2976 local nForcePrint = 0\
2977 local func, e = loadstring( s, \"lua\" )\
2978 local func2, e2 = loadstring( \"return _echo(\"..s..\");\", \"lua\" )\
2979 if not func then\
2980 if func2 then\
2981 func = func2\
2982 e = nil\
2983 nForcePrint = 1\
2984 end\
2985 else\
2986 if func2 then\
2987 func = func2\
2988 end\
2989 end\
2990 \
2991 if func then\
2992 setfenv( func, tEnv )\
2993 local tResults = { pcall( func ) }\
2994 if tResults[1] then\
2995 local n = 1\
2996 while (tResults[n + 1] ~= nil) or (n <= nForcePrint) do\
2997 local value = tResults[ n + 1 ]\
2998 if type( value ) == \"table\" then\
2999 local ok, serialised = pcall( textutils.serialise, value )\
3000 if ok then\
3001 print( serialised )\
3002 else\
3003 print( tostring( value ) )\
3004 end\
3005 else\
3006 print( tostring( value ) )\
3007 end\
3008 n = n + 1\
3009 end\
3010 else\
3011 printError( tResults[2] )\
3012 end\
3013 else\
3014 printError( e )\
3015 end\
3016 \
3017end\
3018",
3019 type = "\
3020local tArgs = { ... }\
3021if #tArgs < 1 then\
3022 print( \"Usage: type <path>\" )\
3023 return\
3024end\
3025\
3026local sPath = shell.resolve( tArgs[1] )\
3027if fs.exists( sPath ) then\
3028 if fs.isDir( sPath ) then\
3029 print( \"directory\" )\
3030 else\
3031 print( \"file\" )\
3032 end\
3033else\
3034 print( \"No such path\" )\
3035end\
3036\
3037",
3038 id = "\
3039local sDrive = nil\
3040local tArgs = { ... }\
3041if #tArgs > 0 then\
3042 sDrive = tostring( tArgs[1] )\
3043end\
3044\
3045if sDrive == nil then\
3046 print( \"This is computer #\"..os.getComputerID() )\
3047 \
3048 local label = os.getComputerLabel()\
3049 if label then\
3050 print( \"This computer is labelled \\\"\"..label..\"\\\"\" )\
3051 end\
3052\
3053else\
3054 local bData = disk.hasData( sDrive )\
3055 if not bData then\
3056 print( \"No disk in drive \"..sDrive )\
3057 return\
3058 end\
3059 \
3060 print( \"The disk is #\"..disk.getID( sDrive ) )\
3061\
3062 local label = disk.getLabel( sDrive )\
3063 if label then\
3064 print( \"The disk is labelled \\\"\"..label..\"\\\"\" )\
3065 end\
3066end\
3067\
3068",
3069 clear = "term.clear()\
3070term.setCursorPos( 1, 1 )\
3071",
3072 fun = {
3073 hello = "if term.isColour() then\
3074 term.setTextColour( 2^math.random(0,15) )\
3075end\
3076textutils.slowPrint( \"Hello World!\" )\
3077term.setTextColour( colours.white )\
3078",
3079 worm = "\
3080-- Display the start screen\
3081local w,h = term.getSize()\
3082\
3083local titleColour, headingColour, textColour, wormColour, fruitColour\
3084if term.isColour() then\
3085 titleColour = colours.red\
3086 headingColour = colours.yellow\
3087 textColour = colours.white\
3088 wormColour = colours.green\
3089 fruitColour = colours.red\
3090else\
3091 titleColour = colours.white\
3092 headingColour = colours.white\
3093 textColour = colours.white\
3094 wormColour = colours.white\
3095 fruitColour = colours.white\
3096end\
3097\
3098function printCentred( y, s )\
3099 local x = math.floor((w - string.len(s)) / 2)\
3100 term.setCursorPos(x,y)\
3101 --term.clearLine()\
3102 term.write( s )\
3103end\
3104\
3105local xVel,yVel = 1,0\
3106local xPos, yPos = math.floor(w/2), math.floor(h/2)\
3107local pxVel, pyVel = nil, nil\
3108\
3109local nLength = 1\
3110local nExtraLength = 6\
3111local bRunning = true\
3112\
3113local tailX,tailY = xPos,yPos\
3114local nScore = 0\
3115local nDifficulty = 2\
3116local nSpeed, nInterval\
3117\
3118-- Setup the screen\
3119local screen = {}\
3120for x=1,w do\
3121 screen[x] = {}\
3122 for y=1,h do\
3123 screen[x][y] = {}\
3124 end\
3125end\
3126screen[xPos][yPos] = { snake = true }\
3127\
3128local nFruit = 1\
3129local tFruits = {\
3130 \"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\",\
3131 \"I\", \"J\", \"K\", \"L\", \"M\", \"N\", \"O\", \"P\",\
3132 \"Q\", \"R\", \"S\", \"T\", \"U\", \"V\", \"W\", \"X\",\
3133 \"Y\", \"Z\",\
3134 \"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\",\
3135 \"i\", \"j\", \"k\", \"l\", \"m\", \"n\", \"o\", \"p\",\
3136 \"q\", \"r\", \"s\", \"t\", \"u\", \"v\", \"w\", \"x\",\
3137 \"y\", \"z\",\
3138 \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"0\",\
3139 \"@\", \"$\", \"%\", \"#\", \"&\", \"!\", \"?\", \"+\", \"*\", \"~\"\
3140}\
3141\
3142local function addFruit()\
3143 while true do\
3144 local x = math.random(1,w)\
3145 local y = math.random(2,h)\
3146 local fruit = screen[x][y]\
3147 if fruit.snake == nil and fruit.wall == nil and fruit.fruit == nil then\
3148 screen[x][y] = { fruit = true }\
3149 term.setCursorPos(x,y)\
3150 term.setBackgroundColour( fruitColour )\
3151 term.write(\" \")\
3152 term.setBackgroundColour( colours.black )\
3153 break\
3154 end\
3155 end\
3156 \
3157 nFruit = nFruit + 1\
3158 if nFruit > #tFruits then\
3159 nFruit = 1\
3160 end\
3161end\
3162\
3163local function drawMenu()\
3164 term.setTextColour( headingColour )\
3165 term.setCursorPos(1,1)\
3166 term.write( \"SCORE \" )\
3167 \
3168 term.setTextColour( textColour )\
3169 term.setCursorPos(7,1)\
3170 term.write( tostring(nScore) )\
3171\
3172 term.setTextColour( headingColour )\
3173 term.setCursorPos(w-11,1)\
3174 term.write( \"DIFFICULTY \")\
3175\
3176 term.setTextColour( textColour )\
3177 term.setCursorPos(w,1)\
3178 term.write( tostring(nDifficulty or \"?\") ) \
3179\
3180 term.setTextColour( colours.white )\
3181end\
3182\
3183local function update( )\
3184 local x,y = xPos,yPos\
3185 if pxVel and pyVel then\
3186 xVel, yVel = pxVel, pyVel\
3187 pxVel, pyVel = nil, nil\
3188 end\
3189\
3190 -- Remove the tail\
3191 if nExtraLength == 0 then\
3192 local tail = screen[tailX][tailY]\
3193 screen[tailX][tailY] = {}\
3194 term.setCursorPos(tailX,tailY)\
3195 term.write(\" \")\
3196 tailX = tail.nextX\
3197 tailY = tail.nextY\
3198 else\
3199 nExtraLength = nExtraLength - 1\
3200 end\
3201 \
3202 -- Update the head\
3203 local head = screen[xPos][yPos]\
3204 local newXPos = xPos + xVel\
3205 local newYPos = yPos + yVel\
3206 if newXPos < 1 then\
3207 newXPos = w\
3208 elseif newXPos > w then\
3209 newXPos = 1\
3210 end\
3211 if newYPos < 2 then\
3212 newYPos = h\
3213 elseif newYPos > h then\
3214 newYPos = 2\
3215 end\
3216 \
3217 local newHead = screen[newXPos][newYPos]\
3218 term.setCursorPos(1,1);\
3219 print( newHead.snake )\
3220 if newHead.snake == true or newHead.wall == true then\
3221 bRunning = false\
3222 \
3223 else\
3224 if newHead.fruit == true then\
3225 nScore = nScore + 10\
3226 nExtraLength = nExtraLength + 1\
3227 addFruit()\
3228 end\
3229 xPos = newXPos\
3230 yPos = newYPos\
3231 head.nextX = newXPos\
3232 head.nextY = newYPos\
3233 screen[newXPos][newYPos] = { snake = true }\
3234 \
3235 end\
3236 \
3237 term.setCursorPos(xPos,yPos)\
3238 term.setBackgroundColour( wormColour )\
3239 term.write(\" \")\
3240 term.setBackgroundColour( colours.black )\
3241\
3242 drawMenu()\
3243end\
3244\
3245-- Display the frontend\
3246term.clear()\
3247local function drawFrontend()\
3248 --term.setTextColour( titleColour )\
3249 --printCentred( math.floor(h/2) - 4, \" W O R M \" )\
3250\
3251 term.setTextColour( headingColour )\
3252 printCentred( math.floor(h/2) - 3, \"\" )\
3253 printCentred( math.floor(h/2) - 2, \" SELECT DIFFICULTY \" )\
3254 printCentred( math.floor(h/2) - 1, \"\" )\
3255 \
3256 printCentred( math.floor(h/2) + 0, \" \" )\
3257 printCentred( math.floor(h/2) + 1, \" \" )\
3258 printCentred( math.floor(h/2) + 2, \" \" )\
3259 printCentred( math.floor(h/2) - 1 + nDifficulty, \" [ ] \" )\
3260\
3261 term.setTextColour( textColour )\
3262 printCentred( math.floor(h/2) + 0, \"EASY\" )\
3263 printCentred( math.floor(h/2) + 1, \"MEDIUM\" )\
3264 printCentred( math.floor(h/2) + 2, \"HARD\" )\
3265 printCentred( math.floor(h/2) + 3, \"\" )\
3266\
3267 term.setTextColour( colours.white )\
3268end\
3269\
3270drawMenu()\
3271drawFrontend()\
3272while true do\
3273 local e,key = os.pullEvent( \"key\" )\
3274 if key == keys.up or key == keys.w then\
3275 -- Up\
3276 if nDifficulty > 1 then\
3277 nDifficulty = nDifficulty - 1\
3278 drawMenu()\
3279 drawFrontend()\
3280 end\
3281 elseif key == keys.down or key == keys.s then\
3282 -- Down\
3283 if nDifficulty < 3 then\
3284 nDifficulty = nDifficulty + 1\
3285 drawMenu()\
3286 drawFrontend()\
3287 end\
3288 elseif key == keys.enter then\
3289 -- Enter\
3290 break\
3291 end\
3292end\
3293\
3294local tSpeeds = { 5, 10, 25 }\
3295nSpeed = tSpeeds[nDifficulty]\
3296nInterval = 1 / nSpeed\
3297\
3298-- Grow the snake to its intended size\
3299term.clear()\
3300drawMenu()\
3301screen[tailX][tailY].snake = true\
3302while nExtraLength > 0 do\
3303 update()\
3304end\
3305addFruit()\
3306addFruit()\
3307\
3308-- Play the game\
3309local timer = os.startTimer(0)\
3310while bRunning do\
3311 local event, p1, p2 = os.pullEvent()\
3312 if event == \"timer\" and p1 == timer then\
3313 timer = os.startTimer(nInterval)\
3314 update( false )\
3315 \
3316 elseif event == \"key\" then\
3317 local key = p1\
3318 if key == keys.up or key == keys.w then\
3319 -- Up\
3320 if yVel == 0 then\
3321 pxVel,pyVel = 0,-1\
3322 end\
3323 elseif key == keys.down or key == keys.s then\
3324 -- Down\
3325 if yVel == 0 then\
3326 pxVel,pyVel = 0,1\
3327 end\
3328 elseif key == keys.left or key == keys.a then\
3329 -- Left\
3330 if xVel == 0 then\
3331 pxVel,pyVel = -1,0\
3332 end\
3333 \
3334 elseif key == keys.right or key == keys.d then\
3335 -- Right\
3336 if xVel == 0 then\
3337 pxVel,pyVel = 1,0\
3338 end\
3339 \
3340 end \
3341 end\
3342end\
3343\
3344-- Display the gameover screen\
3345term.setTextColour( headingColour )\
3346printCentred( math.floor(h/2) - 2, \" \" )\
3347printCentred( math.floor(h/2) - 1, \" G A M E O V E R \" )\
3348\
3349term.setTextColour( textColour )\
3350printCentred( math.floor(h/2) + 0, \" \" )\
3351printCentred( math.floor(h/2) + 1, \" FINAL SCORE \"..nScore..\" \" )\
3352printCentred( math.floor(h/2) + 2, \" \" )\
3353term.setTextColour( colours.white )\
3354\
3355local timer = os.startTimer(2.5)\
3356repeat\
3357 local e,p = os.pullEvent()\
3358 if e == \"timer\" and p == timer then\
3359 term.setTextColour( textColour )\
3360 printCentred( math.floor(h/2) + 2, \" PRESS ANY KEY \" )\
3361 printCentred( math.floor(h/2) + 3, \" \" )\
3362 term.setTextColour( colours.white )\
3363 end\
3364until e == \"char\"\
3365\
3366term.clear()\
3367term.setCursorPos(1,1)\
3368\
3369 ",
3370 adventure = "\
3371local tBiomes = {\
3372 \"in a forest\",\
3373 \"in a pine forest\",\
3374 \"knee deep in a swamp\",\
3375 \"in a mountain range\",\
3376 \"in a desert\",\
3377 \"in a grassy plain\",\
3378 \"in frozen tundra\",\
3379}\
3380\
3381local function hasTrees( _nBiome )\
3382 return _nBiome <= 3\
3383end\
3384\
3385local function hasStone( _nBiome )\
3386 return _nBiome == 4\
3387end\
3388\
3389local function hasRivers( _nBiome )\
3390 return _nBiome ~= 3 and _nBiome ~= 5\
3391end\
3392\
3393local items = {\
3394 [\"no tea\"] = {\
3395 droppable = false,\
3396 desc = \"Pull yourself together man.\",\
3397 },\
3398 [\"a pig\"] = {\
3399 heavy = true,\
3400 creature = true,\
3401 drops = { \"some pork\" },\
3402 aliases = { \"pig\" },\
3403 desc = \"The pig has a square nose.\",\
3404 },\
3405 [\"a cow\"] = {\
3406 heavy = true,\
3407 creature = true,\
3408 aliases = { \"cow\" },\
3409 desc = \"The cow stares at you blankly.\",\
3410 },\
3411 [\"a sheep\"] = {\
3412 heavy = true,\
3413 creature = true,\
3414 hitDrops = { \"some wool\" },\
3415 aliases = { \"sheep\" },\
3416 desc = \"The sheep is fluffy.\",\
3417 },\
3418 [\"a chicken\"] = {\
3419 heavy = true,\
3420 creature = true,\
3421 drops = { \"some chicken\" },\
3422 aliases = { \"chicken\" },\
3423 desc = \"The chicken looks delicious.\",\
3424 },\
3425 [\"a creeper\"] = {\
3426 heavy = true,\
3427 creature = true,\
3428 monster = true,\
3429 aliases = { \"creeper\" },\
3430 desc = \"The creeper needs a hug.\",\
3431 },\
3432 [\"a skeleton\"] = {\
3433 heavy = true,\
3434 creature = true,\
3435 monster = true,\
3436 aliases = { \"skeleton\" },\
3437 nocturnal = true,\
3438 desc = \"The head bone's connected to the neck bone, the neck bone's connected to the chest bone, the chest bone's connected to the arm bone, the arm bone's connected to the bow, and the bow is pointed at you.\",\
3439 },\
3440 [\"a zombie\"] = {\
3441 heavy = true,\
3442 creature = true,\
3443 monster = true,\
3444 aliases = { \"zombie\" },\
3445 nocturnal = true,\
3446 desc = \"All he wants to do is eat your brains.\",\
3447 },\
3448 [\"a spider\"] = {\
3449 heavy = true,\
3450 creature = true,\
3451 monster = true,\
3452 aliases = { \"spider\" },\
3453 desc = \"Dozens of eyes stare back at you.\",\
3454 },\
3455 [\"a cave entrance\"] = {\
3456 heavy = true,\
3457 aliases = { \"cave entance\", \"cave\", \"entrance\" },\
3458 desc = \"The entrance to the cave is dark, but it looks like you can climb down.\",\
3459 },\
3460 [\"an exit to the surface\"] = {\
3461 heavy = true,\
3462 aliases = { \"exit to the surface\", \"exit\", \"opening\" },\
3463 desc = \"You can just see the sky through the opening.\",\
3464 },\
3465 [\"a river\"] = {\
3466 heavy = true,\
3467 aliases = { \"river\" },\
3468 desc = \"The river flows majestically towards the horizon. It doesn't do anything else.\",\
3469 },\
3470 [\"some wood\"] = {\
3471 aliases = { \"wood\" },\
3472 material = true,\
3473 desc = \"You could easilly craft this wood into planks.\",\
3474 },\
3475 [\"some planks\"] = {\
3476 aliases = { \"planks\", \"wooden planks\", \"wood planks\" },\
3477 desc = \"You could easilly craft these planks into sticks.\",\
3478 },\
3479 [\"some sticks\"] = {\
3480 aliases = { \"sticks\", \"wooden sticks\", \"wood sticks\" },\
3481 desc = \"A perfect handle for torches or a pickaxe.\",\
3482 },\
3483 [\"a crafting table\"] = {\
3484 aliases = { \"crafting table\", \"craft table\", \"work bench\", \"workbench\", \"crafting bench\", \"table\", },\
3485 desc = \"It's a crafting table. I shouldn't tell you this, but these don't actually do anything in this game, you can craft tools whenever you like.\",\
3486 },\
3487 [\"a furnace\"] = {\
3488 aliases = { \"furnace\" },\
3489 desc = \"It's a furnace. Between you and me, these don't actually do anything in this game.\",\
3490 },\
3491 [\"a wooden pickaxe\"] = {\
3492 aliases = { \"pickaxe\", \"pick\", \"wooden pick\", \"wooden pickaxe\", \"wood pick\", \"wood pickaxe\" },\
3493 tool = true,\
3494 toolLevel = 1,\
3495 toolType = \"pick\",\
3496 desc = \"The pickaxe looks good for breaking stone and coal.\",\
3497 },\
3498 [\"a stone pickaxe\"] = {\
3499 aliases = { \"pickaxe\", \"pick\", \"stone pick\", \"stone pickaxe\" },\
3500 tool = true,\
3501 toolLevel = 2,\
3502 toolType = \"pick\",\
3503 desc = \"The pickaxe looks good for breaking iron.\",\
3504 },\
3505 [\"an iron pickaxe\"] = {\
3506 aliases = { \"pickaxe\", \"pick\", \"iron pick\", \"iron pickaxe\" },\
3507 tool = true,\
3508 toolLevel = 3,\
3509 toolType = \"pick\",\
3510 desc = \"The pickaxe looks strong enough to break diamond.\",\
3511 },\
3512 [\"a diamond pickaxe\"] = {\
3513 aliases = { \"pickaxe\", \"pick\", \"diamond pick\", \"diamond pickaxe\" },\
3514 tool = true,\
3515 toolLevel = 4,\
3516 toolType = \"pick\",\
3517 desc = \"Best. Pickaxe. Ever.\",\
3518 },\
3519 [\"a wooden sword\"] = {\
3520 aliases = { \"sword\", \"wooden sword\", \"wood sword\" },\
3521 tool = true,\
3522 toolLevel = 1,\
3523 toolType = \"sword\",\
3524 desc = \"Flimsy, but better than nothing.\",\
3525 },\
3526 [\"a stone sword\"] = {\
3527 aliases = { \"sword\", \"stone sword\" },\
3528 tool = true,\
3529 toolLevel = 2,\
3530 toolType = \"sword\",\
3531 desc = \"A pretty good sword.\",\
3532 },\
3533 [\"an iron sword\"] = {\
3534 aliases = { \"sword\", \"iron sword\" },\
3535 tool = true,\
3536 toolLevel = 3,\
3537 toolType = \"sword\",\
3538 desc = \"This sword can slay any enemy.\",\
3539 },\
3540 [\"a diamond sword\"] = {\
3541 aliases = { \"sword\", \"diamond sword\" },\
3542 tool = true,\
3543 toolLevel = 4,\
3544 toolType = \"sword\",\
3545 desc = \"Best. Sword. Ever.\",\
3546 },\
3547 [\"a wooden shovel\"] = {\
3548 aliases = { \"shovel\", \"wooden shovel\", \"wood shovel\" },\
3549 tool = true,\
3550 toolLevel = 1,\
3551 toolType = \"shovel\",\
3552 desc = \"Good for digging holes.\",\
3553 },\
3554 [\"a stone shovel\"] = {\
3555 aliases = { \"shovel\", \"stone shovel\" },\
3556 tool = true,\
3557 toolLevel = 2,\
3558 toolType = \"shovel\",\
3559 desc = \"Good for digging holes.\",\
3560 },\
3561 [\"an iron shovel\"] = {\
3562 aliases = { \"shovel\", \"iron shovel\" },\
3563 tool = true,\
3564 toolLevel = 3,\
3565 toolType = \"shovel\",\
3566 desc = \"Good for digging holes.\",\
3567 },\
3568 [\"a diamond shovel\"] = {\
3569 aliases = { \"shovel\", \"diamond shovel\" },\
3570 tool = true,\
3571 toolLevel = 4,\
3572 toolType = \"shovel\",\
3573 desc = \"Good for digging holes.\",\
3574 },\
3575 [\"some coal\"] = {\
3576 aliases = { \"coal\" },\
3577 ore = true,\
3578 toolLevel = 1,\
3579 toolType = \"pick\",\
3580 desc = \"That coal looks useful for building torches, if only you had a pickaxe to mine it.\",\
3581 },\
3582 [\"some dirt\"] = {\
3583 aliases = { \"dirt\" },\
3584 material = true,\
3585 desc = \"Why not build a mud hut?\",\
3586 },\
3587 [\"some stone\"] = {\
3588 aliases = { \"stone\", \"cobblestone\" },\
3589 material = true,\
3590 ore = true,\
3591 infinite = true,\
3592 toolLevel = 1,\
3593 toolType = \"pick\",\
3594 desc = \"Stone is useful for building things, and making stone pickaxes.\",\
3595 },\
3596 [\"some iron\"] = {\
3597 aliases = { \"iron\" },\
3598 material = true,\
3599 ore = true,\
3600 toolLevel = 2,\
3601 toolType = \"pick\",\
3602 desc = \"That iron looks mighty strong, you'll need a stone pickaxe to mine it.\",\
3603 },\
3604 [\"some diamond\"] = {\
3605 aliases = { \"diamond\", \"diamonds\" },\
3606 material = true,\
3607 ore = true,\
3608 toolLevel = 3,\
3609 toolType = \"pick\",\
3610 desc = \"Sparkly, rare, and impossible to mine without an iron pickaxe.\",\
3611 },\
3612 [\"some torches\"] = {\
3613 aliases = { \"torches\", \"torch\" },\
3614 desc = \"These won't run out for a while.\",\
3615 },\
3616 [\"a torch\"] = {\
3617 aliases = { \"torch\" },\
3618 desc = \"Fire, fire, burn so bright, won't you light my cave tonight?\",\
3619 },\
3620 [\"some wool\"] = {\
3621 aliases = { \"wool\" },\
3622 material = true,\
3623 desc = \"Soft and good for building.\",\
3624 },\
3625 [\"some pork\"] = {\
3626 aliases = { \"pork\", \"porkchops\" },\
3627 food = true,\
3628 desc = \"Delicious and nutricious.\",\
3629 },\
3630 [\"some chicken\"] = {\
3631 aliases = { \"chicken\" },\
3632 food = true,\
3633 desc = \"Finger licking good.\",\
3634 },\
3635}\
3636\
3637local tAnimals = {\
3638 \"a pig\", \"a cow\", \"a sheep\", \"a chicken\",\
3639}\
3640\
3641local tMonsters = {\
3642 \"a creeper\", \"a skeleton\", \"a zombie\", \"a spider\"\
3643}\
3644\
3645local tRecipes = {\
3646 [\"some planks\"] = { \"some wood\" },\
3647 [\"some sticks\"] = { \"some planks\" },\
3648 [\"some sticks\"] = { \"some planks\" },\
3649 [\"a crafting table\"] = { \"some planks\" },\
3650 [\"a furnace\"] = { \"some stone\" },\
3651 [\"some torches\"] = { \"some sticks\", \"some coal\" },\
3652 \
3653 [\"a wooden pickaxe\"] = { \"some planks\", \"some sticks\" },\
3654 [\"a stone pickaxe\"] = { \"some stone\", \"some sticks\" },\
3655 [\"an iron pickaxe\"] = { \"some iron\", \"some sticks\" },\
3656 [\"a diamond pickaxe\"] = { \"some diamond\", \"some sticks\" },\
3657\
3658 [\"a wooden sword\"] = { \"some planks\", \"some sticks\" },\
3659 [\"a stone sword\"] = { \"some stone\", \"some sticks\" },\
3660 [\"an iron sword\"] = { \"some iron\", \"some sticks\" },\
3661 [\"a diamond sword\"] = { \"some diamond\", \"some sticks\" },\
3662\
3663 [\"a wooden shovel\"] = { \"some planks\", \"some sticks\" },\
3664 [\"a stone shovel\"] = { \"some stone\", \"some sticks\" },\
3665 [\"an iron shovel\"] = { \"some iron\", \"some sticks\" },\
3666 [\"a diamond shovel\"] = { \"some diamond\", \"some sticks\" },\
3667}\
3668\
3669local tGoWest = {\
3670 \"(life is peaceful there)\",\
3671 \"(lots of open air)\",\
3672 \"(to begin life anew)\",\
3673 \"(this is what we'll do)\",\
3674 \"(sun in winter time)\",\
3675 \"(we will do just fine)\",\
3676 \"(where the skies are blue)\",\
3677 \"(this and more we'll do)\",\
3678}\
3679local nGoWest = 0\
3680\
3681local bRunning = true\
3682local tMap = { { {}, }, }\
3683local x,y,z = 0,0,0\
3684local inventory = {\
3685 [\"no tea\"] = items[\"no tea\"],\
3686}\
3687\
3688local nTurn = 0\
3689local nTimeInRoom = 0\
3690local bInjured = false\
3691\
3692local tDayCycle = {\
3693 \"It is daytime.\",\
3694 \"It is daytime.\",\
3695 \"It is daytime.\",\
3696 \"It is daytime.\",\
3697 \"It is daytime.\",\
3698 \"It is daytime.\",\
3699 \"It is daytime.\",\
3700 \"It is daytime.\",\
3701 \"The sun is setting.\",\
3702 \"It is night.\",\
3703 \"It is night.\",\
3704 \"It is night.\",\
3705 \"It is night.\",\
3706 \"It is night.\",\
3707 \"The sun is rising.\",\
3708}\
3709\
3710local function getTimeOfDay()\
3711 return math.fmod( math.floor(nTurn/3), #tDayCycle ) + 1\
3712end\
3713\
3714local function isSunny()\
3715 return (getTimeOfDay() < 10)\
3716end\
3717\
3718local function getRoom( x, y, z, dontCreate )\
3719 tMap[x] = tMap[x] or {}\
3720 tMap[x][y] = tMap[x][y] or {}\
3721 if not tMap[x][y][z] and dontCreate ~= true then\
3722 local room = {\
3723 items = {},\
3724 exits = {},\
3725 nMonsters = 0,\
3726 }\
3727 tMap[x][y][z] = room\
3728 \
3729 if y == 0 then\
3730 -- Room is above ground\
3731\
3732 -- Pick biome\
3733 room.nBiome = math.random( 1, #tBiomes )\
3734 room.trees = hasTrees( room.nBiome )\
3735 \
3736 -- Add animals\
3737 if math.random(1,3) == 1 then\
3738 for n = 1,math.random(1,2) do\
3739 local sAnimal = tAnimals[ math.random( 1, #tAnimals ) ]\
3740 room.items[ sAnimal ] = items[ sAnimal ]\
3741 end\
3742 end\
3743 \
3744 -- Add surface ore\
3745 if math.random(1,5) == 1 or hasStone( room.nBiome ) then\
3746 room.items[ \"some stone\" ] = items[ \"some stone\" ]\
3747 end\
3748 if math.random(1,8) == 1 then\
3749 room.items[ \"some coal\" ] = items[ \"some coal\" ]\
3750 end\
3751 if math.random(1,8) == 1 and hasRivers( room.nBiome ) then\
3752 room.items[ \"a river\" ] = items[ \"a river\" ]\
3753 end\
3754\
3755 -- Add exits\
3756 room.exits = {\
3757 [\"north\"] = true,\
3758 [\"south\"] = true,\
3759 [\"east\"] = true,\
3760 [\"west\"] = true,\
3761 }\
3762 if math.random(1,8) == 1 then\
3763 room.exits[\"down\"] = true\
3764 room.items[\"a cave entrance\"] = items[\"a cave entrance\"]\
3765 end\
3766 \
3767 else\
3768 -- Room is underground\
3769 -- Add exits\
3770 local function tryExit( sDir, sOpp, x, y, z )\
3771 local adj = getRoom( x, y, z, true )\
3772 if adj then\
3773 if adj.exits[sOpp] then\
3774 room.exits[sDir] = true\
3775 end\
3776 else\
3777 if math.random(1,3) == 1 then\
3778 room.exits[sDir] = true\
3779 end\
3780 end\
3781 end\
3782 \
3783 if y == -1 then\
3784 local above = getRoom( x, y + 1, z )\
3785 if above.exits[\"down\"] then\
3786 room.exits[\"up\"] = true\
3787 room.items[\"an exit to the surface\"] = items[\"an exit to the surface\"]\
3788 end\
3789 else\
3790 tryExit( \"up\", \"down\", x, y + 1, z )\
3791 end\
3792 \
3793 if y > -3 then\
3794 tryExit( \"down\", \"up\", x, y - 1, z )\
3795 end\
3796 \
3797 tryExit( \"east\", \"west\", x - 1, y, z )\
3798 tryExit( \"west\", \"east\", x + 1, y, z )\
3799 tryExit( \"north\", \"south\", x, y, z + 1 )\
3800 tryExit( \"south\", \"north\", x, y, z - 1 ) \
3801 \
3802 -- Add ores\
3803 room.items[ \"some stone\" ] = items[ \"some stone\" ]\
3804 if math.random(1,3) == 1 then\
3805 room.items[ \"some coal\" ] = items[ \"some coal\" ]\
3806 end\
3807 if math.random(1,8) == 1 then\
3808 room.items[ \"some iron\" ] = items[ \"some iron\" ]\
3809 end\
3810 if y == -3 and math.random(1,15) == 1 then\
3811 room.items[ \"some diamond\" ] = items[ \"some diamond\" ]\
3812 end\
3813 \
3814 -- Turn out the lights\
3815 room.dark = true\
3816 end\
3817 end\
3818 return tMap[x][y][z]\
3819end\
3820\
3821local function itemize( t )\
3822 local item = next( t )\
3823 if item == nil then\
3824 return \"nothing\"\
3825 end\
3826 \
3827 local text = \"\"\
3828 while item do\
3829 text = text .. item\
3830 \
3831 local nextItem = next( t, item )\
3832 if nextItem ~= nil then\
3833 local nextNextItem = next( t, nextItem )\
3834 if nextNextItem == nil then\
3835 text = text .. \" and \"\
3836 else\
3837 text = text .. \", \"\
3838 end\
3839 end\
3840 item = nextItem\
3841 end\
3842 return text\
3843end\
3844\
3845function findItem( _tList, _sQuery )\
3846 for sItem, tItem in pairs( _tList ) do\
3847 if sItem == _sQuery then\
3848 return sItem\
3849 end\
3850 if tItem.aliases ~= nil then\
3851 for n, sAlias in pairs( tItem.aliases ) do\
3852 if sAlias == _sQuery then\
3853 return sItem\
3854 end\
3855 end\
3856 end\
3857 end\
3858 return nil\
3859end\
3860\
3861local tMatches = {\
3862 [\"wait\"] = {\
3863 \"wait\",\
3864 },\
3865 [\"look\"] = {\
3866 \"look at the ([%a ]+)\",\
3867 \"look at ([%a ]+)\",\
3868 \"look\",\
3869 \"inspect ([%a ]+)\",\
3870 \"inspect the ([%a ]+)\",\
3871 \"inspect\",\
3872 },\
3873 [\"inventory\"] = {\
3874 \"check self\",\
3875 \"check inventory\",\
3876 \"inventory\",\
3877 \"i\",\
3878 },\
3879 [\"go\"] = {\
3880 \"go (%a+)\",\
3881 \"travel (%a+)\",\
3882 \"walk (%a+)\",\
3883 \"run (%a+)\",\
3884 \"go\",\
3885 },\
3886 [\"dig\"] = {\
3887 \"dig (%a+) using ([%a ]+)\",\
3888 \"dig (%a+) with ([%a ]+)\",\
3889 \"dig (%a+)\",\
3890 \"dig\",\
3891 },\
3892 [\"take\"] = {\
3893 \"pick up the ([%a ]+)\",\
3894 \"pick up ([%a ]+)\",\
3895 \"pickup ([%a ]+)\",\
3896 \"take the ([%a ]+)\",\
3897 \"take ([%a ]+)\",\
3898 \"take\",\
3899 },\
3900 [\"drop\"] = {\
3901 \"put down the ([%a ]+)\",\
3902 \"put down ([%a ]+)\",\
3903 \"drop the ([%a ]+)\",\
3904 \"drop ([%a ]+)\",\
3905 \"drop\",\
3906 },\
3907 [\"place\"] = {\
3908 \"place the ([%a ]+)\",\
3909 \"place ([%a ]+)\",\
3910 \"place\",\
3911 },\
3912 [\"cbreak\"] = {\
3913 \"punch the ([%a ]+)\",\
3914 \"punch ([%a ]+)\",\
3915 \"punch\",\
3916 \"break the ([%a ]+) with the ([%a ]+)\",\
3917 \"break ([%a ]+) with ([%a ]+) \",\
3918 \"break the ([%a ]+)\",\
3919 \"break ([%a ]+)\",\
3920 \"break\",\
3921 },\
3922 [\"mine\"] = {\
3923 \"mine the ([%a ]+) with the ([%a ]+)\",\
3924 \"mine ([%a ]+) with ([%a ]+)\",\
3925 \"mine ([%a ]+)\",\
3926 \"mine\",\
3927 },\
3928 [\"attack\"] = {\
3929 \"attack the ([%a ]+) with the ([%a ]+)\",\
3930 \"attack ([%a ]+) with ([%a ]+)\",\
3931 \"attack ([%a ]+)\",\
3932 \"attack\",\
3933 \"kill the ([%a ]+) with the ([%a ]+)\",\
3934 \"kill ([%a ]+) with ([%a ]+)\",\
3935 \"kill ([%a ]+)\",\
3936 \"kill\",\
3937 \"hit the ([%a ]+) with the ([%a ]+)\",\
3938 \"hit ([%a ]+) with ([%a ]+)\",\
3939 \"hit ([%a ]+)\",\
3940 \"hit\",\
3941 },\
3942 [\"craft\"] = {\
3943 \"craft a ([%a ]+)\",\
3944 \"craft some ([%a ]+)\",\
3945 \"craft ([%a ]+)\",\
3946 \"craft\",\
3947 \"make a ([%a ]+)\",\
3948 \"make some ([%a ]+)\",\
3949 \"make ([%a ]+)\",\
3950 \"make\",\
3951 },\
3952 [\"build\"] = {\
3953 \"build ([%a ]+) out of ([%a ]+)\",\
3954 \"build ([%a ]+) from ([%a ]+)\",\
3955 \"build ([%a ]+)\",\
3956 \"build\",\
3957 },\
3958 [\"eat\"] = {\
3959 \"eat a ([%a ]+)\",\
3960 \"eat the ([%a ]+)\",\
3961 \"eat ([%a ]+)\",\
3962 \"eat\",\
3963 },\
3964 [\"help\"] = {\
3965 \"help me\",\
3966 \"help\",\
3967 },\
3968 [\"exit\"] = {\
3969 \"exit\",\
3970 \"quit\",\
3971 \"goodbye\",\
3972 \"good bye\",\
3973 \"bye\",\
3974 \"farewell\",\
3975 },\
3976}\
3977\
3978local commands = {}\
3979function doCommand( text )\
3980 if text == \"\" then\
3981 commands[ \"noinput\" ]()\
3982 return\
3983 end\
3984 \
3985 for sCommand, t in pairs( tMatches ) do\
3986 for n, sMatch in pairs( t ) do\
3987 local tCaptures = { string.match( text, \"^\" .. sMatch .. \"$\" ) }\
3988 if #tCaptures ~= 0 then\
3989 local fnCommand = commands[ sCommand ]\
3990 if #tCaptures == 1 and tCaptures[1] == sMatch then\
3991 fnCommand()\
3992 else\
3993 fnCommand( unpack( tCaptures ) )\
3994 end\
3995 return\
3996 end\
3997 end\
3998 end\
3999 commands[ \"badinput\" ]()\
4000end\
4001\
4002function commands.wait()\
4003 print( \"Time passes...\" )\
4004end\
4005\
4006function commands.look( _sTarget )\
4007 local room = getRoom( x,y,z )\
4008 if room.dark then\
4009 print( \"It is pitch dark.\" )\
4010 return\
4011 end\
4012\
4013 if _sTarget == nil then\
4014 -- Look at the world\
4015 if y == 0 then\
4016 io.write( \"You are standing \" .. tBiomes[room.nBiome] .. \". \" )\
4017 print( tDayCycle[ getTimeOfDay() ] )\
4018 else\
4019 io.write( \"You are underground. \" )\
4020 if next( room.exits ) ~= nil then\
4021 print( \"You can travel \"..itemize( room.exits )..\".\" )\
4022 else\
4023 print()\
4024 end\
4025 end\
4026 if next( room.items ) ~= nil then\
4027 print( \"There is \" .. itemize( room.items ) .. \" here.\" )\
4028 end\
4029 if room.trees then\
4030 print( \"There are trees here.\" )\
4031 end\
4032 \
4033 else\
4034 -- Look at stuff\
4035 if room.trees and (_sTarget == \"tree\" or _sTarget == \"trees\") then\
4036 print( \"The trees look easy to break.\" )\
4037 elseif _sTarget == \"self\" or _sTarget == \"myself\" then\
4038 print( \"Very handsome.\" )\
4039 else\
4040 local tItem = nil\
4041 local sItem = findItem( room.items, _sTarget )\
4042 if sItem then\
4043 tItem = room.items[sItem]\
4044 else\
4045 sItem = findItem( inventory, _sTarget )\
4046 if sItem then\
4047 tItem = inventory[sItem]\
4048 end\
4049 end\
4050 \
4051 if tItem then\
4052 print( tItem.desc or (\"You see nothing special about \"..sItem..\".\") )\
4053 else\
4054 print( \"You don't see any \".._sTarget..\" here.\" )\
4055 end\
4056 end\
4057 end\
4058end\
4059\
4060function commands.go( _sDir )\
4061 local room = getRoom( x,y,z )\
4062 if _sDir == nil then\
4063 print( \"Go where?\" )\
4064 return\
4065 end\
4066 \
4067 if nGoWest ~= nil then\
4068 if _sDir == \"west\" then\
4069 nGoWest = nGoWest + 1\
4070 if nGoWest > #tGoWest then\
4071 nGoWest = 1\
4072 end\
4073 print( tGoWest[ nGoWest ] )\
4074 else\
4075 if nGoWest > 0 or nTurn > 6 then\
4076 nGoWest = nil\
4077 end\
4078 end\
4079 end\
4080 \
4081 if room.exits[_sDir] == nil then\
4082 print( \"You can't go that way.\" )\
4083 return\
4084 end\
4085 \
4086 if _sDir == \"north\" then\
4087 z = z + 1\
4088 elseif _sDir == \"south\" then\
4089 z = z - 1\
4090 elseif _sDir == \"east\" then\
4091 x = x - 1\
4092 elseif _sDir == \"west\" then\
4093 x = x + 1\
4094 elseif _sDir == \"up\" then\
4095 y = y + 1\
4096 elseif _sDir == \"down\" then\
4097 y = y - 1\
4098 else\
4099 print( \"I don't understand that direction.\" )\
4100 return\
4101 end\
4102 \
4103 nTimeInRoom = 0\
4104 doCommand( \"look\" )\
4105end\
4106\
4107function commands.dig( _sDir, _sTool )\
4108 local room = getRoom( x,y,z )\
4109 if _sDir == nil then\
4110 print( \"Dig where?\" )\
4111 return\
4112 end\
4113 \
4114 local sTool = nil\
4115 local tTool = nil\
4116 if _sTool ~= nil then\
4117 sTool = findItem( inventory, _sTool )\
4118 if not sTool then\
4119 print( \"You're not carrying a \".._sTool..\".\" )\
4120 return\
4121 end\
4122 tTool = inventory[ sTool ]\
4123 end\
4124 \
4125 local room = getRoom( x, y, z )\
4126 local bActuallyDigging = (room.exits[ _sDir ] ~= true)\
4127 if bActuallyDigging then\
4128 if sTool == nil or tTool.toolType ~= \"pick\" then\
4129 print( \"You need to use a pickaxe to dig through stone.\" )\
4130 return\
4131 end\
4132 end\
4133 \
4134 if _sDir == \"north\" then\
4135 room.exits[\"north\"] = true\
4136 z = z + 1\
4137 getRoom( x, y, z ).exits[\"south\"] = true\
4138\
4139 elseif _sDir == \"south\" then\
4140 room.exits[\"south\"] = true\
4141 z = z - 1\
4142 getRoom( x, y, z ).exits[\"north\"] = true\
4143 \
4144 elseif _sDir == \"east\" then\
4145 room.exits[\"east\"] = true\
4146 x = x - 1\
4147 getRoom( x, y, z ).exits[\"west\"] = true\
4148 \
4149 elseif _sDir == \"west\" then\
4150 room.exits[\"west\"] = true\
4151 x = x + 1\
4152 getRoom( x, y, z ).exits[\"east\"] = true\
4153 \
4154 elseif _sDir == \"up\" then\
4155 if y == 0 then\
4156 print( \"You can't dig that way.\" )\
4157 return\
4158 end\
4159\
4160 room.exits[\"up\"] = true\
4161 if y == -1 then\
4162 room.items[ \"an exit to the surface\" ] = items[ \"an exit to the surface\" ]\
4163 end\
4164 y = y + 1\
4165 \
4166 room = getRoom( x, y, z )\
4167 room.exits[\"down\"] = true\
4168 if y == 0 then\
4169 room.items[ \"a cave entrance\" ] = items[ \"a cave entrance\" ]\
4170 end\
4171 \
4172 elseif _sDir == \"down\" then\
4173 if y <= -3 then\
4174 print( \"You hit bedrock.\" )\
4175 return\
4176 end\
4177\
4178 room.exits[\"down\"] = true\
4179 if y == 0 then\
4180 room.items[ \"a cave entrance\" ] = items[ \"a cave entrance\" ]\
4181 end\
4182 y = y - 1\
4183 \
4184 room = getRoom( x, y, z )\
4185 room.exits[\"up\"] = true\
4186 if y == -1 then\
4187 room.items[ \"an exit to the surface\" ] = items[ \"an exit to the surface\" ]\
4188 end\
4189 \
4190 else\
4191 print( \"I don't understand that direction.\" )\
4192 return\
4193 end\
4194 \
4195 --\
4196 if bActuallyDigging then\
4197 if _sDir == \"down\" and y == -1 or\
4198 _sDir == \"up\" and y == 0 then\
4199 inventory[ \"some dirt\" ] = items[ \"some dirt\" ]\
4200 inventory[ \"some stone\" ] = items[ \"some stone\" ]\
4201 print( \"You dig \".._sDir..\" using \"..sTool..\" and collect some dirt and stone.\" )\
4202 else\
4203 inventory[ \"some stone\" ] = items[ \"some stone\" ]\
4204 print( \"You dig \".._sDir..\" using \"..sTool..\" and collect some stone.\" )\
4205 end\
4206 end\
4207 \
4208 nTimeInRoom = 0\
4209 doCommand( \"look\" )\
4210end\
4211\
4212function commands.inventory()\
4213 print( \"You are carrying \" .. itemize( inventory ) .. \".\" )\
4214end\
4215\
4216function commands.drop( _sItem )\
4217 if _sItem == nil then\
4218 print( \"Drop what?\" )\
4219 return\
4220 end\
4221 \
4222 local room = getRoom( x,y,z )\
4223 local sItem = findItem( inventory, _sItem )\
4224 if sItem then\
4225 local tItem = inventory[ sItem ]\
4226 if tItem.droppable == false then\
4227 print( \"You can't drop that.\" )\
4228 else\
4229 room.items[ sItem ] = tItem\
4230 inventory[ sItem ] = nil\
4231 print( \"Dropped.\" )\
4232 end\
4233 else\
4234 print( \"You don't have a \".._sItem..\".\" )\
4235 end\
4236end\
4237\
4238function commands.place( _sItem )\
4239 if _sItem == nil then\
4240 print( \"Place what?\" )\
4241 return\
4242 end\
4243 \
4244 if _sItem == \"torch\" or _sItem == \"a torch\" then\
4245 local room = getRoom( x,y,z )\
4246 if inventory[\"some torches\"] or inventory[\"a torch\"] then\
4247 inventory[\"a torch\"] = nil\
4248 room.items[\"a torch\"] = items[\"a torch\"]\
4249 if room.dark then\
4250 print( \"The cave lights up under the torchflame.\" )\
4251 room.dark = false\
4252 elseif y == 0 and not isSunny() then\
4253 print( \"The night gets a little brighter.\" )\
4254 else\
4255 print( \"Placed.\" )\
4256 end\
4257 else\
4258 print( \"You don't have torches.\" )\
4259 end\
4260 return\
4261 end\
4262 \
4263 commands.drop( _sItem )\
4264end\
4265\
4266function commands.take( _sItem )\
4267 if _sItem == nil then\
4268 print( \"Take what?\" )\
4269 return\
4270 end\
4271\
4272 local room = getRoom( x,y,z )\
4273 local sItem = findItem( room.items, _sItem )\
4274 if sItem then\
4275 local tItem = room.items[ sItem ]\
4276 if tItem.heavy == true then\
4277 print( \"You can't carry \"..sItem..\".\" )\
4278 elseif tItem.ore == true then\
4279 print( \"You need to mine this ore.\" )\
4280 else\
4281 if tItem.infinite ~= true then\
4282 room.items[ sItem ] = nil\
4283 end\
4284 inventory[ sItem ] = tItem\
4285 \
4286 if inventory[\"some torches\"] and inventory[\"a torch\"] then\
4287 inventory[\"a torch\"] = nil\
4288 end\
4289 if sItem == \"a torch\" and y < 0 then\
4290 room.dark = true\
4291 print( \"The cave plunges into darkness.\" )\
4292 else\
4293 print( \"Taken.\" )\
4294 end\
4295 end\
4296 else\
4297 print( \"You don't see a \".._sItem..\" here.\" )\
4298 end\
4299end\
4300\
4301function commands.mine( _sItem, _sTool )\
4302 if _sItem == nil then\
4303 print( \"Mine what?\" )\
4304 return\
4305 end\
4306 if _sTool == nil then\
4307 print( \"Mine \".._sItem..\" with what?\" )\
4308 return\
4309 end \
4310 commands.cbreak( _sItem, _sTool )\
4311end\
4312\
4313function commands.attack( _sItem, _sTool )\
4314 if _sItem == nil then\
4315 print( \"Attack what?\" )\
4316 return\
4317 end\
4318 commands.cbreak( _sItem, _sTool )\
4319end\
4320\
4321function commands.cbreak( _sItem, _sTool )\
4322 if _sItem == nil then\
4323 print( \"Break what?\" )\
4324 return\
4325 end\
4326 \
4327 local sTool = nil\
4328 if _sTool ~= nil then\
4329 sTool = findItem( inventory, _sTool )\
4330 if sTool == nil then\
4331 print( \"You're not carrying a \".._sTool..\".\" )\
4332 return\
4333 end\
4334 end\
4335\
4336 local room = getRoom( x,y,z )\
4337 if _sItem == \"tree\" or _sItem == \"trees\" or _sItem == \"a tree\" then\
4338 print( \"The tree breaks into blocks of wood, which you pick up.\" )\
4339 inventory[ \"some wood\" ] = items[ \"some wood\" ]\
4340 return\
4341 elseif _sItem == \"self\" or _sItem == \"myself\" then\
4342 if term.isColour() then\
4343 term.setTextColour( colours.red )\
4344 end\
4345 print( \"You have died.\" )\
4346 print( \"Score: &e0\" )\
4347 term.setTextColour( colours.white )\
4348 bRunning = false\
4349 return\
4350 end\
4351 \
4352 local sItem = findItem( room.items, _sItem )\
4353 if sItem then\
4354 local tItem = room.items[ sItem ]\
4355 if tItem.ore == true then\
4356 -- Breaking ore\
4357 if not sTool then\
4358 print( \"You need a tool to break this ore.\" )\
4359 return\
4360 end\
4361 local tTool = inventory[ sTool ]\
4362 if tTool.tool then\
4363 if tTool.toolLevel < tItem.toolLevel then\
4364 print( sTool ..\" is not strong enough to break this ore.\" )\
4365 elseif tTool.toolType ~= tItem.toolType then\
4366 print( \"You need a different kind of tool to break this ore.\" )\
4367 else\
4368 print( \"The ore breaks, dropping \"..sItem..\", which you pick up.\" )\
4369 inventory[ sItem ] = items[ sItem ]\
4370 if tItem.infinite ~= true then\
4371 room.items[ sItem ] = nil\
4372 end\
4373 end\
4374 else\
4375 print( \"You can't break \"..sItem..\" with \"..sTool..\".\")\
4376 end\
4377 \
4378 elseif tItem.creature == true then\
4379 -- Fighting monsters (or pigs)\
4380 local toolLevel = 0\
4381 local tTool = nil\
4382 if sTool then\
4383 tTool = inventory[ sTool ]\
4384 if tTool.toolType == \"sword\" then\
4385 toolLevel = tTool.toolLevel\
4386 end\
4387 end\
4388 \
4389 local tChances = { 0.2, 0.4, 0.55, 0.8, 1 }\
4390 if math.random() <= tChances[ toolLevel + 1 ] then\
4391 room.items[ sItem ] = nil\
4392 print( \"The \"..tItem.aliases[1]..\" dies.\" )\
4393 \
4394 if tItem.drops then\
4395 for n, sDrop in pairs( tItem.drops ) do\
4396 if not room.items[sDrop] then\
4397 print( \"The \"..tItem.aliases[1]..\" dropped \"..sDrop..\".\" )\
4398 room.items[sDrop] = items[sDrop]\
4399 end\
4400 end\
4401 end\
4402 \
4403 if tItem.monster then\
4404 room.nMonsters = room.nMonsters - 1\
4405 end\
4406 else\
4407 print( \"The \"..tItem.aliases[1]..\" is injured by your blow.\" )\
4408 end\
4409 \
4410 if tItem.hitDrops then\
4411 for n, sDrop in pairs( tItem.hitDrops ) do\
4412 if not room.items[sDrop] then\
4413 print( \"The \"..tItem.aliases[1]..\" dropped \"..sDrop..\".\" )\
4414 room.items[sDrop] = items[sDrop]\
4415 end\
4416 end\
4417 end\
4418 \
4419 else\
4420 print( \"You can't break \"..sItem..\".\" )\
4421 end\
4422 else\
4423 print( \"You don't see a \".._sItem..\" here.\" )\
4424 end\
4425end\
4426\
4427function commands.craft( _sItem )\
4428 if _sItem == nil then\
4429 print( \"Craft what?\" )\
4430 return\
4431 end\
4432 \
4433 if _sItem == \"computer\" or _sItem == \"a computer\" then\
4434 print( \"By creating a computer in a computer in a computer, you tear a hole in the spacetime continuum from which no mortal being can escape.\" )\
4435 if term.isColour() then\
4436 term.setTextColour( colours.red )\
4437 end\
4438 print( \"You have died.\" )\
4439 print( \"Score: &e0\" )\
4440 term.setTextColour( colours.white )\
4441 bRunning = false\
4442 return\
4443 end\
4444 \
4445 local room = getRoom( x,y,z )\
4446 local sItem = findItem( items, _sItem )\
4447 local tRecipe = (sItem and tRecipes[ sItem ]) or nil\
4448 if tRecipe then\
4449 for n,sReq in ipairs( tRecipe ) do\
4450 if inventory[sReq] == nil then\
4451 print( \"You don't have the items you need to craft \"..sItem..\".\" )\
4452 return\
4453 end\
4454 end\
4455 \
4456 for n,sReq in ipairs( tRecipe ) do\
4457 inventory[sReq] = nil\
4458 end\
4459 inventory[ sItem ] = items[ sItem ]\
4460 if inventory[\"some torches\"] and inventory[\"a torch\"] then\
4461 inventory[\"a torch\"] = nil\
4462 end\
4463 print( \"Crafted.\" )\
4464 else\
4465 print( \"You don't know how to make \"..(sItem or _sItem)..\".\" )\
4466 end \
4467end\
4468\
4469function commands.build( _sThing, _sMaterial )\
4470 if _sThing == nil then\
4471 print( \"Build what?\" )\
4472 return\
4473 end\
4474 \
4475 local sMaterial = nil\
4476 if _sMaterial == nil then\
4477 for sItem, tItem in pairs( inventory ) do\
4478 if tItem.material then\
4479 sMaterial = sItem\
4480 break\
4481 end\
4482 end\
4483 if sMaterial == nil then\
4484 print( \"You don't have any building materials.\" )\
4485 return\
4486 end\
4487 else\
4488 sMaterial = findItem( inventory, _sMaterial )\
4489 if not sMaterial then\
4490 print( \"You don't have any \".._sMaterial )\
4491 return\
4492 end\
4493 \
4494 if inventory[sMaterial].material ~= true then\
4495 print( sMaterial..\" is not a good building material.\" )\
4496 return\
4497 end\
4498 end\
4499 \
4500 local alias = nil\
4501 if string.sub(_sThing, 1, 1) == \"a\" then\
4502 alias = string.match( _sThing, \"a ([%a ]+)\" )\
4503 end\
4504 \
4505 local room = getRoom( x,y,z )\
4506 inventory[sMaterial] = nil\
4507 room.items[ _sThing ] = {\
4508 heavy = true,\
4509 aliases = { alias },\
4510 desc = \"As you look at your creation (made from \"..sMaterial..\"), you feel a swelling sense of pride.\",\
4511 }\
4512\
4513 print( \"Your construction is complete.\" )\
4514end\
4515\
4516function commands.help()\
4517 local sText = \
4518 \"Welcome to adventure, the greatest text adventure game on CraftOS. \" ..\
4519 \"To get around the world, type actions, and the adventure will \" ..\
4520 \"be read back to you. The actions availiable to you are go, look, inspect, inventory, \" ..\
4521 \"take, drop, place, punch, attack, mine, dig, craft, build, eat and exit.\"\
4522 print( sText )\
4523end\
4524\
4525function commands.eat( _sItem )\
4526 if _sItem == nil then\
4527 print( \"Eat what?\" )\
4528 return\
4529 end\
4530\
4531 local sItem = findItem( inventory, _sItem )\
4532 if not sItem then\
4533 print( \"You don't have any \".._sItem..\".\" )\
4534 return\
4535 end\
4536 \
4537 local tItem = inventory[sItem]\
4538 if tItem.food then\
4539 print( \"That was delicious!\" )\
4540 inventory[sItem] = nil\
4541 \
4542 if bInjured then\
4543 print( \"You are no longer injured.\" )\
4544 bInjured = false\
4545 end\
4546 else\
4547 print( \"You can't eat \"..sItem..\".\" )\
4548 end\
4549end\
4550\
4551function commands.exit()\
4552 bRunning = false\
4553end\
4554\
4555function commands.badinput()\
4556 local tResponses = {\
4557 \"I don't understand.\",\
4558 \"I don't understand you.\",\
4559 \"You can't do that.\",\
4560 \"Nope.\",\
4561 \"Huh?\",\
4562 \"Say again?\",\
4563 \"That's crazy talk.\",\
4564 \"Speak clearly.\",\
4565 \"I'll think about it.\",\
4566 \"Let me get back to you on that one.\",\
4567 \"That doesn't make any sense.\",\
4568 \"What?\",\
4569 }\
4570 print( tResponses[ math.random(1,#tResponses) ] )\
4571end\
4572\
4573function commands.noinput()\
4574 local tResponses = {\
4575 \"Speak up.\",\
4576 \"Enunciate.\",\
4577 \"Project your voice.\",\
4578 \"Don't be shy.\",\
4579 \"Use your words.\",\
4580 }\
4581 print( tResponses[ math.random(1,#tResponses) ] )\
4582end\
4583\
4584local function simulate()\
4585 local bNewMonstersThisRoom = false\
4586 \
4587 -- Spawn monsters in nearby rooms\
4588 for sx = -2,2 do\
4589 for sy = -1,1 do\
4590 for sz = -2,2 do\
4591 local h = y + sy\
4592 if h >= -3 and h <= 0 then\
4593 local room = getRoom( x + sx, h, z + sz )\
4594 \
4595 -- Spawn monsters\
4596 if room.nMonsters < 2 and\
4597 ((h == 0 and not isSunny() and not room.items[\"a torch\"]) or room.dark) and\
4598 math.random(1,6) == 1 then\
4599 \
4600 local sMonster = tMonsters[ math.random(1,#tMonsters) ]\
4601 if room.items[ sMonster ] == nil then\
4602 room.items[ sMonster ] = items[ sMonster ]\
4603 room.nMonsters = room.nMonsters + 1\
4604 \
4605 if sx == 0 and sy == 0 and sz == 0 and not room.dark then\
4606 print( \"From the shadows, \"..sMonster..\" appears.\" )\
4607 bNewMonstersThisRoom = true\
4608 end\
4609 end \
4610 end\
4611 \
4612 -- Burn monsters\
4613 if h == 0 and isSunny() then\
4614 for n,sMonster in ipairs( tMonsters ) do\
4615 if room.items[sMonster] and items[sMonster].nocturnal then\
4616 room.items[sMonster] = nil\
4617 if sx == 0 and sy == 0 and sz == 0 and not room.dark then\
4618 print( \"With the sun high in the sky, the \"..items[sMonster].aliases[1]..\" bursts into flame and dies.\" )\
4619 end\
4620 room.nMonsters = room.nMonsters - 1\
4621 end\
4622 end\
4623 end \
4624 end\
4625 end\
4626 end\
4627 end\
4628\
4629 -- Make monsters attack\
4630 local room = getRoom( x, y, z )\
4631 if nTimeInRoom >= 2 and not bNewMonstersThisRoom then\
4632 for n,sMonster in ipairs( tMonsters ) do\
4633 if room.items[sMonster] then\
4634 if math.random(1,4) == 1 and\
4635 not (y == 0 and isSunny() and (sMonster == \"a spider\")) then\
4636 if sMonster == \"a creeper\" then\
4637 if room.dark then\
4638 print( \"A creeper explodes.\" )\
4639 else\
4640 print( \"The creeper explodes.\" )\
4641 end\
4642 room.items[sMonster] = nil\
4643 room.nMonsters = room.nMonsters - 1\
4644 else\
4645 if room.dark then\
4646 print( \"A \"..items[sMonster].aliases[1]..\" attacks you.\" )\
4647 else\
4648 print( \"The \"..items[sMonster].aliases[1]..\" attacks you.\" )\
4649 end\
4650 end\
4651 \
4652 if bInjured then\
4653 if term.isColour() then\
4654 term.setTextColour( colours.red )\
4655 end\
4656 print( \"You have died.\" )\
4657 print( \"Score: &e0\" )\
4658 term.setTextColour( colours.white )\
4659 bRunning = false\
4660 return\
4661 else\
4662 bInjured = true\
4663 end\
4664 \
4665 break\
4666 end\
4667 end\
4668 end\
4669 end\
4670 \
4671 -- Always print this\
4672 if bInjured then\
4673 if term.isColour() then\
4674 term.setTextColour( colours.red )\
4675 end\
4676 print( \"You are injured.\" )\
4677 term.setTextColour( colours.white )\
4678 end\
4679 \
4680 -- Advance time\
4681 nTurn = nTurn + 1\
4682 nTimeInRoom = nTimeInRoom + 1\
4683end\
4684\
4685doCommand( \"look\" )\
4686simulate()\
4687\
4688local tCommandHistory = {}\
4689while bRunning do\
4690 if term.isColour() then\
4691 term.setTextColour( colours.yellow )\
4692 end\
4693 write( \"? \" )\
4694 term.setTextColour( colours.white )\
4695 \
4696 local sRawLine = read( nil, tCommandHistory )\
4697 table.insert( tCommandHistory, sRawLine )\
4698 \
4699 local sLine = nil\
4700 for match in string.gmatch(sRawLine, \"%a+\") do\
4701 if sLine then\
4702 sLine = sLine .. \" \" .. string.lower(match)\
4703 else\
4704 sLine = string.lower(match)\
4705 end\
4706 end\
4707 \
4708 doCommand( sLine or \"\" )\
4709 if bRunning then\
4710 simulate()\
4711 end\
4712end\
4713",
4714 dj = "local tArgs = { ... }\
4715\
4716local function printUsage()\
4717 print( \"Usages:\")\
4718 print( \"dj play\" )\
4719 print( \"dj play <drive>\" )\
4720 print( \"dj stop\" )\
4721end\
4722\
4723if #tArgs > 2 then\
4724 printUsage()\
4725 return\
4726end\
4727\
4728local sCommand = tArgs[1]\
4729if sCommand == \"stop\" then\
4730 -- Stop audio\
4731 disk.stopAudio()\
4732\
4733elseif sCommand == \"play\" or sCommand == nil then\
4734 -- Play audio\
4735 local sName = tArgs[2]\
4736 if sName == nil then\
4737 -- No disc specified, pick one at random\
4738 local tNames = {}\
4739 for n,sName in ipairs( peripheral.getNames() ) do\
4740 if disk.isPresent( sName ) and disk.hasAudio( sName ) then\
4741 table.insert( tNames, sName )\
4742 end\
4743 end\
4744 if #tNames == 0 then\
4745 print( \"No Music Discs in attached disk drives\" )\
4746 return\
4747 end\
4748 sName = tNames[ math.random(1,#tNames) ]\
4749 end\
4750\
4751 -- Play the disc\
4752 if disk.isPresent( sName ) and disk.hasAudio( sName ) then\
4753 print( \"Playing \"..disk.getAudioTitle( sName ) )\
4754 disk.playAudio( sName )\
4755 else\
4756 print( \"No Music Disc in disk drive: \"..sName )\
4757 return\
4758 end\
4759 \
4760else\
4761 printUsage()\
4762 \
4763end\
4764",
4765 advanced = {
4766 levels = {
4767 [ "1" ] = "1\
4768 777\
4769 7b7\
4770 787\
47717777778777\
47727188888887\
47737777777777\
4774",
4775 [ "0" ] = "0\
477677 77\
4777718888887\
4778 8 8\
4779 8 8\
4780 8 8\
4781788888897\
478277 77\
4783",
4784 [ "3" ] = "2\
4785 77777777\
4786777888188777\
47877b78777787b7\
478878787 78787\
478978787 78787\
479078887 78887\
4791777877778777\
4792 78838887\
4793 77777777\
4794",
4795 [ "2" ] = "1\
4796777777777\
47977888888b7\
4798787778887\
4799787 78777\
48007877787\
48017888887\
48027777787\
4803 707\
4804 777\
4805",
4806 [ "5" ] = "3\
4807777777777\
4808788888887\
4809787787787\
4810787787787\
4811788888887\
4812787787787\
4813787787787\
481478e748887\
4815777777777\
4816",
4817 [ "4" ] = "2\
4818 77777777\
4819777778888887\
4820788888777787\
48217b77787 787\
4822787 787 787\
48237b77787 787\
48247888887 787\
48257777707 707\
4826 777 777\
4827",
4828 [ "7" ] = "3\
4829728777778b7\
483078888888887\
483178777877787\
4832787 787 787\
4833787 7877788\
4834787 7888889\
483588777877777\
4836e888887\
48377777887\
4838",
4839 [ "6" ] = "4\
48407777777777\
48417288888837\
484278 87\
4843788888b 87\
4844788888b 87\
4845788888b 87\
4846788888b 87\
484778 87\
48487188888807\
48497777777777\
4850",
4851 [ "9" ] = "2\
4852 777 777\
4853 777877778777\
4854 788838888887\
48557778bbbbbbbb8777\
48567888b888888b8897\
48577878be8888eb8787\
48587588b888888b8887\
48597778bbbbbbbb8777\
4860 788888818887\
4861 777877778777\
4862 777 777\
4863",
4864 [ "8" ] = "4\
4865777777 7777\
48667287b7 7867\
4867788787 7887\
486877878777877\
4869 7888eb8887\
4870 77877787877\
4871 7887 787887\
4872 7487 7e7807\
4873 7777 777777\
4874",
4875 [ "12" ] = "6\
487677 777 77\
487772888888897\
4878 8 8 8\
4879 8 8b888 8\
488078 e8888 87\
488178888788887\
488278 8888e 87\
4883 8 888b8 8\
4884 8 8 8\
488575888888807\
488677 777 77\
4887",
4888 [ "11" ] = "4\
4889 777777777\
4890 727872787\
4891 787878787\
4892777787878787777\
48937be888888888be7\
4894777787878787777\
4895 787878787\
4896 787478747\
4897 777777777\
4898",
4899 [ "10" ] = "5\
4900 777 77777\
4901 727777778837\
4902 788888878787\
4903 787777888887\
490477877778777777\
49057e8b7888b888e7\
49067787787b777877\
4907 777887887887\
4908 7487807487\
4909 7777777777\
4910",
4911 },
4912 paint = "-- Paint created by nitrogenfingers (edited by dan200)\
4913-- http://www.youtube.com/user/NitrogenFingers\
4914\
4915------------\
4916-- Fields --\
4917------------\
4918\
4919-- The width and height of the terminal\
4920local w,h = term.getSize()\
4921\
4922-- The selected colours on the left and right mouse button, and the colour of the canvas\
4923local leftColour, rightColour = colours.white, nil\
4924local canvasColour = colours.black\
4925\
4926-- The values stored in the canvas\
4927local canvas = {}\
4928\
4929-- The menu options\
4930local mChoices = { \"Save\",\"Exit\" }\
4931\
4932-- The message displayed in the footer bar\
4933local fMessage = \"Press Ctrl to access menu\"\
4934\
4935-------------------------\
4936-- Initialisation --\
4937-------------------------\
4938\
4939-- Determine if we can even run this\
4940if not term.isColour() then\
4941 print(\"Requires an Advanced Computer\")\
4942 return\
4943end\
4944\
4945-- Determines if the file exists, and can be edited on this computer\
4946local tArgs = {...}\
4947if #tArgs == 0 then\
4948 print(\"Usage: paint <path>\")\
4949 return\
4950end\
4951local sPath = shell.resolve(tArgs[1])\
4952local bReadOnly = fs.isReadOnly(sPath)\
4953if fs.exists(sPath) and fs.isDir(sPath) then\
4954 print(\"Cannot edit a directory.\")\
4955 return\
4956end\
4957\
4958---------------\
4959-- Functions --\
4960---------------\
4961\
4962local function getCanvasPixel( x, y )\
4963 if canvas[y] then\
4964 return canvas[y][x]\
4965 end\
4966 return nil\
4967end\
4968\
4969--[[\
4970 Converts a colour value to a text character\
4971 params: colour = the number to convert to a hex value\
4972 returns: a string representing the chosen colour\
4973]]\
4974local function getCharOf( colour )\
4975 -- Incorrect values always convert to nil\
4976 if type(colour) == \"number\" then\
4977 local value = math.floor( math.log(colour) / math.log(2) ) + 1\
4978 if value >= 1 and value <= 16 then\
4979 return string.sub( \"0123456789abcdef\", value, value )\
4980 end\
4981 end\
4982 return \" \"\
4983end \
4984\
4985--[[\
4986 Converts a text character to colour value\
4987 params: char = the char (from string.byte) to convert to number\
4988 returns: the colour number of the hex value\
4989]]\
4990local tColourLookup = {}\
4991for n=1,16 do\
4992 tColourLookup[ string.byte( \"0123456789abcdef\",n,n ) ] = 2^(n-1)\
4993end\
4994local function getColourOf( char )\
4995 -- Values not in the hex table are transparent (canvas coloured)\
4996 return tColourLookup[char]\
4997end\
4998\
4999--[[ \
5000 Loads the file into the canvas\
5001 params: path = the path of the file to open\
5002 returns: nil\
5003]]\
5004local function load(path)\
5005 -- Load the file\
5006 if fs.exists(path) then\
5007 local file = fs.open(sPath, \"r\")\
5008 local sLine = file.readLine()\
5009 while sLine do\
5010 local line = {}\
5011 for x=1,w-2 do\
5012 line[x] = getColourOf( string.byte(sLine,x,x) )\
5013 end\
5014 table.insert( canvas, line )\
5015 sLine = file.readLine()\
5016 end\
5017 file.close()\
5018 end\
5019end\
5020\
5021--[[ \
5022 Saves the current canvas to file \
5023 params: path = the path of the file to save\
5024 returns: true if save was successful, false otherwise\
5025]]\
5026local function save(path)\
5027 -- Open file\
5028 local sDir = string.sub(sPath, 1, #sPath - #fs.getName(sPath))\
5029 if not fs.exists(sDir) then\
5030 fs.makeDir(sDir)\
5031 end\
5032\
5033 local file = fs.open( path, \"w\" )\
5034 if not file then\
5035 return false\
5036 end\
5037\
5038 -- Encode (and trim)\
5039 local tLines = {}\
5040 local nLastLine = 0\
5041 for y=1,h-1 do\
5042 local sLine = \"\"\
5043 local nLastChar = 0\
5044 for x=1,w-2 do\
5045 local c = getCharOf( getCanvasPixel( x, y ) )\
5046 sLine = sLine .. c\
5047 if c ~= \" \" then\
5048 nLastChar = x\
5049 end\
5050 end\
5051 sLine = string.sub( sLine, 1, nLastChar )\
5052 tLines[y] = sLine\
5053 if string.len( sLine ) > 0 then\
5054 nLastLine = y\
5055 end\
5056 end\
5057\
5058 -- Save out\
5059 for n=1,nLastLine do\
5060 file.writeLine( tLines[ n ] )\
5061 end\
5062 file.close()\
5063 return true\
5064end\
5065\
5066--[[ \
5067 Draws colour picker sidebar, the pallette and the footer\
5068 returns: nil\
5069]]\
5070local function drawInterface()\
5071 -- Footer\
5072 term.setCursorPos(1, h)\
5073 term.setBackgroundColour(colours.black)\
5074 term.setTextColour(colours.yellow)\
5075 term.clearLine()\
5076 term.write(fMessage)\
5077 \
5078 -- Colour Picker\
5079 for i=1,16 do\
5080 term.setCursorPos(w-1, i)\
5081 term.setBackgroundColour( 2^(i-1) )\
5082 term.write(\" \")\
5083 end\
5084\
5085 term.setCursorPos(w-1, 17)\
5086 term.setBackgroundColour( canvasColour )\
5087 term.setTextColour( colours.grey )\
5088 term.write(\"XX\")\
5089 \
5090 -- Left and Right Selected Colours\
5091 for i=18,18 do\
5092 term.setCursorPos(w-1, i)\
5093 if leftColour ~= nil then\
5094 term.setBackgroundColour( leftColour )\
5095 term.write(\" \")\
5096 else\
5097 term.setBackgroundColour( canvasColour )\
5098 term.setTextColour( colours.grey )\
5099 term.write(\"X\")\
5100 end\
5101 if rightColour ~= nil then\
5102 term.setBackgroundColour( rightColour )\
5103 term.write(\" \")\
5104 else\
5105 term.setBackgroundColour( canvasColour )\
5106 term.setTextColour( colours.grey )\
5107 term.write(\"X\")\
5108 end\
5109 end\
5110\
5111 -- Padding\
5112 term.setBackgroundColour( canvasColour )\
5113 for i=20,h-1 do\
5114 term.setCursorPos(w-1, i)\
5115 term.write(\" \")\
5116 end\
5117end\
5118\
5119--[[ \
5120 Converts a single pixel of a single line of the canvas and draws it\
5121 returns: nil\
5122]]\
5123local function drawCanvasPixel( x, y )\
5124 local pixel = getCanvasPixel( x, y )\
5125 if pixel then\
5126 term.setBackgroundColour( pixel or canvasColour )\
5127 term.setCursorPos(x, y)\
5128 term.write(\" \")\
5129 else\
5130 term.setBackgroundColour( canvasColour )\
5131 term.setTextColour( colours.grey )\
5132 term.setCursorPos(x, y)\
5133 term.write(\"-\")\
5134 end\
5135end\
5136\
5137--[[ \
5138 Converts each colour in a single line of the canvas and draws it\
5139 returns: nil\
5140]]\
5141local function drawCanvasLine( y )\
5142 for x = 1, w-2 do\
5143 drawCanvasPixel( x, y )\
5144 end\
5145end\
5146\
5147--[[ \
5148 Converts each colour in the canvas and draws it\
5149 returns: nil\
5150]]\
5151local function drawCanvas()\
5152 for y = 1, h-1 do\
5153 drawCanvasLine( y )\
5154 end\
5155end\
5156\
5157--[[\
5158 Draws menu options and handles input from within the menu.\
5159 returns: true if the program is to be exited; false otherwise\
5160]]\
5161local function accessMenu()\
5162 -- Selected menu option\
5163 local selection = 1\
5164 \
5165 term.setBackgroundColour(colours.black)\
5166 while true do\
5167 -- Draw the menu\
5168 term.setCursorPos(1,h)\
5169 term.clearLine()\
5170 term.setTextColour(colours.white)\
5171 for k,v in pairs(mChoices) do\
5172 if selection==k then \
5173 term.setTextColour(colours.yellow)\
5174 local ox,_ = term.getCursorPos()\
5175 term.write(\"[\"..string.rep(\" \",#v)..\"]\")\
5176 term.setCursorPos(ox+1,h)\
5177 term.setTextColour(colours.white)\
5178 term.write(v)\
5179 term.setCursorPos(term.getCursorPos()+1,h)\
5180 else\
5181 term.write(\" \"..v..\" \")\
5182 end\
5183 end\
5184 \
5185 -- Handle input in the menu\
5186 local id,key = os.pullEvent(\"key\")\
5187 if id == \"key\" then\
5188 -- S and E are shortcuts\
5189 if key == keys.s then\
5190 selection = 1\
5191 key = keys.enter\
5192 elseif key == keys.e then\
5193 selection = 2\
5194 key = keys.enter\
5195 end\
5196 \
5197 if key == keys.right then\
5198 -- Move right\
5199 selection = selection + 1\
5200 if selection > #mChoices then\
5201 selection = 1\
5202 end\
5203 \
5204 elseif key == keys.left and selection > 1 then\
5205 -- Move left\
5206 selection = selection - 1\
5207 if selection < 1 then\
5208 selection = #mChoices\
5209 end\
5210 \
5211 elseif key == keys.enter then\
5212 -- Select an option\
5213 if mChoices[selection]==\"Save\" then \
5214 if bReadOnly then \
5215 fMessage = \"Access Denied\"\
5216 return false\
5217 end\
5218 local success = save(sPath)\
5219 if success then\
5220 fMessage = \"Saved to \"..sPath\
5221 else\
5222 fMessage = \"Error saving to \"..sPath\
5223 end\
5224 return false\
5225 elseif mChoices[selection]==\"Exit\" then \
5226 return true\
5227 end\
5228 elseif key == keys.leftCtrl or keys == keys.rightCtrl then\
5229 -- Cancel the menu\
5230 return false \
5231 end\
5232 end\
5233 end\
5234end\
5235\
5236--[[ \
5237 Runs the main thread of execution. Draws the canvas and interface, and handles\
5238 mouse and key events.\
5239 returns: nil\
5240]]\
5241local function handleEvents()\
5242 local programActive = true\
5243 while programActive do\
5244 local id,p1,p2,p3 = os.pullEvent()\
5245 if id==\"mouse_click\" or id==\"mouse_drag\" then\
5246 if p2 >= w-1 and p3 >= 1 and p3 <= 17 then\
5247 if id ~= \"mouse_drag\" then\
5248 -- Selecting an items in the colour picker\
5249 if p3 <= 16 then\
5250 if p1==1 then\
5251 leftColour = 2^(p3-1)\
5252 else\
5253 rightColour = 2^(p3-1)\
5254 end\
5255 else\
5256 if p1==1 then\
5257 leftColour = nil\
5258 else\
5259 rightColour = nil\
5260 end\
5261 end\
5262 --drawCanvas()\
5263 drawInterface()\
5264 end\
5265 elseif p2 < w-1 and p3 <= h-1 then\
5266 -- Clicking on the canvas\
5267 local paintColour = nil\
5268 if p1==1 then\
5269 paintColour = leftColour\
5270 elseif p1==2 then\
5271 paintColour = rightColour\
5272 end\
5273 if not canvas[p3] then\
5274 canvas[p3] = {}\
5275 end\
5276 canvas[p3][p2] = paintColour\
5277\
5278 drawCanvasPixel( p2, p3 )\
5279 end\
5280 elseif id==\"key\" then\
5281 if p1==keys.leftCtrl or p1==keys.rightCtrl then\
5282 programActive = not accessMenu()\
5283 drawInterface()\
5284 end\
5285 elseif id==\"term_resize\" then\
5286 w,h = term.getSize()\
5287 drawCanvas()\
5288 drawInterface()\
5289 end\
5290 end\
5291end\
5292\
5293-- Init\
5294load(sPath)\
5295drawCanvas()\
5296drawInterface()\
5297\
5298-- Main loop\
5299handleEvents()\
5300\
5301-- Shutdown\
5302term.setBackgroundColour(colours.black)\
5303term.setTextColour(colours.white)\
5304term.clear()\
5305term.setCursorPos(1,1)\
5306",
5307 redirection = "--CCRedirection by : RamiLego4Game and Dan200--\
5308--Based on Redirection by Dan200: http://www.redirectiongame.com--\
5309--Clearing Screen--\
5310\
5311--Vars--\
5312local TermW,TermH = term.getSize()\
5313\
5314local sLevelTitle\
5315local tScreen\
5316local oScreen\
5317local SizeW,SizeH\
5318local aExits\
5319local fExit\
5320local nSpeed\
5321local Speed\
5322local fSpeed\
5323local fSpeedS\
5324local bPaused\
5325local Tick\
5326local Blocks\
5327local XOrgin,YOrgin\
5328\
5329local function reset()\
5330 sLevelTitle = \"\"\
5331 tScreen = {}\
5332 oScreen = {}\
5333 SizeW,SizeH = TermW,TermH\
5334 aExits = 0\
5335 fExit = \"nop\"\
5336 nSpeed = 0.6\
5337 Speed = nSpeed\
5338 fSpeed = 0.2\
5339 fSpeedS = false\
5340 bPaused = false\
5341 Tick = os.startTimer(Speed)\
5342 Blocks = 0\
5343 XOrgin,YOrgin = 1,1\
5344\
5345 term.setBackgroundColor(colors.black)\
5346 term.setTextColor(colors.white)\
5347 term.clear()\
5348end\
5349\
5350local InterFace = {}\
5351InterFace.cExit = colors.red\
5352InterFace.cSpeedD = colors.white\
5353InterFace.cSpeedA = colors.red\
5354InterFace.cTitle = colors.red\
5355\
5356local cG = colors.lightGray\
5357local cW = colors.gray\
5358local cS = colors.black\
5359local cR1 = colors.blue\
5360local cR2 = colors.red\
5361local cR3 = colors.green\
5362local cR4 = colors.yellow\
5363\
5364local tArgs = { ... }\
5365\
5366--Functions--\
5367local function printCentred( yc, stg )\
5368 local xc = math.floor((TermW - string.len(stg)) / 2) + 1\
5369 term.setCursorPos(xc,yc)\
5370 term.write( stg )\
5371end\
5372\
5373local function centerOrgin()\
5374 XOrgin = math.floor((TermW/2)-(SizeW/2))\
5375 YOrgin = math.floor((TermH/2)-(SizeH/2))\
5376end\
5377\
5378local function reMap()\
5379 tScreen = nil\
5380 tScreen = {}\
5381 for x=1,SizeW do\
5382 tScreen[x] = {}\
5383 for y=1,SizeH do\
5384 tScreen[x][y] = { space = true, wall = false, ground = false, robot = \"zz\", start = \"zz\", exit = \"zz\" }\
5385 end\
5386 end\
5387end\
5388\
5389local function tablecopy(t)\
5390 local t2 = {}\
5391 for k,v in pairs(t) do\
5392 t2[k] = v\
5393 end\
5394 return t2\
5395end\
5396\
5397local function buMap()\
5398 oScreen = nil\
5399 oScreen = {}\
5400 for x=1,SizeW do\
5401 oScreen[x] = {}\
5402 for y=1,SizeH do\
5403 oScreen[x][y] = tablecopy(tScreen[x][y])\
5404 end\
5405 end\
5406end\
5407\
5408local function addRobot(x,y,side,color)\
5409 local obj = tScreen[x][y]\
5410 local data = side..color\
5411 if obj.wall == nil and obj.robot == nil then\
5412 tScreen[x][y].robot = data\
5413 else\
5414 obj.wall = nil\
5415 obj.robot = \"zz\"\
5416 tScreen[x][y].robot = data\
5417 end\
5418end\
5419\
5420local function addStart(x,y,side,color)\
5421 local obj = tScreen[x][y]\
5422 local data = side..color\
5423 if obj.wall == nil and obj.space == nil then\
5424 tScreen[x][y].start = data\
5425 else\
5426 obj.wall = nil\
5427 obj.space = nil\
5428 tScreen[x][y].start = data\
5429 end\
5430 aExits = aExits+1\
5431end\
5432\
5433local function addGround(x,y)\
5434 local obj = tScreen[x][y]\
5435 if obj.space == nil and obj.exit == nil and obj.wall == nil and obj.robot == nil and obj.start == nil then\
5436 tScreen[x][y].ground = true\
5437 else\
5438 obj.space = nil\
5439 obj.exit = \"zz\"\
5440 obj.wall = nil\
5441 obj.robot = \"zz\"\
5442 obj.start = \"zz\"\
5443 tScreen[x][y].ground = true\
5444 end\
5445end\
5446\
5447local function addExit(x,y,cl)\
5448 local obj = tScreen[x][y]\
5449 if obj.space == nil and obj.ground == nil and obj.wall == nil and obj.robot == nil and obj.start == nil then\
5450 tScreen[x][y].exit = cl\
5451 else\
5452 obj.space = nil\
5453 obj.ground = nil\
5454 obj.wall = nil\
5455 obj.robot = \"zz\"\
5456 obj.start = \"zz\"\
5457 tScreen[x][y].exit = cl\
5458 end\
5459end\
5460\
5461local function addWall(x,y)\
5462 local obj = tScreen[x][y]\
5463 if obj == nil then\
5464 return error(\"Here X\"..x..\" Y\"..y)\
5465 end\
5466 if obj.space == nil and obj.exit == nil and obj.ground == nil and obj.robot == nil and obj.start == nil then\
5467 tScreen[x][y].wall = true\
5468 else\
5469 obj.space = nil\
5470 obj.exit = nil\
5471 obj.ground = nil\
5472 obj.robot = nil\
5473 obj.start = nil\
5474 tScreen[x][y].wall = true\
5475 end\
5476end\
5477\
5478local function loadLevel(nNum)\
5479 sLevelTitle = \"Level \"..nNum\
5480 if nNum == nil then return error(\"nNum == nil\") end\
5481 local sDir = fs.getDir( shell.getRunningProgram() )\
5482 local sLevelD = sDir .. \"/levels/\" .. tostring(nNum)\
5483 if not ( fs.exists(sLevelD) or fs.isDir(sLevelD) ) then return error(\"Level Not Exists : \"..sLevelD) end\
5484 fLevel = fs.open(sLevelD,\"r\")\
5485 local Line = 0\
5486 local wl = true\
5487 Blocks = tonumber(string.sub(fLevel.readLine(),1,1))\
5488 local xSize = string.len(fLevel.readLine())+2\
5489 local Lines = 3\
5490 while wl do\
5491 local wLine = fLevel.readLine()\
5492 if wLine == nil then\
5493 fLevel.close()\
5494 wl = false\
5495 else\
5496 xSize = math.max(string.len(wLine)+2,xSize)\
5497 Lines = Lines + 1\
5498 end\
5499 end\
5500 SizeW,SizeH = xSize,Lines\
5501 reMap()\
5502 fLevel = fs.open(sLevelD,\"r\")\
5503 fLevel.readLine()\
5504 for Line=2,Lines-1 do\
5505 sLine = fLevel.readLine()\
5506 local chars = string.len(sLine)\
5507 for char = 1, chars do\
5508 local el = string.sub(sLine,char,char)\
5509 if el == \"8\" then\
5510 addGround(char+1,Line)\
5511 elseif el == \"0\" then\
5512 addStart(char+1,Line,\"a\",\"a\")\
5513 elseif el == \"1\" then\
5514 addStart(char+1,Line,\"b\",\"a\")\
5515 elseif el == \"2\" then\
5516 addStart(char+1,Line,\"c\",\"a\")\
5517 elseif el == \"3\" then\
5518 addStart(char+1,Line,\"d\",\"a\")\
5519 elseif el == \"4\" then\
5520 addStart(char+1,Line,\"a\",\"b\")\
5521 elseif el == \"5\" then\
5522 addStart(char+1,Line,\"b\",\"b\")\
5523 elseif el == \"6\" then\
5524 addStart(char+1,Line,\"c\",\"b\")\
5525 elseif el == \"9\" then\
5526 addStart(char+1,Line,\"d\",\"b\")\
5527 elseif el == \"b\" then\
5528 addExit(char+1,Line,\"a\")\
5529 elseif el == \"e\" then\
5530 addExit(char+1,Line,\"b\")\
5531 elseif el == \"7\" then\
5532 addWall(char+1,Line)\
5533 end\
5534 end\
5535 end\
5536 fLevel.close()\
5537end\
5538\
5539local function drawStars()\
5540 --CCR Background By : RamiLego--\
5541 local cStar,cStarG,crStar,crStarB = colors.lightGray,colors.gray,\".\",\"*\"\
5542 local DStar,BStar,nStar,gStar = 14,10,16,3\
5543 local TermW,TermH = term.getSize()\
5544\
5545 term.clear()\
5546 term.setCursorPos(1,1)\
5547 for x=1,TermW do\
5548 for y=1,TermH do\
5549 local StarT = math.random(1,30)\
5550 if StarT == DStar then\
5551 term.setCursorPos(x,y)\
5552 term.setTextColor(cStar)\
5553 write(crStar)\
5554 elseif StarT == BStar then\
5555 term.setCursorPos(x,y)\
5556 term.setTextColor(cStar)\
5557 write(crStarB)\
5558 elseif StarT == nStar then\
5559 term.setCursorPos(x,y)\
5560 term.setTextColor(cStarG)\
5561 write(crStar)\
5562 elseif StarT == gStar then\
5563 term.setCursorPos(x,y)\
5564 term.setTextColor(cStarG)\
5565 write(crStarB)\
5566 end\
5567 end\
5568 end\
5569end\
5570\
5571local function drawMap()\
5572 for x=1,SizeW do\
5573 for y=1,SizeH do\
5574 \
5575 local obj = tScreen[x][y]\
5576 if obj.ground == true then\
5577 paintutils.drawPixel(XOrgin+x,YOrgin+y+1,cG)\
5578 end\
5579 if obj.wall == true then\
5580 paintutils.drawPixel(XOrgin+x,YOrgin+y+1,cW)\
5581 end\
5582 \
5583 local ex = tostring(tScreen[x][y].exit)\
5584 if not(ex == \"zz\" or ex == \"nil\") then\
5585 if ex == \"a\" then\
5586 ex = cR1\
5587 elseif ex == \"b\" then\
5588 ex = cR2\
5589 elseif ex == \"c\" then\
5590 ex = cR3\
5591 elseif ex == \"d\" then\
5592 ex = cR4\
5593 else\
5594 return error(\"Exit Color Out\")\
5595 end\
5596 term.setBackgroundColor(cG)\
5597 term.setTextColor(ex)\
5598 term.setCursorPos(XOrgin+x,YOrgin+y+1)\
5599 print(\"X\")\
5600 end\
5601 \
5602 local st = tostring(tScreen[x][y].start)\
5603 if not(st == \"zz\" or st == \"nil\") then\
5604 local Cr = string.sub(st,2,2)\
5605 if Cr == \"a\" then\
5606 Cr = cR1\
5607 elseif Cr == \"b\" then\
5608 Cr = cR2\
5609 elseif Cr == \"c\" then\
5610 Cr = cR3\
5611 elseif Cr == \"d\" then\
5612 Cr = cR4\
5613 else\
5614 return error(\"Start Color Out\")\
5615 end\
5616 \
5617 term.setTextColor(Cr)\
5618 term.setBackgroundColor(cG)\
5619 term.setCursorPos(XOrgin+x,YOrgin+y+1)\
5620 \
5621 sSide = string.sub(st,1,1)\
5622 if sSide == \"a\" then\
5623 print(\"^\")\
5624 elseif sSide == \"b\" then\
5625 print(\">\")\
5626 elseif sSide == \"c\" then\
5627 print(\"v\")\
5628 elseif sSide == \"d\" then\
5629 print(\"<\")\
5630 else\
5631 print(\"@\")\
5632 end\
5633 end\
5634 \
5635 if obj.space == true then\
5636 paintutils.drawPixel(XOrgin+x,YOrgin+y+1,cS)\
5637 end\
5638 \
5639 local rb = tostring(tScreen[x][y].robot)\
5640 if not(rb == \"zz\" or rb == \"nil\") then\
5641 local Cr = string.sub(rb,2,2)\
5642 if Cr == \"a\" then\
5643 Cr = cR1\
5644 elseif Cr == \"b\" then\
5645 Cr = cR2\
5646 elseif Cr == \"c\" then\
5647 Cr = cR3\
5648 elseif Cr == \"d\" then\
5649 Cr = cR4\
5650 else\
5651 Cr = colors.white\
5652 end\
5653 term.setBackgroundColor(Cr)\
5654 term.setTextColor(colors.white)\
5655 term.setCursorPos(XOrgin+x,YOrgin+y+1)\
5656 sSide = string.sub(rb,1,1)\
5657 if sSide == \"a\" then\
5658 print(\"^\")\
5659 elseif sSide == \"b\" then\
5660 print(\">\")\
5661 elseif sSide == \"c\" then\
5662 print(\"v\")\
5663 elseif sSide == \"d\" then\
5664 print(\"<\")\
5665 else\
5666 print(\"@\")\
5667 end\
5668 end\
5669 end\
5670 end\
5671end\
5672\
5673local function isBrick(x,y)\
5674 local brb = tostring(tScreen[x][y].robot)\
5675 local bobj = oScreen[x][y]\
5676 if (brb == \"zz\" or brb == \"nil\") and not bobj.wall == true then\
5677 return false\
5678 else\
5679 return true\
5680 end\
5681end\
5682\
5683local function gRender(sContext)\
5684 if sContext == \"start\" then\
5685 for x=1,SizeW do\
5686 for y=1,SizeH do\
5687 local st = tostring(tScreen[x][y].start)\
5688 if not(st == \"zz\" or st == \"nil\") then\
5689 local Cr = string.sub(st,2,2)\
5690 local sSide = string.sub(st,1,1)\
5691 addRobot(x,y,sSide,Cr)\
5692 end\
5693 end\
5694 end\
5695 elseif sContext == \"tick\" then\
5696 buMap()\
5697 for x=1,SizeW do\
5698 for y=1,SizeH do\
5699 local rb = tostring(oScreen[x][y].robot)\
5700 if not(rb == \"zz\" or rb == \"nil\") then\
5701 local Cr = string.sub(rb,2,2)\
5702 local sSide = string.sub(rb,1,1)\
5703 local sobj = oScreen[x][y]\
5704 if sobj.space == true then\
5705 tScreen[x][y].robot = \"zz\"\
5706 if not sSide == \"g\" then\
5707 addRobot(x,y,\"g\",Cr)\
5708 end\
5709 elseif sobj.exit == Cr then\
5710 if sSide == \"a\" or sSide == \"b\" or sSide == \"c\" or sSide == \"d\" then\
5711 tScreen[x][y].robot = \"zz\"\
5712 addRobot(x,y,\"g\",Cr)\
5713 aExits = aExits-1\
5714 end\
5715 elseif sSide == \"a\" then\
5716 local obj = isBrick(x,y-1)\
5717 tScreen[x][y].robot = \"zz\"\
5718 if not obj == true then\
5719 addRobot(x,y-1,sSide,Cr)\
5720 else\
5721 local obj2 = isBrick(x-1,y)\
5722 local obj3 = isBrick(x+1,y)\
5723 if not obj2 == true and not obj3 == true then\
5724 if Cr == \"a\" then\
5725 addRobot(x,y,\"d\",Cr)\
5726 elseif Cr == \"b\" then\
5727 addRobot(x,y,\"b\",Cr)\
5728 end\
5729 elseif obj == true and obj2 == true and obj3 == true then\
5730 addRobot(x,y,\"c\",Cr)\
5731 else\
5732 if obj3 == true then\
5733 addRobot(x,y,\"d\",Cr)\
5734 elseif obj2 == true then\
5735 addRobot(x,y,\"b\",Cr)\
5736 end\
5737 end\
5738 end\
5739 elseif sSide == \"b\" then\
5740 local obj = isBrick(x+1,y)\
5741 tScreen[x][y].robot = \"zz\"\
5742 if not obj == true then\
5743 addRobot(x+1,y,sSide,Cr)\
5744 else\
5745 local obj2 = isBrick(x,y-1)\
5746 local obj3 = isBrick(x,y+1)\
5747 if not obj2 == true and not obj3 == true then\
5748 if Cr == \"a\" then\
5749 addRobot(x,y,\"a\",Cr)\
5750 elseif Cr == \"b\" then\
5751 addRobot(x,y,\"c\",Cr)\
5752 end\
5753 elseif obj == true and obj2 == true and obj3 == true then\
5754 addRobot(x,y,\"d\",Cr)\
5755 else\
5756 if obj3 == true then\
5757 addRobot(x,y,\"a\",Cr)\
5758 elseif obj2 == true then\
5759 addRobot(x,y,\"c\",Cr)\
5760 end\
5761 end\
5762 end\
5763 elseif sSide == \"c\" then\
5764 local obj = isBrick(x,y+1)\
5765 tScreen[x][y].robot = \"zz\"\
5766 if not obj == true then\
5767 addRobot(x,y+1,sSide,Cr)\
5768 else\
5769 local obj2 = isBrick(x-1,y)\
5770 local obj3 = isBrick(x+1,y)\
5771 if not obj2 == true and not obj3 == true then\
5772 if Cr == \"a\" then\
5773 addRobot(x,y,\"b\",Cr)\
5774 elseif Cr == \"b\" then\
5775 addRobot(x,y,\"d\",Cr)\
5776 end\
5777 elseif obj == true and obj2 == true and obj3 == true then\
5778 addRobot(x,y,\"a\",Cr)\
5779 else\
5780 if obj3 == true then\
5781 addRobot(x,y,\"d\",Cr)\
5782 elseif obj2 == true then\
5783 addRobot(x,y,\"b\",Cr)\
5784 end\
5785 end\
5786 end\
5787 elseif sSide == \"d\" then\
5788 local obj = isBrick(x-1,y)\
5789 tScreen[x][y].robot = \"zz\"\
5790 if not obj == true then\
5791 addRobot(x-1,y,sSide,Cr)\
5792 else\
5793 local obj2 = isBrick(x,y-1)\
5794 local obj3 = isBrick(x,y+1)\
5795 if not obj2 == true and not obj3 == true then\
5796 if Cr == \"a\" then\
5797 addRobot(x,y,\"c\",Cr)\
5798 elseif Cr == \"b\" then\
5799 addRobot(x,y,\"a\",Cr)\
5800 end\
5801 elseif obj == true and obj2 == true and obj3 == true then\
5802 addRobot(x,y,\"b\",Cr)\
5803 else\
5804 if obj3 == true then\
5805 addRobot(x,y,\"a\",Cr)\
5806 elseif obj2 == true then\
5807 addRobot(x,y,\"c\",Cr)\
5808 end\
5809 end\
5810 end\
5811 else\
5812 addRobot(x,y,sSide,\"g\")\
5813 end\
5814 end\
5815 end\
5816 end\
5817 end\
5818end\
5819\
5820function InterFace.drawBar()\
5821 term.setBackgroundColor( colors.black )\
5822 term.setTextColor( InterFace.cTitle )\
5823 printCentred( 1, \" \"..sLevelTitle..\" \" )\
5824 \
5825 term.setCursorPos(1,1)\
5826 term.setBackgroundColor( cW )\
5827 write( \" \" )\
5828 term.setBackgroundColor( colors.black )\
5829 write( \" x \"..tostring(Blocks)..\" \" )\
5830 \
5831 term.setCursorPos( TermW-8,TermH )\
5832 term.setBackgroundColor( colors.black )\
5833 term.setTextColour(InterFace.cSpeedD)\
5834 write(\" <<\" )\
5835 if bPaused then\
5836 term.setTextColour(InterFace.cSpeedA)\
5837 else\
5838 term.setTextColour(InterFace.cSpeedD)\
5839 end\
5840 write(\" ||\")\
5841 if fSpeedS then\
5842 term.setTextColour(InterFace.cSpeedA)\
5843 else\
5844 term.setTextColour(InterFace.cSpeedD)\
5845 end\
5846 write(\" >>\")\
5847\
5848 term.setCursorPos( TermW-1, 1 )\
5849 term.setBackgroundColor( colors.black )\
5850 term.setTextColour( InterFace.cExit )\
5851 write(\" X\")\
5852 term.setBackgroundColor(colors.black)\
5853end\
5854\
5855function InterFace.render()\
5856 local id,p1,p2,p3 = os.pullEvent()\
5857 if id == \"mouse_click\" then\
5858 if p3 == 1 and p2 == TermW then\
5859 return \"end\"\
5860 elseif p3 == TermH and p2 >= TermW-7 and p2 <= TermW-6 then\
5861 return \"retry\"\
5862 elseif p3 == TermH and p2 >= TermW-4 and p2 <= TermW-3 then\
5863 bPaused = not bPaused\
5864 fSpeedS = false\
5865 Speed = (bPaused and 0) or nSpeed\
5866 if Speed > 0 then\
5867 Tick = os.startTimer(Speed)\
5868 else\
5869 Tick = nil\
5870 end\
5871 InterFace.drawBar()\
5872 elseif p3 == TermH and p2 >= TermW-1 then\
5873 bPaused = false\
5874 fSpeedS = not fSpeedS\
5875 Speed = (fSpeedS and fSpeed) or nSpeed\
5876 Tick = os.startTimer(Speed)\
5877 InterFace.drawBar()\
5878 elseif p3-1 < YOrgin+SizeH+1 and p3-1 > YOrgin and\
5879 p2 < XOrgin+SizeW+1 and p2 > XOrgin then\
5880 local eobj = tScreen[p2-XOrgin][p3-YOrgin-1]\
5881 local erobj = tostring(tScreen[p2-XOrgin][p3-YOrgin-1].robot)\
5882 if (erobj == \"zz\" or erobj == \"nil\") and not eobj.wall == true and not eobj.space == true and Blocks > 0 then\
5883 addWall(p2-XOrgin,p3-YOrgin-1)\
5884 Blocks = Blocks-1\
5885 InterFace.drawBar()\
5886 drawMap()\
5887 end\
5888 end\
5889 elseif id == \"timer\" and p1 == Tick then\
5890 gRender(\"tick\")\
5891 drawMap()\
5892 if Speed > 0 then\
5893 Tick = os.startTimer(Speed)\
5894 else\
5895 Tick = nil\
5896 end\
5897 end\
5898end\
5899\
5900local function startG(LevelN)\
5901 drawStars()\
5902 loadLevel(LevelN)\
5903 centerOrgin()\
5904 local create = true\
5905 drawMap()\
5906 InterFace.drawBar()\
5907 gRender(\"start\")\
5908 drawMap()\
5909 \
5910 local NExit = true\
5911 if aExits == 0 then\
5912 NExit = false\
5913 end\
5914 \
5915 while true do\
5916 local isExit = InterFace.render()\
5917 if isExit == \"end\" then\
5918 return nil\
5919 elseif isExit == \"retry\" then\
5920 return LevelN\
5921 elseif fExit == \"yes\" then\
5922 if fs.exists( fs.getDir( shell.getRunningProgram() ) .. \"/levels/\" .. tostring(LevelN + 1) ) then\
5923 return LevelN + 1\
5924 else\
5925 return nil\
5926 end\
5927 end\
5928 if aExits == 0 and NExit == true then\
5929 fExit = \"yes\"\
5930 end\
5931 end\
5932end\
5933\
5934local ok, err = true, nil\
5935\
5936--Menu--\
5937local sStartLevel = tArgs[1]\
5938if ok and not sStartLevel then\
5939 ok, err = pcall( function()\
5940 term.setTextColor(colors.white)\
5941 term.setBackgroundColor( colors.black )\
5942 term.clear()\
5943 drawStars()\
5944 term.setTextColor( colors.red )\
5945 printCentred( TermH/2 - 1, \" REDIRECTION \" )\
5946 printCentred( TermH/2 - 0, \" ComputerCraft Edition \" )\
5947 term.setTextColor( colors.yellow )\
5948 printCentred( TermH/2 + 2, \" Click to Begin \" )\
5949 os.pullEvent( \"mouse_click\" )\
5950 end )\
5951end\
5952\
5953--Game--\
5954if ok then\
5955 ok,err = pcall( function()\
5956 local nLevel\
5957 if sStartLevel then\
5958 nLevel = tonumber( sStartLevel )\
5959 else\
5960 nLevel = 1\
5961 end\
5962 while nLevel do\
5963 reset()\
5964 nLevel = startG(nLevel)\
5965 end\
5966 end )\
5967end\
5968\
5969--Upsell screen--\
5970if ok then\
5971 ok, err = pcall( function()\
5972 term.setTextColor(colors.white)\
5973 term.setBackgroundColor( colors.black )\
5974 term.clear()\
5975 drawStars()\
5976 term.setTextColor( colors.red )\
5977 if TermW >= 40 then\
5978 printCentred( TermH/2 - 1, \" Thank you for playing Redirection \" )\
5979 printCentred( TermH/2 - 0, \" ComputerCraft Edition \" )\
5980 printCentred( TermH/2 + 2, \" Check out the full game: \" )\
5981 term.setTextColor( colors.yellow )\
5982 printCentred( TermH/2 + 3, \" http://www.redirectiongame.com \" )\
5983 else\
5984 printCentred( TermH/2 - 2, \" Thank you for \" )\
5985 printCentred( TermH/2 - 1, \" playing Redirection \" )\
5986 printCentred( TermH/2 - 0, \" ComputerCraft Edition \" )\
5987 printCentred( TermH/2 + 2, \" Check out the full game: \" )\
5988 term.setTextColor( colors.yellow )\
5989 printCentred( TermH/2 + 3, \" www.redirectiongame.com \" )\
5990 end\
5991 parallel.waitForAll(\
5992 function() sleep(2) end,\
5993 function() os.pullEvent( \"mouse_click\" ) end\
5994 )\
5995 end )\
5996end\
5997\
5998--Clear and exit--\
5999term.setCursorPos(1,1)\
6000term.setTextColor(colors.white)\
6001term.setBackgroundColor(colors.black)\
6002term.clear()\
6003if not ok then\
6004 if err == \"Terminated\" then\
6005 print( \"Check out the full version of Redirection:\" )\
6006 print( \"http://www.redirectiongame.com\" )\
6007 else\
6008 printError( err )\
6009 end\
6010end\
6011",
6012 },
6013 },
6014 time = "local nTime = os.time()\
6015local nDay = os.day()\
6016print( \"The time is \"..textutils.formatTime( nTime, false )..\" on Day \"..nDay )\
6017",
6018 turtle = {
6019 refuel = "\
6020local tArgs = { ... }\
6021local nLimit = 1\
6022if #tArgs > 1 then\
6023 print( \"Usage: refuel [number]\" )\
6024 return\
6025elseif #tArgs > 0 then\
6026 if tArgs[1] == \"all\" then\
6027 nLimit = 64 * 16\
6028 else\
6029 nLimit = tonumber( tArgs[1] )\
6030 end\
6031end\
6032\
6033if turtle.getFuelLevel() ~= \"unlimited\" then\
6034 for n=1,16 do\
6035 local nCount = turtle.getItemCount(n)\
6036 if nLimit > 0 and nCount > 0 and turtle.getFuelLevel() < turtle.getFuelLimit() then\
6037 local nBurn = math.min( nLimit, nCount )\
6038 turtle.select( n )\
6039 if turtle.refuel( nBurn ) then\
6040 local nNewCount = turtle.getItemCount(n)\
6041 nLimit = nLimit - (nCount - nNewCount)\
6042 end\
6043 end\
6044 end\
6045 print( \"Fuel level is \"..turtle.getFuelLevel() )\
6046 if turtle.getFuelLevel() == turtle.getFuelLimit() then\
6047 print( \"Fuel limit reached\" )\
6048 end\
6049else\
6050 print( \"Fuel level is unlimited\" )\
6051end\
6052",
6053 craft = "\
6054if not turtle.craft then\
6055 print( \"Requires a Crafty Turtle\" )\
6056 return\
6057end\
6058\
6059local tArgs = { ... }\
6060local nLimit = nil\
6061if #tArgs < 1 then\
6062 print( \"Usage: craft [number]\" )\
6063 return\
6064else\
6065 nLimit = tonumber( tArgs[1] )\
6066end\
6067\
6068local nCrafted = 0\
6069local nOldCount = turtle.getItemCount( turtle.getSelectedSlot() )\
6070if turtle.craft( nLimit ) then\
6071 local nNewCount = turtle.getItemCount( turtle.getSelectedSlot() )\
6072 if nOldCount <= nLimit then\
6073 nCrafted = nNewCount\
6074 else\
6075 nCrafted = nOldCount - nNewCount\
6076 end\
6077end\
6078\
6079if nCrafted > 1 then\
6080 print( nCrafted..\" items crafted\" )\
6081elseif nCrafted == 1 then\
6082 print( \"1 item crafted\" )\
6083else\
6084 print( \"No items crafted\" )\
6085end\
6086",
6087 unequip = "\
6088local tArgs = { ... }\
6089local function printUsage()\
6090 print( \"Usage: unequip <side>\" )\
6091end\
6092\
6093if #tArgs ~= 1 then\
6094 printUsage()\
6095 return\
6096end\
6097\
6098local function unequip( fnEquipFunction )\
6099 for nSlot=1,16 do\
6100 local nOldCount = turtle.getItemCount( nSlot )\
6101 if nOldCount == 0 then\
6102 turtle.select( nSlot )\
6103 if fnEquipFunction() then\
6104 local nNewCount = turtle.getItemCount( nSlot )\
6105 if nNewCount > 0 then\
6106 print( \"Item unequipped\" )\
6107 return\
6108 else\
6109 print( \"Nothing to unequip\" )\
6110 return\
6111 end\
6112 end\
6113 end\
6114 end\
6115 print( \"No space to unequip item\" )\
6116end\
6117\
6118local sSide = tArgs[1]\
6119if sSide == \"left\" then\
6120 unequip( turtle.equipLeft )\
6121elseif sSide == \"right\" then\
6122 unequip( turtle.equipRight )\
6123else\
6124 printUsage()\
6125 return\
6126end\
6127",
6128 excavate = "\
6129local tArgs = { ... }\
6130if #tArgs ~= 1 then\
6131 print( \"Usage: excavate <diameter>\" )\
6132 return\
6133end\
6134\
6135-- Mine in a quarry pattern until we hit something we can't dig\
6136local size = tonumber( tArgs[1] )\
6137if size < 1 then\
6138 print( \"Excavate diameter must be positive\" )\
6139 return\
6140end\
6141 \
6142local depth = 0\
6143local unloaded = 0\
6144local collected = 0\
6145\
6146local xPos,zPos = 0,0\
6147local xDir,zDir = 0,1\
6148\
6149local goTo -- Filled in further down\
6150local refuel -- Filled in further down\
6151 \
6152local function unload( _bKeepOneFuelStack )\
6153 print( \"Unloading items...\" )\
6154 for n=1,16 do\
6155 local nCount = turtle.getItemCount(n)\
6156 if nCount > 0 then\
6157 turtle.select(n) \
6158 local bDrop = true\
6159 if _bKeepOneFuelStack and turtle.refuel(0) then\
6160 bDrop = false\
6161 _bKeepOneFuelStack = false\
6162 end \
6163 if bDrop then\
6164 turtle.drop()\
6165 unloaded = unloaded + nCount\
6166 end\
6167 end\
6168 end\
6169 collected = 0\
6170 turtle.select(1)\
6171end\
6172\
6173local function returnSupplies()\
6174 local x,y,z,xd,zd = xPos,depth,zPos,xDir,zDir\
6175 print( \"Returning to surface...\" )\
6176 goTo( 0,0,0,0,-1 )\
6177 \
6178 local fuelNeeded = 2*(x+y+z) + 1\
6179 if not refuel( fuelNeeded ) then\
6180 unload( true )\
6181 print( \"Waiting for fuel\" )\
6182 while not refuel( fuelNeeded ) do\
6183 os.pullEvent( \"turtle_inventory\" )\
6184 end\
6185 else\
6186 unload( true ) \
6187 end\
6188 \
6189 print( \"Resuming mining...\" )\
6190 goTo( x,y,z,xd,zd )\
6191end\
6192\
6193local function collect() \
6194 local bFull = true\
6195 local nTotalItems = 0\
6196 for n=1,16 do\
6197 local nCount = turtle.getItemCount(n)\
6198 if nCount == 0 then\
6199 bFull = false\
6200 end\
6201 nTotalItems = nTotalItems + nCount\
6202 end\
6203 \
6204 if nTotalItems > collected then\
6205 collected = nTotalItems\
6206 if math.fmod(collected + unloaded, 50) == 0 then\
6207 print( \"Mined \"..(collected + unloaded)..\" items.\" )\
6208 end\
6209 end\
6210 \
6211 if bFull then\
6212 print( \"No empty slots left.\" )\
6213 return false\
6214 end\
6215 return true\
6216end\
6217\
6218function refuel( ammount )\
6219 local fuelLevel = turtle.getFuelLevel()\
6220 if fuelLevel == \"unlimited\" then\
6221 return true\
6222 end\
6223 \
6224 local needed = ammount or (xPos + zPos + depth + 2)\
6225 if turtle.getFuelLevel() < needed then\
6226 local fueled = false\
6227 for n=1,16 do\
6228 if turtle.getItemCount(n) > 0 then\
6229 turtle.select(n)\
6230 if turtle.refuel(1) then\
6231 while turtle.getItemCount(n) > 0 and turtle.getFuelLevel() < needed do\
6232 turtle.refuel(1)\
6233 end\
6234 if turtle.getFuelLevel() >= needed then\
6235 turtle.select(1)\
6236 return true\
6237 end\
6238 end\
6239 end\
6240 end\
6241 turtle.select(1)\
6242 return false\
6243 end\
6244 \
6245 return true\
6246end\
6247\
6248local function tryForwards()\
6249 if not refuel() then\
6250 print( \"Not enough Fuel\" )\
6251 returnSupplies()\
6252 end\
6253 \
6254 while not turtle.forward() do\
6255 if turtle.detect() then\
6256 if turtle.dig() then\
6257 if not collect() then\
6258 returnSupplies()\
6259 end\
6260 else\
6261 return false\
6262 end\
6263 elseif turtle.attack() then\
6264 if not collect() then\
6265 returnSupplies()\
6266 end\
6267 else\
6268 sleep( 0.5 )\
6269 end\
6270 end\
6271 \
6272 xPos = xPos + xDir\
6273 zPos = zPos + zDir\
6274 return true\
6275end\
6276\
6277local function tryDown()\
6278 if not refuel() then\
6279 print( \"Not enough Fuel\" )\
6280 returnSupplies()\
6281 end\
6282 \
6283 while not turtle.down() do\
6284 if turtle.detectDown() then\
6285 if turtle.digDown() then\
6286 if not collect() then\
6287 returnSupplies()\
6288 end\
6289 else\
6290 return false\
6291 end\
6292 elseif turtle.attackDown() then\
6293 if not collect() then\
6294 returnSupplies()\
6295 end\
6296 else\
6297 sleep( 0.5 )\
6298 end\
6299 end\
6300\
6301 depth = depth + 1\
6302 if math.fmod( depth, 10 ) == 0 then\
6303 print( \"Descended \"..depth..\" metres.\" )\
6304 end\
6305\
6306 return true\
6307end\
6308\
6309local function turnLeft()\
6310 turtle.turnLeft()\
6311 xDir, zDir = -zDir, xDir\
6312end\
6313\
6314local function turnRight()\
6315 turtle.turnRight()\
6316 xDir, zDir = zDir, -xDir\
6317end\
6318\
6319function goTo( x, y, z, xd, zd )\
6320 while depth > y do\
6321 if turtle.up() then\
6322 depth = depth - 1\
6323 elseif turtle.digUp() or turtle.attackUp() then\
6324 collect()\
6325 else\
6326 sleep( 0.5 )\
6327 end\
6328 end\
6329\
6330 if xPos > x then\
6331 while xDir ~= -1 do\
6332 turnLeft()\
6333 end\
6334 while xPos > x do\
6335 if turtle.forward() then\
6336 xPos = xPos - 1\
6337 elseif turtle.dig() or turtle.attack() then\
6338 collect()\
6339 else\
6340 sleep( 0.5 )\
6341 end\
6342 end\
6343 elseif xPos < x then\
6344 while xDir ~= 1 do\
6345 turnLeft()\
6346 end\
6347 while xPos < x do\
6348 if turtle.forward() then\
6349 xPos = xPos + 1\
6350 elseif turtle.dig() or turtle.attack() then\
6351 collect()\
6352 else\
6353 sleep( 0.5 )\
6354 end\
6355 end\
6356 end\
6357 \
6358 if zPos > z then\
6359 while zDir ~= -1 do\
6360 turnLeft()\
6361 end\
6362 while zPos > z do\
6363 if turtle.forward() then\
6364 zPos = zPos - 1\
6365 elseif turtle.dig() or turtle.attack() then\
6366 collect()\
6367 else\
6368 sleep( 0.5 )\
6369 end\
6370 end\
6371 elseif zPos < z then\
6372 while zDir ~= 1 do\
6373 turnLeft()\
6374 end\
6375 while zPos < z do\
6376 if turtle.forward() then\
6377 zPos = zPos + 1\
6378 elseif turtle.dig() or turtle.attack() then\
6379 collect()\
6380 else\
6381 sleep( 0.5 )\
6382 end\
6383 end \
6384 end\
6385 \
6386 while depth < y do\
6387 if turtle.down() then\
6388 depth = depth + 1\
6389 elseif turtle.digDown() or turtle.attackDown() then\
6390 collect()\
6391 else\
6392 sleep( 0.5 )\
6393 end\
6394 end\
6395 \
6396 while zDir ~= zd or xDir ~= xd do\
6397 turnLeft()\
6398 end\
6399end\
6400\
6401if not refuel() then\
6402 print( \"Out of Fuel\" )\
6403 return\
6404end\
6405\
6406print( \"Excavating...\" )\
6407\
6408local reseal = false\
6409turtle.select(1)\
6410if turtle.digDown() then\
6411 reseal = true\
6412end\
6413\
6414local alternate = 0\
6415local done = false\
6416while not done do\
6417 for n=1,size do\
6418 for m=1,size-1 do\
6419 if not tryForwards() then\
6420 done = true\
6421 break\
6422 end\
6423 end\
6424 if done then\
6425 break\
6426 end\
6427 if n<size then\
6428 if math.fmod(n + alternate,2) == 0 then\
6429 turnLeft()\
6430 if not tryForwards() then\
6431 done = true\
6432 break\
6433 end\
6434 turnLeft()\
6435 else\
6436 turnRight()\
6437 if not tryForwards() then\
6438 done = true\
6439 break\
6440 end\
6441 turnRight()\
6442 end\
6443 end\
6444 end\
6445 if done then\
6446 break\
6447 end\
6448 \
6449 if size > 1 then\
6450 if math.fmod(size,2) == 0 then\
6451 turnRight()\
6452 else\
6453 if alternate == 0 then\
6454 turnLeft()\
6455 else\
6456 turnRight()\
6457 end\
6458 alternate = 1 - alternate\
6459 end\
6460 end\
6461 \
6462 if not tryDown() then\
6463 done = true\
6464 break\
6465 end\
6466end\
6467\
6468print( \"Returning to surface...\" )\
6469\
6470-- Return to where we started\
6471goTo( 0,0,0,0,-1 )\
6472unload( false )\
6473goTo( 0,0,0,0,1 )\
6474\
6475-- Seal the hole\
6476if reseal then\
6477 turtle.placeDown()\
6478end\
6479\
6480print( \"Mined \"..(collected + unloaded)..\" items total.\" )\
6481",
6482 dance = "\
6483local tMoves = {\
6484 function()\
6485 turtle.up()\
6486 turtle.down()\
6487 end,\
6488 function()\
6489 turtle.up()\
6490 turtle.turnLeft()\
6491 turtle.turnLeft()\
6492 turtle.turnLeft()\
6493 turtle.turnLeft()\
6494 turtle.down()\
6495 end,\
6496 function()\
6497 turtle.up()\
6498 turtle.turnRight()\
6499 turtle.turnRight()\
6500 turtle.turnRight()\
6501 turtle.turnRight()\
6502 turtle.down()\
6503 end,\
6504 function()\
6505 turtle.turnLeft()\
6506 turtle.turnLeft()\
6507 turtle.turnLeft()\
6508 turtle.turnLeft()\
6509 end,\
6510 function()\
6511 turtle.turnRight()\
6512 turtle.turnRight()\
6513 turtle.turnRight()\
6514 turtle.turnRight()\
6515 end,\
6516 function()\
6517 turtle.turnLeft()\
6518 turtle.back()\
6519 turtle.back()\
6520 turtle.turnRight()\
6521 turtle.turnRight()\
6522 turtle.back()\
6523 turtle.back()\
6524 turtle.turnLeft()\
6525 end,\
6526 function()\
6527 turtle.turnRight()\
6528 turtle.back()\
6529 turtle.back()\
6530 turtle.turnLeft()\
6531 turtle.turnLeft()\
6532 turtle.back()\
6533 turtle.back()\
6534 turtle.turnRight()\
6535 end,\
6536 function()\
6537 turtle.back()\
6538 turtle.turnLeft()\
6539 turtle.back()\
6540 turtle.turnLeft()\
6541 turtle.back()\
6542 turtle.turnLeft()\
6543 turtle.back()\
6544 turtle.turnLeft()\
6545 end,\
6546 function()\
6547 turtle.back()\
6548 turtle.turnRight()\
6549 turtle.back()\
6550 turtle.turnRight()\
6551 turtle.back()\
6552 turtle.turnRight()\
6553 turtle.back()\
6554 turtle.turnRight()\
6555 end,\
6556}\
6557\
6558textutils.slowWrite( \"Preparing to get down.\" )\
6559textutils.slowPrint( \"..\", 0.75 )\
6560\
6561local sAudio = nil\
6562for n,sName in pairs( peripheral.getNames() ) do\
6563 if disk.hasAudio( sName ) then\
6564 disk.playAudio( sName )\
6565 print( \"Jamming to \"..disk.getAudioTitle( sName ) )\
6566 sAudio = sName\
6567 break\
6568 end\
6569end\
6570\
6571print( \"Press any key to stop the groove\" )\
6572\
6573local bEnd = false\
6574parallel.waitForAll(\
6575 function()\
6576 while not bEnd do\
6577 local event, key = os.pullEvent(\"key\")\
6578 if key ~= keys.escape then\
6579 bEnd = true\
6580 end\
6581 end \
6582 end,\
6583 function()\
6584 while not bEnd do\
6585 local fnMove = tMoves[math.random(1,#tMoves)]\
6586 fnMove()\
6587 end\
6588 end\
6589)\
6590\
6591if sAudio then\
6592 disk.stopAudio( sAudio )\
6593end\
6594",
6595 equip = "\
6596local tArgs = { ... }\
6597local function printUsage()\
6598 print( \"Usage: equip <slot> <side>\" )\
6599end\
6600\
6601if #tArgs ~= 2 then\
6602 printUsage()\
6603 return\
6604end\
6605\
6606local function equip( nSlot, fnEquipFunction )\
6607 turtle.select( nSlot )\
6608 local nOldCount = turtle.getItemCount( nSlot )\
6609 if nOldCount == 0 then\
6610 print( \"Nothing to equip\" )\
6611 elseif fnEquipFunction() then\
6612 local nNewCount = turtle.getItemCount( nSlot )\
6613 if nNewCount > 0 then\
6614 print( \"Items swapped\" )\
6615 else\
6616 print( \"Item equipped\" )\
6617 end\
6618 else\
6619 print( \"Item not equippable\" )\
6620 end\
6621end\
6622\
6623local nSlot = tonumber( tArgs[1] )\
6624local sSide = tArgs[2]\
6625if sSide == \"left\" then\
6626 equip( nSlot, turtle.equipLeft )\
6627elseif sSide == \"right\" then\
6628 equip( nSlot, turtle.equipRight )\
6629else\
6630 printUsage()\
6631 return\
6632end\
6633",
6634 turn = "local tArgs = { ... }\
6635if #tArgs < 1 then\
6636 print( \"Usage: turn <direction> <turns>\" )\
6637 return\
6638end\
6639\
6640local tHandlers = {\
6641 [\"lt\"] = turtle.turnLeft,\
6642 [\"left\"] = turtle.turnLeft,\
6643 [\"rt\"] = turtle.turnRight,\
6644 [\"right\"] = turtle.turnRight,\
6645}\
6646\
6647local nArg = 1\
6648while nArg <= #tArgs do\
6649 local sDirection = tArgs[nArg]\
6650 local nDistance = 1\
6651 if nArg < #tArgs then\
6652 local num = tonumber( tArgs[nArg + 1] )\
6653 if num then\
6654 nDistance = num\
6655 nArg = nArg + 1\
6656 end\
6657 end\
6658 nArg = nArg + 1\
6659\
6660 local fnHandler = tHandlers[string.lower(sDirection)]\
6661 if fnHandler then\
6662 for n=1,nDistance do\
6663 fnHandler( nArg )\
6664 end\
6665 else\
6666 print( \"No such direction: \"..sDirection )\
6667 print( \"Try: left, right\" )\
6668 return\
6669 end\
6670 \
6671end",
6672 tunnel = "\
6673local tArgs = { ... }\
6674if #tArgs ~= 1 then\
6675 print( \"Usage: tunnel <length>\" )\
6676 return\
6677end\
6678\
6679-- Mine in a quarry pattern until we hit something we can't dig\
6680local length = tonumber( tArgs[1] )\
6681if length < 1 then\
6682 print( \"Tunnel length must be positive\" )\
6683 return\
6684end\
6685 \
6686local depth = 0\
6687local collected = 0\
6688\
6689local function collect()\
6690 collected = collected + 1\
6691 if math.fmod(collected, 25) == 0 then\
6692 print( \"Mined \"..collected..\" items.\" )\
6693 end\
6694end\
6695\
6696local function tryDig()\
6697 while turtle.detect() do\
6698 if turtle.dig() then\
6699 collect()\
6700 sleep(0.5)\
6701 else\
6702 return false\
6703 end\
6704 end\
6705 return true\
6706end\
6707\
6708local function tryDigUp()\
6709 while turtle.detectUp() do\
6710 if turtle.digUp() then\
6711 collect()\
6712 sleep(0.5)\
6713 else\
6714 return false\
6715 end\
6716 end\
6717 return true\
6718end\
6719\
6720local function tryDigDown()\
6721 while turtle.detectDown() do\
6722 if turtle.digDown() then\
6723 collect()\
6724 sleep(0.5)\
6725 else\
6726 return false\
6727 end\
6728 end\
6729 return true\
6730end\
6731\
6732local function refuel()\
6733 local fuelLevel = turtle.getFuelLevel()\
6734 if fuelLevel == \"unlimited\" or fuelLevel > 0 then\
6735 return\
6736 end\
6737 \
6738 local function tryRefuel()\
6739 for n=1,16 do\
6740 if turtle.getItemCount(n) > 0 then\
6741 turtle.select(n)\
6742 if turtle.refuel(1) then\
6743 turtle.select(1)\
6744 return true\
6745 end\
6746 end\
6747 end\
6748 turtle.select(1)\
6749 return false\
6750 end\
6751 \
6752 if not tryRefuel() then\
6753 print( \"Add more fuel to continue.\" )\
6754 while not tryRefuel() do\
6755 os.pullEvent( \"turtle_inventory\" )\
6756 end\
6757 print( \"Resuming Tunnel.\" )\
6758 end\
6759end\
6760\
6761local function tryUp()\
6762 refuel()\
6763 while not turtle.up() do\
6764 if turtle.detectUp() then\
6765 if not tryDigUp() then\
6766 return false\
6767 end\
6768 elseif turtle.attackUp() then\
6769 collect()\
6770 else\
6771 sleep( 0.5 )\
6772 end\
6773 end\
6774 return true\
6775end\
6776\
6777local function tryDown()\
6778 refuel()\
6779 while not turtle.down() do\
6780 if turtle.detectDown() then\
6781 if not tryDigDown() then\
6782 return false\
6783 end\
6784 elseif turtle.attackDown() then\
6785 collect()\
6786 else\
6787 sleep( 0.5 )\
6788 end\
6789 end\
6790 return true\
6791end\
6792\
6793local function tryForward()\
6794 refuel()\
6795 while not turtle.forward() do\
6796 if turtle.detect() then\
6797 if not tryDig() then\
6798 return false\
6799 end\
6800 elseif turtle.attack() then\
6801 collect()\
6802 else\
6803 sleep( 0.5 )\
6804 end\
6805 end\
6806 return true\
6807end\
6808\
6809print( \"Tunnelling...\" )\
6810\
6811for n=1,length do\
6812 turtle.placeDown()\
6813 tryDigUp()\
6814 turtle.turnLeft()\
6815 tryDig()\
6816 tryUp()\
6817 tryDig()\
6818 turtle.turnRight()\
6819 turtle.turnRight()\
6820 tryDig()\
6821 tryDown()\
6822 tryDig()\
6823 turtle.turnLeft()\
6824 \
6825 if n<length then\
6826 tryDig()\
6827 if not tryForward() then\
6828 print( \"Aborting Tunnel.\" )\
6829 break\
6830 end\
6831 else\
6832 print( \"Tunnel complete.\" )\
6833 end\
6834\
6835end\
6836\
6837--[[\
6838print( \"Returning to start...\" )\
6839\
6840-- Return to where we started\
6841turtle.turnLeft()\
6842turtle.turnLeft()\
6843while depth > 0 do\
6844 if turtle.forward() then\
6845 depth = depth - 1\
6846 else\
6847 turtle.dig()\
6848 end\
6849end\
6850turtle.turnRight()\
6851turtle.turnRight()\
6852]]\
6853\
6854print( \"Tunnel complete.\" )\
6855print( \"Mined \"..collected..\" items total.\" )\
6856",
6857 go = "local tArgs = { ... }\
6858if #tArgs < 1 then\
6859 print( \"Usage: go <direction> <distance>\" )\
6860 return\
6861end\
6862\
6863local tHandlers = {\
6864 [\"fd\"] = turtle.forward,\
6865 [\"forward\"] = turtle.forward,\
6866 [\"forwards\"] = turtle.forward,\
6867 [\"bk\"] = turtle.back,\
6868 [\"back\"] = turtle.back,\
6869 [\"up\"] = turtle.up,\
6870 [\"dn\"] = turtle.down,\
6871 [\"down\"] = turtle.down,\
6872 [\"lt\"] = turtle.turnLeft,\
6873 [\"left\"] = turtle.turnLeft,\
6874 [\"rt\"] = turtle.turnRight,\
6875 [\"right\"] = turtle.turnRight,\
6876}\
6877\
6878local nArg = 1\
6879while nArg <= #tArgs do\
6880 local sDirection = tArgs[nArg]\
6881 local nDistance = 1\
6882 if nArg < #tArgs then\
6883 local num = tonumber( tArgs[nArg + 1] )\
6884 if num then\
6885 nDistance = num\
6886 nArg = nArg + 1\
6887 end\
6888 end\
6889 nArg = nArg + 1\
6890\
6891 local fnHandler = tHandlers[string.lower(sDirection)]\
6892 if fnHandler then\
6893 while nDistance > 0 do\
6894 if fnHandler() then\
6895 nDistance = nDistance - 1\
6896 elseif turtle.getFuelLevel() == 0 then\
6897 print( \"Out of fuel\" )\
6898 return\
6899 else\
6900 sleep(0.5)\
6901 end\
6902 end\
6903 else\
6904 print( \"No such direction: \"..sDirection )\
6905 print( \"Try: forward, back, up, down\" )\
6906 return\
6907 end\
6908\
6909end",
6910 },
6911 rednet = {
6912 [ "repeat" ] = "\
6913-- Find modems\
6914local tModems = {}\
6915for n,sModem in ipairs( peripheral.getNames() ) do\
6916 if peripheral.getType( sModem ) == \"modem\" then\
6917 table.insert( tModems, sModem )\
6918 end\
6919end\
6920if #tModems == 0 then\
6921 print( \"No modems found.\" )\
6922 return\
6923elseif #tModems == 1 then\
6924 print( \"1 modem found.\" )\
6925else\
6926 print( #tModems .. \" modems found.\" )\
6927end\
6928\
6929function open( nChannel )\
6930 for n=1,#tModems do\
6931 local sModem = tModems[n]\
6932 peripheral.call( sModem, \"open\", nChannel )\
6933 end\
6934end\
6935\
6936function close( nChannel )\
6937 for n=1,#tModems do\
6938 local sModem = tModems[n]\
6939 peripheral.call( sModem, \"close\", nChannel )\
6940 end\
6941end\
6942\
6943-- Open channels\
6944print( \"0 messages repeated.\" )\
6945open( rednet.CHANNEL_REPEAT )\
6946\
6947-- Main loop (terminate to break)\
6948local ok, error = pcall( function()\
6949 local tReceivedMessages = {}\
6950 local tReceivedMessageTimeouts = {}\
6951 local nTransmittedMessages = 0\
6952\
6953 while true do\
6954 local sEvent, sModem, nChannel, nReplyChannel, tMessage = os.pullEvent()\
6955 if sEvent == \"modem_message\" then\
6956 -- Got a modem message, rebroadcast it if it's a rednet thing\
6957 if nChannel == rednet.CHANNEL_REPEAT then\
6958 if type( tMessage ) == \"table\" and tMessage.nMessageID and tMessage.nRecipient then\
6959 if not tReceivedMessages[ tMessage.nMessageID ] then\
6960 -- Ensure we only repeat a message once\
6961 tReceivedMessages[ tMessage.nMessageID ] = true\
6962 tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = tMessage.nMessageID\
6963\
6964 -- Send on all other open modems, to the target and to other repeaters\
6965 for n=1,#tModems do\
6966 local sOtherModem = tModems[n]\
6967 peripheral.call( sOtherModem, \"transmit\", rednet.CHANNEL_REPEAT, nReplyChannel, tMessage )\
6968 peripheral.call( sOtherModem, \"transmit\", tMessage.nRecipient, nReplyChannel, tMessage )\
6969 end\
6970\
6971 -- Log the event\
6972 nTransmittedMessages = nTransmittedMessages + 1\
6973 local x,y = term.getCursorPos()\
6974 term.setCursorPos( 1, y - 1 )\
6975 term.clearLine()\
6976 if nTransmittedMessages == 1 then\
6977 print( nTransmittedMessages .. \" message repeated.\" )\
6978 else\
6979 print( nTransmittedMessages .. \" messages repeated.\" )\
6980 end\
6981 end\
6982 end\
6983 end\
6984\
6985 elseif sEvent == \"timer\" then\
6986 -- Got a timer event, use it to clear the message history\
6987 local nTimer = sModem\
6988 local nMessageID = tReceivedMessageTimeouts[ nTimer ]\
6989 if nMessageID then\
6990 tReceivedMessageTimeouts[ nTimer ] = nil\
6991 tReceivedMessages[ nMessageID ] = nil\
6992 end\
6993\
6994 end\
6995 end\
6996end )\
6997if not ok then\
6998 printError( error )\
6999end\
7000\
7001-- Close channels\
7002close( rednet.CHANNEL_REPEAT )\
7003",
7004 chat = "\
7005local tArgs = { ... }\
7006\
7007local function printUsage()\
7008 print( \"Usages:\" )\
7009 print( \"chat host <hostname>\" )\
7010 print( \"chat join <hostname> <nickname>\" )\
7011end\
7012\
7013local sOpenedModem = nil\
7014local function openModem()\
7015 for n,sModem in ipairs( peripheral.getNames() ) do\
7016 if peripheral.getType( sModem ) == \"modem\" then\
7017 if not rednet.isOpen( sModem ) then\
7018 rednet.open( sModem )\
7019 sOpenedModem = sModem\
7020 end\
7021 return true\
7022 end\
7023 end\
7024 print( \"No modems found.\" )\
7025 return false\
7026end\
7027\
7028local function closeModem()\
7029 if sOpenedModem ~= nil then\
7030 rednet.close( sOpenedModem )\
7031 sOpenedModem = nil\
7032 end\
7033end\
7034\
7035-- Colours\
7036local highlightColour, textColour\
7037if term.isColour() then\
7038 textColour = colours.white\
7039 highlightColour = colours.yellow\
7040else\
7041 textColour = colours.white\
7042 highlightColour = colours.white\
7043end\
7044\
7045local sCommand = tArgs[1]\
7046if sCommand == \"host\" then\
7047 -- \"chat host\"\
7048 -- Get hostname\
7049 local sHostname = tArgs[2]\
7050 if sHostname == nil then\
7051 printUsage()\
7052 return\
7053 end\
7054\
7055 -- Host server\
7056 if not openModem() then\
7057 return\
7058 end\
7059 rednet.host( \"chat\", sHostname )\
7060 print( \"0 users connected.\" )\
7061\
7062 local tUsers = {}\
7063 local nUsers = 0\
7064 function send( sText, nUserID )\
7065 if nUserID then\
7066 local tUser = tUsers[ nUserID ]\
7067 if tUser then\
7068 rednet.send( tUser.nID, {\
7069 sType = \"text\",\
7070 nUserID = nUserID,\
7071 sText = sText,\
7072 }, \"chat\" )\
7073 end\
7074 else\
7075 for nUserID, tUser in pairs( tUsers ) do\
7076 rednet.send( tUser.nID, {\
7077 sType = \"text\",\
7078 nUserID = nUserID,\
7079 sText = sText,\
7080 }, \"chat\" )\
7081 end\
7082 end\
7083 end\
7084\
7085 -- Setup ping pong\
7086 local tPingPongTimer = {}\
7087 function ping( nUserID )\
7088 local tUser = tUsers[ nUserID ]\
7089 rednet.send( tUser.nID, {\
7090 sType = \"ping to client\",\
7091 nUserID = nUserID,\
7092 }, \"chat\" )\
7093\
7094 local timer = os.startTimer( 15 )\
7095 tUser.bPingPonged = false\
7096 tPingPongTimer[ timer ] = nUserID\
7097 end\
7098\
7099 function printUsers()\
7100 local x,y = term.getCursorPos()\
7101 term.setCursorPos( 1, y - 1 )\
7102 term.clearLine()\
7103 if nUsers == 1 then\
7104 print( nUsers .. \" user connected.\" )\
7105 else\
7106 print( nUsers .. \" users connected.\" )\
7107 end\
7108 end\
7109\
7110 -- Handle messages\
7111 local ok, error = pcall( function()\
7112 parallel.waitForAny( function()\
7113 while true do\
7114 local sEvent, timer = os.pullEvent( \"timer\" )\
7115 local nUserID = tPingPongTimer[ timer ]\
7116 if nUserID and tUsers[ nUserID ] then\
7117 local tUser = tUsers[ nUserID ]\
7118 if tUser then\
7119 if not tUser.bPingPonged then\
7120 send( \"* \"..tUser.sUsername..\" has timed out\" )\
7121 tUsers[ nUserID ] = nil\
7122 nUsers = nUsers - 1\
7123 printUsers()\
7124 else\
7125 ping( nUserID )\
7126 end\
7127 end\
7128 end\
7129 end\
7130 end,\
7131 function()\
7132 while true do\
7133 local tCommands\
7134 tCommands = {\
7135 [\"me\"] = function( tUser, sContent )\
7136 if string.len(sContent) > 0 then\
7137 send( \"* \"..tUser.sUsername..\" \"..sContent )\
7138 else\
7139 send( \"* Usage: /me [words]\", tUser.nUserID )\
7140 end\
7141 end,\
7142 [\"nick\"] = function( tUser, sContent )\
7143 if string.len(sContent) > 0 then\
7144 local sOldName = tUser.sUsername\
7145 tUser.sUsername = sContent\
7146 send( \"* \"..sOldName..\" is now known as \"..tUser.sUsername )\
7147 else\
7148 send( \"* Usage: /nick [nickname]\", tUser.nUserID )\
7149 end\
7150 end,\
7151 [\"users\"] = function( tUser, sContent )\
7152 send( \"* Connected Users:\", tUser.nUserID )\
7153 local sUsers = \"*\"\
7154 for nUserID, tUser in pairs( tUsers ) do\
7155 sUsers = sUsers .. \" \" .. tUser.sUsername\
7156 end\
7157 send( sUsers, tUser.nUserID )\
7158 end,\
7159 [\"help\"] = function( tUser, sContent )\
7160 send( \"* Available commands:\", tUser.nUserID )\
7161 local sCommands = \"*\"\
7162 for sCommand, fnCommand in pairs( tCommands ) do\
7163 sCommands = sCommands .. \" /\" .. sCommand\
7164 end\
7165 send( sCommands..\" /logout\", tUser.nUserID )\
7166 end,\
7167 }\
7168\
7169 local nSenderID, tMessage = rednet.receive( \"chat\" )\
7170 if type( tMessage ) == \"table\" then\
7171 if tMessage.sType == \"login\" then\
7172 -- Login from new client\
7173 local nUserID = tMessage.nUserID\
7174 local sUsername = tMessage.sUsername\
7175 if nUserID and sUsername then\
7176 tUsers[ nUserID ] = {\
7177 nID = nSenderID,\
7178 nUserID = nUserID,\
7179 sUsername = sUsername,\
7180 }\
7181 nUsers = nUsers + 1\
7182 printUsers()\
7183 send( \"* \"..sUsername..\" has joined the chat\" )\
7184 ping( nUserID )\
7185 end\
7186\
7187 else\
7188 -- Something else from existing client\
7189 local nUserID = tMessage.nUserID\
7190 local tUser = tUsers[ nUserID ]\
7191 if tUser and tUser.nID == nSenderID then\
7192 if tMessage.sType == \"logout\" then\
7193 send( \"* \"..tUser.sUsername..\" has left the chat\" )\
7194 tUsers[ nUserID ] = nil\
7195 nUsers = nUsers - 1\
7196 printUsers()\
7197\
7198 elseif tMessage.sType == \"chat\" then\
7199 local sMessage = tMessage.sText\
7200 if sMessage then\
7201 local sCommand = string.match( sMessage, \"^/([a-z]+)\" )\
7202 if sCommand then\
7203 local fnCommand = tCommands[ sCommand ]\
7204 if fnCommand then\
7205 local sContent = string.sub( sMessage, string.len(sCommand)+3 )\
7206 fnCommand( tUser, sContent )\
7207 else\
7208 send( \"* Unrecognised command: /\"..sCommand, tUser.nUserID )\
7209 end\
7210 else\
7211 send( \"<\"..tUser.sUsername..\"> \"..tMessage.sText )\
7212 end\
7213 end\
7214\
7215 elseif tMessage.sType == \"ping to server\" then\
7216 rednet.send( tUser.nID, {\
7217 sType = \"pong to client\",\
7218 nUserID = nUserID,\
7219 }, \"chat\" )\
7220\
7221 elseif tMessage.sType == \"pong to server\" then\
7222 tUser.bPingPonged = true\
7223\
7224 end\
7225 end\
7226 end\
7227 end\
7228 end\
7229 end )\
7230 end )\
7231 if not ok then\
7232 printError( error )\
7233 end\
7234\
7235 -- Unhost server\
7236 for nUserID, tUser in pairs( tUsers ) do\
7237 rednet.send( tUser.nID, {\
7238 sType = \"kick\",\
7239 nUserID = nUserID,\
7240 }, \"chat\" )\
7241 end\
7242 rednet.unhost( \"chat\" )\
7243 closeModem()\
7244\
7245elseif sCommand == \"join\" then\
7246 -- \"chat join\"\
7247 -- Get hostname and username\
7248 local sHostname = tArgs[2]\
7249 local sUsername = tArgs[3]\
7250 if sHostname == nil or sUsername == nil then\
7251 printUsage()\
7252 return\
7253 end\
7254\
7255 -- Connect\
7256 if not openModem() then\
7257 return\
7258 end\
7259 write( \"Looking up \" .. sHostname .. \"... \" )\
7260 local nHostID = rednet.lookup( \"chat\", sHostname )\
7261 if nHostID == nil then\
7262 print( \"Failed.\" )\
7263 return\
7264 else\
7265 print( \"Success.\" )\
7266 end\
7267\
7268 -- Login\
7269 local nUserID = math.random( 1, 2147483647 )\
7270 rednet.send( nHostID, {\
7271 sType = \"login\",\
7272 nUserID = nUserID,\
7273 sUsername = sUsername,\
7274 }, \"chat\" )\
7275\
7276 -- Setup ping pong\
7277 local bPingPonged = true\
7278 local pingPongTimer = os.startTimer( 0 )\
7279\
7280 function ping()\
7281 rednet.send( nHostID, {\
7282 sType = \"ping to server\",\
7283 nUserID = nUserID,\
7284 }, \"chat\" )\
7285 bPingPonged = false\
7286 pingPongTimer = os.startTimer( 15 )\
7287 end\
7288\
7289 -- Handle messages\
7290 local w,h = term.getSize()\
7291 local parentTerm = term.current()\
7292 local titleWindow = window.create( parentTerm, 1, 1, w, 1, true )\
7293 local historyWindow = window.create( parentTerm, 1, 2, w, h-2, true )\
7294 local promptWindow = window.create( parentTerm, 1, h, w, 1, true )\
7295 historyWindow.setCursorPos( 1, h-2 )\
7296\
7297 term.clear()\
7298 term.setTextColour( textColour )\
7299 term.redirect( promptWindow )\
7300 promptWindow.restoreCursor()\
7301\
7302 function drawTitle()\
7303 local x,y = titleWindow.getCursorPos()\
7304 local w,h = titleWindow.getSize()\
7305 local sTitle = sUsername..\" on \"..sHostname\
7306 titleWindow.setTextColour( highlightColour )\
7307 titleWindow.setCursorPos( math.floor( w/2 - string.len(sTitle)/2 ), 1 )\
7308 titleWindow.clearLine()\
7309 titleWindow.write( sTitle )\
7310 promptWindow.restoreCursor()\
7311 end\
7312\
7313 function printMessage( sMessage )\
7314 term.redirect( historyWindow )\
7315 print()\
7316 if string.match( sMessage, \"^\\*\" ) then\
7317 -- Information\
7318 term.setTextColour( highlightColour )\
7319 write( sMessage )\
7320 term.setTextColour( textColour )\
7321 else\
7322 -- Chat\
7323 local sUsernameBit = string.match( sMessage, \"^\\<[^\\>]*\\>\" )\
7324 if sUsernameBit then\
7325 term.setTextColour( highlightColour )\
7326 write( sUsernameBit )\
7327 term.setTextColour( textColour )\
7328 write( string.sub( sMessage, string.len( sUsernameBit ) + 1 ) )\
7329 else\
7330 write( sMessage )\
7331 end\
7332 end\
7333 term.redirect( promptWindow )\
7334 promptWindow.restoreCursor()\
7335 end\
7336\
7337 drawTitle()\
7338\
7339 local ok, error = pcall( function()\
7340 parallel.waitForAny( function()\
7341 while true do\
7342 local sEvent, timer = os.pullEvent()\
7343 if sEvent == \"timer\" then\
7344 if timer == pingPongTimer then\
7345 if not bPingPonged then\
7346 printMessage( \"Server timeout.\" )\
7347 return\
7348 else\
7349 ping()\
7350 end\
7351 end\
7352\
7353 elseif sEvent == \"term_resize\" then\
7354 local w,h = parentTerm.getSize()\
7355 titleWindow.reposition( 1, 1, w, 1 )\
7356 historyWindow.reposition( 1, 2, w, h-2 )\
7357 promptWindow.reposition( 1, h, w, 1 )\
7358\
7359 end\
7360 end\
7361 end,\
7362 function()\
7363 while true do\
7364 local nSenderID, tMessage = rednet.receive( \"chat\" )\
7365 if nSenderID == nHostID and type( tMessage ) == \"table\" and tMessage.nUserID == nUserID then\
7366 if tMessage.sType == \"text\" then\
7367 local sText = tMessage.sText\
7368 if sText then\
7369 printMessage( sText )\
7370 end\
7371\
7372 elseif tMessage.sType == \"ping to client\" then\
7373 rednet.send( nSenderID, {\
7374 sType = \"pong to server\",\
7375 nUserID = nUserID,\
7376 }, \"chat\" )\
7377\
7378 elseif tMessage.sType == \"pong to client\" then\
7379 bPingPonged = true\
7380\
7381 elseif tMessage.sType == \"kick\" then\
7382 return\
7383\
7384 end\
7385 end\
7386 end\
7387 end,\
7388 function()\
7389 local tSendHistory = {}\
7390 while true do\
7391 promptWindow.setCursorPos( 1,1 )\
7392 promptWindow.clearLine()\
7393 promptWindow.setTextColor( highlightColour )\
7394 promptWindow.write( \": \")\
7395 promptWindow.setTextColor( textColour )\
7396\
7397 local sChat = read( nil, tSendHistory )\
7398 if string.match( sChat, \"^/logout\" ) then\
7399 break\
7400 else\
7401 rednet.send( nHostID, {\
7402 sType = \"chat\",\
7403 nUserID = nUserID,\
7404 sText = sChat,\
7405 }, \"chat\" )\
7406 table.insert( tSendHistory, sChat )\
7407 end\
7408 end\
7409 end )\
7410 end )\
7411\
7412 -- Close the windows\
7413 term.redirect( parentTerm )\
7414\
7415 -- Print error notice\
7416 local w,h = term.getSize()\
7417 term.setCursorPos( 1, h )\
7418 term.clearLine()\
7419 term.setCursorBlink( false )\
7420 if not ok then\
7421 printError( error )\
7422 end\
7423\
7424 -- Logout\
7425 rednet.send( nHostID, {\
7426 sType = \"logout\",\
7427 nUserID = nUserID,\
7428 }, \"chat\" )\
7429 closeModem()\
7430\
7431 -- Print disconnection notice\
7432 print( \"Disconnected.\" )\
7433\
7434else\
7435 -- \"chat somethingelse\"\
7436 printUsage()\
7437\
7438end\
7439",
7440 },
7441 mkdir = "local tArgs = { ... }\
7442if #tArgs < 1 then\
7443 print( \"Usage: mkdir <path>\" )\
7444 return\
7445end\
7446\
7447local sNewDir = shell.resolve( tArgs[1] )\
7448fs.makeDir( sNewDir )\
7449\
7450",
7451 advanced = {
7452 multishell = "\
7453-- Setup process switching\
7454local parentTerm = term.current()\
7455local w,h = parentTerm.getSize()\
7456\
7457local tProcesses = {}\
7458local nCurrentProcess = nil\
7459local nRunningProcess = nil\
7460local bShowMenu = false\
7461local bWindowsResized = false\
7462\
7463local function selectProcess( n )\
7464 if nCurrentProcess ~= n then\
7465 if nCurrentProcess then\
7466 local tOldProcess = tProcesses[ nCurrentProcess ]\
7467 tOldProcess.window.setVisible( false )\
7468 end\
7469 nCurrentProcess = n\
7470 if nCurrentProcess then\
7471 local tNewProcess = tProcesses[ nCurrentProcess ]\
7472 tNewProcess.window.setVisible( true )\
7473 tNewProcess.bInteracted = true\
7474 end\
7475 end\
7476end\
7477\
7478local function setProcessTitle( n, sTitle )\
7479 tProcesses[ n ].sTitle = sTitle\
7480end\
7481\
7482local function resumeProcess( nProcess, sEvent, ... )\
7483 local tProcess = tProcesses[ nProcess ]\
7484 local sFilter = tProcess.sFilter\
7485 if sFilter == nil or sFilter == sEvent or sEvent == \"terminate\" then\
7486 local nPreviousProcess = nRunningProcess\
7487 nRunningProcess = nProcess\
7488 term.redirect( tProcess.terminal )\
7489 local ok, result = coroutine.resume( tProcess.co, sEvent, ... )\
7490 tProcess.terminal = term.current()\
7491 if ok then\
7492 tProcess.sFilter = result\
7493 else\
7494 printError( result )\
7495 end\
7496 nRunningProcess = nPreviousProcess\
7497 end\
7498end\
7499\
7500local function launchProcess( tProgramEnv, sProgramPath, ... )\
7501 local tProgramArgs = { ... }\
7502 local nProcess = #tProcesses + 1\
7503 local tProcess = {}\
7504 tProcess.sTitle = fs.getName( sProgramPath )\
7505 if bShowMenu then\
7506 tProcess.window = window.create( parentTerm, 1, 2, w, h-1, false )\
7507 else\
7508 tProcess.window = window.create( parentTerm, 1, 1, w, h, false )\
7509 end\
7510 tProcess.co = coroutine.create( function()\
7511 os.run( tProgramEnv, sProgramPath, unpack( tProgramArgs ) )\
7512 if not tProcess.bInteracted then\
7513 term.setCursorBlink( false )\
7514 print( \"Press any key to continue\" )\
7515 os.pullEvent( \"char\" )\
7516 end\
7517 end )\
7518 tProcess.sFilter = nil\
7519 tProcess.terminal = tProcess.window\
7520 tProcess.bInteracted = false\
7521 tProcesses[ nProcess ] = tProcess\
7522 resumeProcess( nProcess )\
7523 return nProcess\
7524end\
7525\
7526local function cullProcess( nProcess )\
7527 local tProcess = tProcesses[ nProcess ]\
7528 if coroutine.status( tProcess.co ) == \"dead\" then\
7529 if nCurrentProcess == nProcess then\
7530 selectProcess( nil )\
7531 end\
7532 table.remove( tProcesses, nProcess )\
7533 if nCurrentProcess == nil then\
7534 if nProcess > 1 then\
7535 selectProcess( nProcess - 1 )\
7536 elseif #tProcesses > 0 then\
7537 selectProcess( 1 )\
7538 end\
7539 end\
7540 return true\
7541 end\
7542 return false\
7543end\
7544\
7545local function cullProcesses()\
7546 local culled = false\
7547 for n=#tProcesses,1,-1 do\
7548 culled = culled or cullProcess( n )\
7549 end\
7550 return culled\
7551end\
7552\
7553-- Setup the main menu\
7554local menuMainTextColor, menuMainBgColor, menuOtherTextColor, menuOtherBgColor\
7555if parentTerm.isColor() then\
7556 menuMainTextColor, menuMainBgColor = colors.yellow, colors.black\
7557 menuOtherTextColor, menuOtherBgColor = colors.black, colors.gray\
7558else\
7559 menuMainTextColor, menuMainBgColor = colors.white, colors.black\
7560 menuOtherTextColor, menuOtherBgColor = colors.black, colors.white\
7561end\
7562\
7563local function redrawMenu()\
7564 if bShowMenu then\
7565 -- Draw menu\
7566 parentTerm.setCursorPos( 1, 1 )\
7567 parentTerm.setBackgroundColor( menuOtherBgColor )\
7568 parentTerm.clearLine()\
7569 for n=1,#tProcesses do\
7570 if n == nCurrentProcess then\
7571 parentTerm.setTextColor( menuMainTextColor )\
7572 parentTerm.setBackgroundColor( menuMainBgColor )\
7573 else\
7574 parentTerm.setTextColor( menuOtherTextColor )\
7575 parentTerm.setBackgroundColor( menuOtherBgColor )\
7576 end\
7577 parentTerm.write( \" \" .. tProcesses[n].sTitle .. \" \" )\
7578 end\
7579\
7580 -- Put the cursor back where it should be\
7581 local tProcess = tProcesses[ nCurrentProcess ]\
7582 if tProcess then\
7583 tProcess.window.restoreCursor()\
7584 end\
7585 end\
7586end\
7587\
7588local function resizeWindows()\
7589 local windowY, windowHeight\
7590 if bShowMenu then\
7591 windowY = 2\
7592 windowHeight = h-1\
7593 else\
7594 windowY = 1\
7595 windowHeight = h\
7596 end\
7597 for n=1,#tProcesses do\
7598 local tProcess = tProcesses[n]\
7599 local window = tProcess.window\
7600 local x,y = tProcess.window.getCursorPos()\
7601 if y > windowHeight then\
7602 tProcess.window.scroll( y - windowHeight )\
7603 tProcess.window.setCursorPos( x, windowHeight )\
7604 end\
7605 tProcess.window.reposition( 1, windowY, w, windowHeight )\
7606 end\
7607 bWindowsResized = true\
7608end\
7609\
7610local function setMenuVisible( bVis )\
7611 if bShowMenu ~= bVis then\
7612 bShowMenu = bVis\
7613 resizeWindows()\
7614 redrawMenu()\
7615 end\
7616end\
7617\
7618local multishell = {}\
7619\
7620function multishell.getFocus()\
7621 return nCurrentProcess\
7622end\
7623\
7624function multishell.setFocus( n )\
7625 if n >= 1 and n <= #tProcesses then\
7626 selectProcess( n )\
7627 redrawMenu()\
7628 return true\
7629 end\
7630 return false\
7631end\
7632\
7633function multishell.getTitle( n )\
7634 if n >= 1 and n <= #tProcesses then\
7635 return tProcesses[n].sTitle\
7636 end\
7637 return nil\
7638end\
7639\
7640function multishell.setTitle( n, sTitle )\
7641 if n >= 1 and n <= #tProcesses then\
7642 setProcessTitle( n, sTitle )\
7643 redrawMenu()\
7644 end\
7645end\
7646\
7647function multishell.getCurrent()\
7648 return nRunningProcess\
7649end\
7650\
7651function multishell.launch( tProgramEnv, sProgramPath, ... )\
7652 local previousTerm = term.current()\
7653 setMenuVisible( (#tProcesses + 1) >= 2 )\
7654 local nResult = launchProcess( tProgramEnv, sProgramPath, ... )\
7655 redrawMenu()\
7656 term.redirect( previousTerm )\
7657 return nResult\
7658end\
7659\
7660function multishell.getCount()\
7661 return #tProcesses\
7662end\
7663\
7664-- Begin\
7665parentTerm.clear()\
7666setMenuVisible( false )\
7667selectProcess( launchProcess( {\
7668 [\"shell\"] = shell,\
7669 [\"multishell\"] = multishell,\
7670}, \"/rom/programs/shell\" ) )\
7671redrawMenu()\
7672\
7673-- Run processes\
7674while #tProcesses > 0 do\
7675 -- Get the event\
7676 local tEventData = { os.pullEventRaw() }\
7677 local sEvent = tEventData[1]\
7678 if sEvent == \"term_resize\" then\
7679 -- Resize event\
7680 w,h = parentTerm.getSize()\
7681 resizeWindows()\
7682 redrawMenu()\
7683\
7684 elseif sEvent == \"char\" or sEvent == \"key\" or sEvent == \"paste\" or sEvent == \"terminate\" then\
7685 -- Keyboard event\
7686 -- Passthrough to current process\
7687 resumeProcess( nCurrentProcess, unpack( tEventData ) )\
7688 if cullProcess( nCurrentProcess ) then\
7689 setMenuVisible( #tProcesses >= 2 )\
7690 redrawMenu()\
7691 end\
7692\
7693 elseif sEvent == \"mouse_click\" then\
7694 -- Click event\
7695 local button, x, y = tEventData[2], tEventData[3], tEventData[4]\
7696 if bShowMenu and y == 1 then\
7697 -- Switch process\
7698 local tabStart = 1\
7699 for n=1,#tProcesses do\
7700 tabEnd = tabStart + string.len( tProcesses[n].sTitle ) + 1\
7701 if x >= tabStart and x <= tabEnd then\
7702 selectProcess( n )\
7703 redrawMenu()\
7704 break\
7705 end\
7706 tabStart = tabEnd + 1\
7707 end\
7708 else\
7709 -- Passthrough to current process\
7710 resumeProcess( nCurrentProcess, sEvent, button, x, (bShowMenu and y-1) or y )\
7711 if cullProcess( nCurrentProcess ) then\
7712 setMenuVisible( #tProcesses >= 2 )\
7713 redrawMenu()\
7714 end\
7715 end\
7716\
7717 elseif sEvent == \"mouse_drag\" or sEvent == \"mouse_scroll\" then\
7718 -- Other mouse event\
7719 local p1, x, y = tEventData[2], tEventData[3], tEventData[4]\
7720 if not (bShowMenu and y == 1) then\
7721 -- Passthrough to current process\
7722 resumeProcess( nCurrentProcess, sEvent, p1, x, (bShowMenu and y-1) or y )\
7723 if cullProcess( nCurrentProcess ) then\
7724 setMenuVisible( #tProcesses >= 2 )\
7725 redrawMenu()\
7726 end\
7727 end\
7728\
7729 else\
7730 -- Other event\
7731 -- Passthrough to all processes\
7732 local nLimit = #tProcesses -- Storing this ensures any new things spawned don't get the event\
7733 for n=1,nLimit do\
7734 resumeProcess( n, unpack( tEventData ) )\
7735 end\
7736 if cullProcesses() then\
7737 setMenuVisible( #tProcesses >= 2 )\
7738 redrawMenu()\
7739 end\
7740 end\
7741\
7742 if bWindowsResized then\
7743 -- Pass term_resize to all processes\
7744 local nLimit = #tProcesses -- Storing this ensures any new things spawned don't get the event\
7745 for n=1,nLimit do\
7746 resumeProcess( n, \"term_resize\" )\
7747 end\
7748 bWindowsResized = false\
7749 if cullProcesses() then\
7750 setMenuVisible( #tProcesses >= 2 )\
7751 redrawMenu()\
7752 end\
7753 end\
7754end\
7755\
7756-- Shutdown\
7757term.redirect( parentTerm )\
7758",
7759 fg = "\
7760local tArgs = { ... }\
7761if #tArgs > 0 then\
7762 local nTask = shell.openTab( unpack( tArgs ) )\
7763 if nTask then\
7764 shell.switchTab( nTask )\
7765 end\
7766else\
7767 local nTask = shell.openTab( \"shell\" )\
7768 if nTask then\
7769 shell.switchTab( nTask )\
7770 end\
7771end\
7772",
7773 bg = "\
7774local tArgs = { ... }\
7775if #tArgs > 0 then\
7776 shell.openTab( unpack( tArgs ) )\
7777else\
7778 shell.openTab( \"shell\" )\
7779end\
7780",
7781 },
7782 eject = "\
7783-- Get arguments\
7784local tArgs = { ... }\
7785if #tArgs == 0 then\
7786 print( \"Usage: eject <drive>\" )\
7787 return\
7788end\
7789\
7790local sDrive = tArgs[1]\
7791\
7792-- Check the disk exists\
7793local bPresent = disk.isPresent( sDrive )\
7794if not bPresent then\
7795 print( \"Nothing in \"..sDrive..\" drive\" )\
7796 return\
7797end\
7798\
7799disk.eject( sDrive )\
7800",
7801 cd = "\
7802local tArgs = { ... }\
7803if #tArgs < 1 then\
7804 print( \"Usage: cd <path>\" )\
7805 return\
7806end\
7807\
7808local sNewDir = shell.resolve( tArgs[1] )\
7809if fs.isDir( sNewDir ) then\
7810 shell.setDir( sNewDir )\
7811else\
7812 print( \"Not a directory\" )\
7813 return\
7814end\
7815",
7816 rename = "local tArgs = { ... }\
7817if #tArgs < 2 then\
7818 print( \"Usage: rename <source> <destination>\" )\
7819 return\
7820end\
7821\
7822local sSource = shell.resolve( tArgs[1] )\
7823local sDest = shell.resolve( tArgs[2] )\
7824fs.move( sSource, sDest )\
7825",
7826 shell = "\
7827local multishell = multishell\
7828local parentShell = shell\
7829local parentTerm = term.current()\
7830\
7831if multishell then\
7832 multishell.setTitle( multishell.getCurrent(), \"shell\" )\
7833end\
7834\
7835local bExit = false\
7836local sDir = (parentShell and parentShell.dir()) or \"\"\
7837local sPath = (parentShell and parentShell.path()) or \".:/rom/programs\"\
7838local tAliases = (parentShell and parentShell.aliases()) or {}\
7839local tProgramStack = {}\
7840\
7841local shell = {}\
7842local tEnv = {\
7843 [ \"shell\" ] = shell,\
7844 [ \"multishell\" ] = multishell,\
7845}\
7846\
7847-- Colours\
7848local promptColour, textColour, bgColour\
7849if term.isColour() then\
7850 promptColour = colours.yellow\
7851 textColour = colours.white\
7852 bgColour = colours.black\
7853else\
7854 promptColour = colours.white\
7855 textColour = colours.white\
7856 bgColour = colours.black\
7857end\
7858\
7859local function run( _sCommand, ... )\
7860 local sPath = shell.resolveProgram( _sCommand )\
7861 if sPath ~= nil then\
7862 tProgramStack[#tProgramStack + 1] = sPath\
7863 if multishell then\
7864 multishell.setTitle( multishell.getCurrent(), fs.getName( sPath ) )\
7865 end\
7866 local result = os.run( tEnv, sPath, ... )\
7867 tProgramStack[#tProgramStack] = nil\
7868 if multishell then\
7869 if #tProgramStack > 0 then\
7870 multishell.setTitle( multishell.getCurrent(), fs.getName( tProgramStack[#tProgramStack] ) )\
7871 else\
7872 multishell.setTitle( multishell.getCurrent(), \"shell\" )\
7873 end\
7874 end\
7875 return result\
7876 else\
7877 printError( \"No such program\" )\
7878 return false\
7879 end\
7880end\
7881\
7882local function tokenise( ... )\
7883 local sLine = table.concat( { ... }, \" \" )\
7884 local tWords = {}\
7885 local bQuoted = false\
7886 for match in string.gmatch( sLine .. \"\\\"\", \"(.-)\\\"\" ) do\
7887 if bQuoted then\
7888 table.insert( tWords, match )\
7889 else\
7890 for m in string.gmatch( match, \"[^ \\t]+\" ) do\
7891 table.insert( tWords, m )\
7892 end\
7893 end\
7894 bQuoted = not bQuoted\
7895 end\
7896 return tWords\
7897end\
7898\
7899-- Install shell API\
7900function shell.run( ... )\
7901 local tWords = tokenise( ... )\
7902 local sCommand = tWords[1]\
7903 if sCommand then\
7904 return run( sCommand, unpack( tWords, 2 ) )\
7905 end\
7906 return false\
7907end\
7908\
7909function shell.exit()\
7910 bExit = true\
7911end\
7912\
7913function shell.dir()\
7914 return sDir\
7915end\
7916\
7917function shell.setDir( _sDir )\
7918 sDir = _sDir\
7919end\
7920\
7921function shell.path()\
7922 return sPath\
7923end\
7924\
7925function shell.setPath( _sPath )\
7926 sPath = _sPath\
7927end\
7928\
7929function shell.resolve( _sPath )\
7930 local sStartChar = string.sub( _sPath, 1, 1 )\
7931 if sStartChar == \"/\" or sStartChar == \"\\\\\" then\
7932 return fs.combine( \"\", _sPath )\
7933 else\
7934 return fs.combine( sDir, _sPath )\
7935 end\
7936end\
7937\
7938function shell.resolveProgram( _sCommand )\
7939 -- Substitute aliases firsts\
7940 if tAliases[ _sCommand ] ~= nil then\
7941 _sCommand = tAliases[ _sCommand ]\
7942 end\
7943\
7944 -- If the path is a global path, use it directly\
7945 local sStartChar = string.sub( _sCommand, 1, 1 )\
7946 if sStartChar == \"/\" or sStartChar == \"\\\\\" then\
7947 local sPath = fs.combine( \"\", _sCommand )\
7948 if fs.exists( sPath ) and not fs.isDir( sPath ) then\
7949 return sPath\
7950 end\
7951 return nil\
7952 end\
7953 \
7954 -- Otherwise, look on the path variable\
7955 for sPath in string.gmatch(sPath, \"[^:]+\") do\
7956 sPath = fs.combine( shell.resolve( sPath ), _sCommand )\
7957 if fs.exists( sPath ) and not fs.isDir( sPath ) then\
7958 return sPath\
7959 end\
7960 end\
7961 \
7962 -- Not found\
7963 return nil\
7964end\
7965\
7966function shell.programs( _bIncludeHidden )\
7967 local tItems = {}\
7968 \
7969 -- Add programs from the path\
7970 for sPath in string.gmatch(sPath, \"[^:]+\") do\
7971 sPath = shell.resolve( sPath )\
7972 if fs.isDir( sPath ) then\
7973 local tList = fs.list( sPath )\
7974 for n,sFile in pairs( tList ) do\
7975 if not fs.isDir( fs.combine( sPath, sFile ) ) and\
7976 (_bIncludeHidden or string.sub( sFile, 1, 1 ) ~= \".\") then\
7977 tItems[ sFile ] = true\
7978 end\
7979 end\
7980 end\
7981 end \
7982\
7983 -- Sort and return\
7984 local tItemList = {}\
7985 for sItem, b in pairs( tItems ) do\
7986 table.insert( tItemList, sItem )\
7987 end\
7988 table.sort( tItemList )\
7989 return tItemList\
7990end\
7991\
7992function shell.getRunningProgram()\
7993 if #tProgramStack > 0 then\
7994 return tProgramStack[#tProgramStack]\
7995 end\
7996 return nil\
7997end\
7998\
7999function shell.setAlias( _sCommand, _sProgram )\
8000 tAliases[ _sCommand ] = _sProgram\
8001end\
8002\
8003function shell.clearAlias( _sCommand )\
8004 tAliases[ _sCommand ] = nil\
8005end\
8006\
8007function shell.aliases()\
8008 -- Add aliases\
8009 local tCopy = {}\
8010 for sAlias, sCommand in pairs( tAliases ) do\
8011 tCopy[sAlias] = sCommand\
8012 end\
8013 return tCopy\
8014end\
8015\
8016if multishell then\
8017 function shell.openTab( ... )\
8018 local tWords = tokenise( ... )\
8019 local sCommand = tWords[1]\
8020 if sCommand then\
8021 local sPath = shell.resolveProgram( sCommand )\
8022 if sPath == \"rom/programs/shell\" then\
8023 return multishell.launch( tEnv, sPath, unpack( tWords, 2 ) )\
8024 elseif sPath ~= nil then\
8025 return multishell.launch( tEnv, \"rom/programs/shell\", sPath, unpack( tWords, 2 ) )\
8026 else\
8027 printError( \"No such program\" )\
8028 end\
8029 end\
8030 end\
8031\
8032 function shell.switchTab( nID )\
8033 multishell.setFocus( nID )\
8034 end\
8035end\
8036\
8037local tArgs = { ... }\
8038if #tArgs > 0 then\
8039 -- \"shell x y z\"\
8040 -- Run the program specified on the commandline\
8041 shell.run( ... )\
8042\
8043else\
8044 -- \"shell\"\
8045 -- Print the header\
8046 term.setBackgroundColor( bgColour )\
8047 term.setTextColour( promptColour )\
8048 print( os.version() )\
8049 term.setTextColour( textColour )\
8050\
8051 -- Run the startup program\
8052 if parentShell == nil then\
8053 shell.run( \"/rom/startup\" )\
8054 end\
8055\
8056 -- Read commands and execute them\
8057 local tCommandHistory = {}\
8058 while not bExit do\
8059 term.redirect( parentTerm )\
8060 term.setBackgroundColor( bgColour )\
8061 term.setTextColour( promptColour )\
8062 write( shell.dir() .. \"> \" )\
8063 term.setTextColour( textColour )\
8064\
8065 local sLine = read( nil, tCommandHistory )\
8066 table.insert( tCommandHistory, sLine )\
8067 shell.run( sLine )\
8068 end\
8069end\
8070",
8071 },
8072 help = {
8073 exit = "exit will exit the current shell.",
8074 monitor = "monitor will connect to an attached Monitor peripheral, and run a program on its display.\
8075\
8076ex:\
8077\"monitor left hello\" will run the \"hello\" program on the monitor to the left of the computer.\
8078\"monitor top edit foo\" will run the edit program on the top monitor, editing the file \"foo\".",
8079 redstoneapi = "Functions in the Redstone API:\
8080redstone.getSides( )\
8081redstone.getInput( side )\
8082redstone.setOutput( side, boolean )\
8083redstone.getOutput( side )\
8084redstone.getAnalogInput( side )\
8085redstone.setAnalogOutput( side, number )\
8086redstone.getAnalogOutput( side )\
8087\
8088Functions in the Redstone API for working with bundled cables:\
8089redstone.getBundledInput( side )\
8090redstone.testBundledInput( side, color )\
8091redstone.setBundledOutput( side, colors )\
8092redstone.getBundledOutput( side )\
8093Type \"help bundled\" for usage examples.\
8094\
8095Events emitted by the redstone API:\
8096\"redstone\", when the state of any redstone input changes. Use getInput() or getBundledInput() to inspect the changes\
8097Type \"help events\" to learn about the event system.\
8098",
8099 fs = "Functions in the Filesystem API:\
8100fs.list( path )\
8101fs.find( wildcard )\
8102fs.exists( path )\
8103fs.isDir( path )\
8104fs.isReadOnly( path )\
8105fs.getDir( path )\
8106fs.getName( path )\
8107fs.getSize( path )\
8108fs.getDrive( path )\
8109fs.getFreeSpace( path )\
8110fs.makeDir( path )\
8111fs.move( path, path )\
8112fs.copy( path, path )\
8113fs.delete( path )\
8114fs.combine( path, localpath )\
8115fs.open( path, mode )\
8116Available fs.open() modes are \"r\", \"w\", \"a\", \"rb\", \"wb\" and \"ab\".\
8117\
8118Functions on files opened with mode \"r\":\
8119readLine()\
8120readAll()\
8121close()\
8122\
8123Functions on files opened with mode \"w\" or \"a\":\
8124write( string )\
8125writeLine( string )\
8126flush()\
8127close()\
8128\
8129Functions on files opened with mode \"rb\":\
8130read()\
8131close()\
8132\
8133Functions on files opened with mode \"wb\" or \"ab\":\
8134write( byte )\
8135flush()\
8136close()",
8137 colours = "Functions in the colours api\
8138(used for redstone.setBundledOutput):\
8139colours.combine( colour1, colour2, colour3, ...)\
8140colours.subtract( colours, colour1, colour2, ...)\
8141colours.test( colours, colour )\
8142\
8143Colour constants in the colours api, in ascending bit order:\
8144colours.white, colours.orange, colours.magenta, colours.lightBlue, colours.yellow, colours.lime, colours.pink, colours.grey, colours.lightGrey, colours.cyan, colours.purple, colours.blue, colours.brown, colours.green, colours.red, colours.black.",
8145 refuel = "refuel is a program for Turtles. Refuel will consume items from the inventory as fuel for turtle.\
8146\
8147ex:\
8148\"refuel\" will refuel with at most one fuel item\
8149\"refuel 10\" will refuel with at most 10 fuel items\
8150\"refuel all\" will refuel with as many fuel items as possible",
8151 earth = "Mostly harmless.",
8152 copy = "cp copies a file or directory from one location to another.\
8153\
8154ex:\
8155\"cp rom myrom\" copies \"rom\" to \"myrom\".\
8156\"cp rom mystuff/rom\" copies \"rom\" to \"mystuff/rom\".\
8157\"cp disk/* disk2\" copies the contents of one disk to another\
8158",
8159 os = "Functions in the os (Operating System) API:\
8160os.version()\
8161os.getComputerID()\
8162os.getComputerLabel()\
8163os.setComputerLabel()\
8164os.run( environment, programpath, arguments )\
8165os.loadAPI( path )\
8166os.unloadAPI( name )\
8167os.pullEvent( [filter] )\
8168os.queueEvent( event, arguments )\
8169os.clock()\
8170os.startTimer( timeout )\
8171os.cancelTimer( token )\
8172os.sleep( timeout )\
8173os.time()\
8174os.day()\
8175os.setAlarm( time )\
8176os.cancelAlarm( token )\
8177os.shutdown()\
8178os.reboot()\
8179\
8180Events emitted by the os API:\
8181\"timer\" when a timeout started by os.startTimer() completes. Argument is the token returned by os.startTimer().\
8182\"alarm\" when a time passed to os.setAlarm() is reached. Argument is the token returned by os.setAlarm().\
8183Type \"help events\" to learn about the event system.",
8184 list = "ls will list all the directories and files in the current location. Use \"type\" to find out if an item is a file or a directory.",
8185 bg = "bg is a program for Advanced Computers which opens a new tab in the background.\
8186\
8187ex:\
8188\"bg\" will open a background tab running the shell\
8189\"bg worm\" will open a background tab running the \"worm\" program\
8190",
8191 rs = "Functions in the Redstone API:\
8192rs.getSides( )\
8193rs.getInput( side )\
8194rs.setOutput( side, boolean )\
8195rs.getOutput( side )\
8196rs.getAnalogInput( side )\
8197rs.setAnalogOutput( side, number )\
8198rs.getAnalogOutput( side )\
8199\
8200Functions in the Redstone API for working with RedPower bundled cables:\
8201rs.getBundledInput( side )\
8202rs.testBundledInput( side, color )\
8203rs.setBundledOutput( side, colors )\
8204rs.getBundledOutput( side )\
8205Type \"help bundled\" for usage examples.\
8206\
8207Events emitted by the redstone API:\
8208\"redstone\", when the state of any redstone input changes. Use getInput() or getBundledInput() to inspect the changes\
8209Type \"help events\" to learn about the event system.\
8210",
8211 multishell = "multishell is the toplevel program on Advanced Computers which manages background tabs.\
8212Type \"help shellapi\" for information about the shell lua api.",
8213 move = "mv moves a file or directory from one location to another.\
8214\
8215ex:\
8216\"mv foo bar\" renames the file \"foo\" to \"bar\".\
8217\"mv foo bar/foo\" moves the file \"foo\" to a folder called \"bar\".\
8218\"mv disk/* disk2\" moves the contents of one disk to another\
8219",
8220 disk = "Functions in the disk API. These functions are for interacting with disk drives:\
8221disk.isPresent( drive )\
8222disk.setLabel( drive, label )\
8223disk.getLabel( drive )\
8224disk.hasData( drive )\
8225disk.getMountPath( drive )\
8226disk.hasAudio( drive )\
8227disk.getAudioTitle( drive )\
8228disk.playAudio( drive )\
8229disk.stopAudio( )\
8230disk.eject( drive )\
8231disk.getID( drive )\
8232\
8233Events fired by the disk API:\
8234\"disk\" when a disk or other item is inserted into a disk drive. Argument is the name of the drive\
8235\"disk_eject\" when a disk is removed from a disk drive. Argument is the name of the drive\
8236Type \"help events\" to learn about the event system.",
8237 unequip = "unequip is a program for Turtles. unequip will remove tools of peripherals from the specified side of the turtle.\
8238\
8239ex:\
8240\"unequip left\" will remove the item on the left side of the turtle\
8241",
8242 io = "io is a standard Lua5.1 API, reimplemented for CraftOS. Not all the features are availiable.\
8243Refer to http://www.lua.org/manual/5.1/ for more information.",
8244 helpapi = "Functions in the help API:\
8245help.setPath( path )\
8246help.lookup( topic )\
8247help.topics()\
8248",
8249 redstone = "The redstone program can be used to get, set or pulse redstone inputs and outputs from the computer.\
8250\
8251ex:\
8252\"redstone probe\" will list all the redstone inputs to the computer\
8253\"redstone set left true\" turns on the left redstone output.\
8254\"redstone set right blue false\" turns off the blue wire in the bundled cable on the right redstone output.\
8255\"redstone pulse front 10 1\" emits 10 one second redstone pulses on the front redstone output.\
8256\
8257Type \"help redstoneapi\" or \"help rs\" for information on the redstone Lua API.",
8258 shellapi = "Functions in the Shell API:\
8259shell.exit()\
8260shell.dir()\
8261shell.setDir( path )\
8262shell.path()\
8263shell.setPath( path )\
8264shell.resolve( localpath )\
8265shell.resolveProgram( name )\
8266shell.aliases()\
8267shell.setAlias( alias, command )\
8268shell.clearAlias( alias )\
8269shell.programs()\
8270shell.run( program, arguments )\
8271shell.getRunningProgram()\
8272shell.openTab( program, arguments ) (Advanced Computer required)\
8273shell.switchTab( n ) (Advanced Computer required)\
8274",
8275 go = "go is a program for Turtles, used to control the turtle without programming. It accepts one or more commands as a direction followed by a distance.\
8276\
8277ex:\
8278\"go forward\" moves the turtle 1 space forward.\
8279\"go forward 3\" moves the turtle 3 spaces forward.\
8280\"go forward 3 up left 2\" moves the turtle 3 spaces forward, 1 spaces up, then left 180 degrees.\
8281",
8282 programs = "programs lists all the programs on the rom of the computer.\
8283",
8284 dj = "dj plays Music Discs from disk drives attached to the computer.\
8285\
8286ex:\
8287\"dj\" or \"dj play\" plays a random disc.\
8288\"dj play left\" plays the disc in the drive on the left of the computer.\
8289\"dj stop\" stops the current disc.",
8290 chat = "Surf the rednet superhighway with \"chat\", the networked chat program for CraftOS! Host chatrooms and invite your friends! Requires a Wired or Wireless Modem on each computer. When running chat, type \"/help\" to see a list of available commands.\
8291\
8292ex:\
8293\"chat host forgecraft\" will create a chatroom with the name \"forgecraft\"\
8294\"chat join forgecraft direwolf20\" will connect to the chatroom with the name \"forgecraft\", using the nickname \"direwolf20\"",
8295 intro = "Welcome to CraftOS!\
8296Type \"programs\" to see the programs you can run.\
8297Type \"help <program>\" to see help for a specific program.\
8298Type \"help programming\" to learn about programming.\
8299Type \"help whatsnew\" to find out about new features.\
8300Type \"help credits\" to learn who made all this.\
8301Type \"help index\" to see all help topics.\
8302",
8303 keys = "The keys API contains constants for all the key codes that can be returned by the \"key\" event:\
8304\
8305Example usage:\
8306local sEvent, nKey = os.pullEvent()\
8307if sEvent == \"key\" and nKey == keys.enter then\
8308 -- Do something \
8309end\
8310\
8311See http://www.minecraftwiki.net/wiki/Key_codes, or the source code, for a complete reference.",
8312 coroutine = "coroutine is a standard Lua5.1 API.\
8313Refer to http://www.lua.org/manual/5.1/ for more information.",
8314 textutils = "Functions in the Text Utilities API:\
8315textutils.slowPrint( text )\
8316textutils.tabulate( table, table2, ... )\
8317textutils.pagedTabulate( table, table2, ... )\
8318textutils.formatTime( time, bTwentyFourHour )\
8319textutils.serialize( table )\
8320textutils.unserialize( string )\
8321textutils.serializeJSON( table )\
8322textutils.urlEncode( string )",
8323 clear = "clear clears the screen.",
8324 delete = "rm deletes a file or a directory and its contents.\
8325\
8326ex:\
8327\"rm foo\" will delete the file foo.\
8328\"rm disk/*\" will delete the contents of a disk.\
8329",
8330 gpsapi = "Functions in the GPS API:\
8331gps.locate( timeout )\
8332\
8333The locate function will send a signal to nearby gps servers, and wait for responses before the timeout. If it receives enough responses to determine this computers position then x, y and z co-ordinates will be returned, otherwise it will return nil. If GPS hosts do not have their positions configured correctly, results will be inaccurate.",
8334 craft = "craft is a program for Crafty Turtles. Craft will craft a stack of items using the current inventory.\
8335\
8336ex:\
8337\"craft\" will craft as many items as possible\
8338\"craft 5\" will craft at most 5 times\
8339",
8340 falling = "\"From Russia with Fun\" comes a fun, new, suspiciously-familiar falling block game for CraftOS. Only on Pocket Computers!\
8341",
8342 rednet = "The rednet API provides a simple computer networking model using modems.\
8343\
8344Functions in the rednet API:\
8345rednet.open( side )\
8346rednet.close( [side] )\
8347rednet.isOpen( [side] )\
8348rednet.send( receiverID, message, [protocol] ) -- Send to a specific computer\
8349rednet.broadcast( message, [protocol] ) -- Send to all computers\
8350rednet.receive( [protocol], [timeout] ) -- Returns: senderID, message, protocol\
8351rednet.host( protocol, hostname )\
8352rednet.unhost( protocol )\
8353rednet.lookup( protocol, [hostname] ) -- Returns: ID\
8354\
8355Events fired by the rednet API:\
8356\"rednet_message\" when a message is received. Arguments are senderID, message, protocol\
8357Type \"help events\" to learn about the event system.\
8358\
8359Rednet is not the only way to use modems for networking. Interfacing with the modem directly using the peripheral API and listening for the \"modem_message\" event allows for lower level control, at the expense of powerful high level networking features.\
8360",
8361 events = "The function os.pullEvent() will yield the program until a system event occurs. The first return value is the event name, followed by any arguments.\
8362\
8363Some events which can occur are:\
8364\"char\" when text is typed on the keyboard. Argument is the letter typed.\
8365\"key\" when a key is pressed on the keyboard. Argument is the numerical keycode. Compare to the values in keys API to see which key was pressed.\
8366\"paste\" when text is pasted from the users keyboard. Argument is the line of text pasted.\
8367\
8368Events only on advanced computers:\
8369\"mouse_click\" when a user clicks the mouse. Arguments are button, xPos, yPos.\
8370\"mouse_drag\" when a user moves the mouse when held. Arguments are button, xPos, yPos.\
8371\"mouse_scroll\" when a user uses the scrollwheel on the mouse. Arguments are direction, xPos, yPos.\
8372\
8373Other APIs and peripherals will emit their own events. See their respective help pages for details.\
8374",
8375 printers = "The Printer is a peripheral device available for CraftOS. Type \"help peripheral\" to learn about using the Peripheral API to connect with peripherals. When a Printer is connected, peripheral.getType() will return \"printer\".\
8376\
8377Methods exposed by the Printer:\
8378getInkLevel()\
8379getPaperLevel()\
8380newPage()\
8381setPageTitle( title )\
8382getPageSize()\
8383setCursorPos( x, y )\
8384getCursorPos()\
8385write( text )\
8386endPage()",
8387 exec = "On a Command Computer, \"exec\" will execute a command as if entered on a command block. Use \"commands\" to list all the available commands.\
8388\
8389ex:\
8390\"exec say Hello World\"\
8391\"exec setblock ~0 ~1 ~0 minecraft:dirt\"\
8392\
8393Type \"help commandsapi\" for help using commands in lua programs.\
8394",
8395 rename = "rename renames a file or directory.\
8396\
8397ex:\
8398\"rename foo bar\" renames the file \"foo\" to \"bar\".\
8399",
8400 string = "string is a standard Lua5.1 API.\
8401Refer to http://www.lua.org/manual/5.1/ for more information.",
8402 redirection = "Redirection ComputerCraft Edition is the CraftOS version of a fun new puzzle game by Dan200, the author of ComputerCraft.\
8403Play it on any Advanced Computer, then visit http://www.redirectiongame.com to play the full game!\
8404",
8405 parallel = "Functions in the Parallel API:\
8406parallel.waitForAny( function1, function2, ... )\
8407parallel.waitForAll( function1, function2, ... )\
8408These methods provide an easy way to run multiple lua functions simultaneously.",
8409 fg = "fg is a program for Advanced Computers which opens a new tab in the foreground.\
8410\
8411ex:\
8412\"fg\" will open a foreground tab running the shell\
8413\"fg worm\" will open a foreground tab running the \"worm\" program\
8414",
8415 table = "table is a standard Lua5.1 API.\
8416Refer to http://www.lua.org/manual/5.1/ for more information.",
8417 workbench = "Workbenches are peripheral devices found on Crafty Turtles running CraftOS. Type \"help peripheral\" to learn about using the Peripheral API to connect with peripherals. When a workbench is attached to a turtle, peripheral.getType() will return \"workbench\".\
8418\
8419Methods exposed by Workbenches:\
8420craft( channel )\
8421",
8422 window = "Functions in the window API:\
8423window.create( parent, x, y, width, height, visible )\
8424\
8425Windows created with the window API have the following methods:\
8426write( text )\
8427clear()\
8428clearLine()\
8429getCursorPos()\
8430setCursorPos( x, y )\
8431setCursorBlink( blink )\
8432isColor()\
8433setTextColor( color )\
8434setBackgroundColor( color )\
8435getSize()\
8436scroll( n )\
8437setVisible( bVisible )\
8438redraw()\
8439restoreCursor()\
8440getPosition()\
8441reposition( x, y, width, height )\
8442",
8443 whatsnew = "New Features in ComputerCraft 1.73:\
8444\
8445* The \"exec\" program, commands.exec() and all related Command Computer functions now return the console output of the command.\
8446* Fixed two multiplayer crash bugs.\
8447\
8448Type \"help changelog\" to see the full version history.\
8449",
8450 credits = "ComputerCraft was created by Daniel \"dan200\" Ratcliffe, with additional code by Aaron \"Cloudy\" Mills.\
8451Thanks to nitrogenfingers, GopherATL and RamiLego for program contributions.\
8452Thanks to Mojang, the Forge team, and the MCP team.\
8453Uses LuaJ from http://luaj.sourceforge.net/\
8454\
8455Join the ComputerCraft community online at http://www.computercraft.info\
8456Follow @DanTwoHundred on Twitter!\
8457",
8458 vector = "Functions in the 3D Vector Math API:\
8459vector.new( x,y,z )\
8460\
8461Vectors returned by vector.new() have the following fields and methods:\
8462vector.x\
8463vector.y\
8464vector.z\
8465vector:add( vector )\
8466vector:sub( vector )\
8467vector:mul( number )\
8468vector:dot( vector )\
8469vector:cross( vector )\
8470vector:length()\
8471vector:normalize()\
8472vector:round()\
8473vector:tostring()\
8474The +, - and * operators can also be used on vectors.\
8475",
8476 type = "type determines the type of a file or directory. Prints \"file\", \"directory\" or \"does not exist\".",
8477 cd = "cd changes the the directory you're in.\
8478\
8479ex:\
8480\"cd rom\" will move to \"rom\" folder.\
8481\"cd ..\" will move up one folder.\
8482\"cd /\" will move to the root.",
8483 edit = "edit is a text editor for creating or modifying programs or text files. After creating a program with edit, type its filename in the shell to run it. You can open any of the builtin programs with edit to learn how to program.\
8484\
8485ex:\
8486\"edit hello\" opens a file called \"hello\" for editing.",
8487 turn = "turn is a program for Turtles, used to turn the turtle around without programming. It accepts one or more commands as a direction and a number of turns. The \"go\" program can also be used for turning.\
8488\
8489ex:\
8490\"turn left\" turns the turtle 90 degrees left.\
8491\"turn right 2\" turns the turtle 180 degrees right.\
8492\"turn left 2 right\" turns left 180 degrees, then right 90 degrees.\
8493",
8494 tunnel = "tunnel is a program for Mining Turtles. Tunnel will mine a 3x2 tunnel of the depth specified.\
8495\
8496ex:\
8497\"tunnel 20\" will tunnel a tunnel 20 blocks long.\
8498",
8499 time = "time prints the current time of day.",
8500 term = "Functions in the Terminal API:\
8501term.write( text )\
8502term.clear()\
8503term.clearLine()\
8504term.getCursorPos()\
8505term.setCursorPos( x, y )\
8506term.setCursorBlink( blink )\
8507term.isColor()\
8508term.setTextColor( color )\
8509term.setBackgroundColor( color )\
8510term.getSize()\
8511term.scroll( n )\
8512term.redirect( object )\
8513term.current()\
8514\
8515Events emitted by the terminals:\
8516\"term_resize\", when the size of a terminal changes. This can happen in multitasking environments, or when the terminal out is being redirected by the \"monitor\" program.\
8517",
8518 peripheral = "The peripheral API is for interacting with external peripheral devices. Type \"help peripherals\" to learn about the peripherals available.\
8519\
8520Functions in the peripheral API:\
8521peripheral.getNames()\
8522peripheral.isPresent( name )\
8523peripheral.getType( name )\
8524peripheral.getMethods( name )\
8525peripheral.call( name, methodName, param1, param2, etc )\
8526peripheral.wrap( name )\
8527peripheral.find( type, [fnFilter] )\
8528\
8529Events fired by the peripheral API:\
8530\"peripheral\" when a new peripheral is attached. Argument is the name.\
8531\"peripheral_detach\" when a peripheral is removed. Argument is the name.\
8532Type \"help events\" to learn about the event system.\
8533",
8534 eject = "eject ejects the contents of an attached disk drive.\
8535\
8536ex:\
8537\"eject left\" ejects the contents of the disk drive to the left of the computer.\
8538",
8539 shell = "shell is the toplevel program which interprets commands and runs program.\
8540Type \"help shellapi\" for information about the shell lua api.",
8541 shutdown = "shutdown will turn off the computer.",
8542 reboot = "reboot will turn the computer off and on again.\
8543You can also hold Ctrl+R at any time to quickly reboot.",
8544 [ "repeat" ] = "repeat is a program for repeating rednet messages across long distances. To use, connect 2 or more modems to a computer and run the \"repeat\" program; from then on, any rednet message sent from any computer in wireless range or connected by networking cable to either of the modems will be repeated to those on the other side.",
8545 peripherals = "Peripherals are external devices which CraftOS Computers and Turtles can interact with using the peripheral API.\
8546Type \"help peripheral\" to learn about using the peripheral API.\
8547Type \"help drives\" to learn about using Disk Drives.\
8548Type \"help modems\" to learn about using Wireless Modems.\
8549Type \"help monitors\" to learn about using Monitors.\
8550Type \"help printers\" to learn about using Printers.\
8551",
8552 bit = "Functions in the bit manipulation API:\
8553bit.bnot(n) -- bitwise not (~n)\
8554bit.band(m, n) -- bitwise and (m & n)\
8555bit.bor(m, n) -- bitwise or (m | n)\
8556bit.bxor(m, n) -- bitwise xor (m ^ n)\
8557bit.brshift(n, bits) -- right shift (n >> bits)\
8558bit.blshift(n, bits) -- left shift (n << bits)\
8559",
8560 sleep = "sleep makes the computer idle for a specific number of seconds.\
8561\
8562ex:\
8563\"sleep 10\" puts the computer to sleep for 10 seconds",
8564 pastebin = "pastebin is a program for uploading files to and downloading files from pastebin.com. This is useful for sharing programs with other players.\
8565The HTTP API must be enabled in ComputerCraft.cfg to use this program.\
8566\
8567ex:\
8568\"pastebin put foo\" will upload the file \"foo\" to pastebin.com, and print the URL.\
8569\"pastebin get xq5gc7LB foo\" will download the file from the URL http://pastebin.com/xq5gc7LB, and save it as \"foo\".\
8570\"pastebin run CxaWmPrX\" will download the file from the URL http://pastebin.com/CxaWmPrX, and immediately run it.\
8571",
8572 worm = "You've played it in the arcades, now experience the high-octane thrills of the hit game \"WORM!\" on your home computer! Only on CraftOS!\
8573",
8574 label = "label gets or sets the label of the Computer, or of Floppy Disks in attached disk drives.\
8575\
8576ex:\
8577\"label get\" prints the label of the computer.\
8578\"label get left\" prints the label of the disk in the left drive.\
8579\"label set \"My Computer\"\" set the label of the computer to \"My Computer\".\
8580\"label set left \"My Programs\"\" - sets the label of the disk in the left drive to \"My Programs\".\
8581\"label clear\" clears the label of the computer.\
8582\"label clear left\" clears the label of the disk in the left drive.\
8583",
8584 commandsapi = "Functions in the commands API:\
8585commands.exec( command )\
8586commands.execAsync( command )\
8587commands.list()\
8588commands.getBlockPosition()\
8589commands.getBlockInfo( x, y, z )\
8590\
8591The commands API can also be used to invoke commands directly, like so:\
8592commands.say( \"Hello World\" )\
8593commands.give( \"dan200\", \"minecraft:diamond\", 64 )\
8594This works with any command. Use \"commands.async\" instead of \"commands\" to execute asynchronously.\
8595\
8596The commands API is only available on Command Computers.\
8597Visit http://minecraft.gamepedia.com/Commands for documentation on all commands.\
8598",
8599 paintutils = "Functions in the Paint Utilities API:\
8600paintutils.drawPixel( x, y, colour )\
8601paintutils.drawLine( startX, startY, endX, endY, colour )\
8602paintutils.drawBox( startX, startY, endX, endY, colour )\
8603paintutils.drawFilledBox( startX, startY, endX, endY, colour )\
8604paintutils.loadImage( path )\
8605paintutils.drawImage( image, x, y )\
8606",
8607 modems = "Wired and Wireless Modems are peripheral devices available for CraftOS. Type \"help peripheral\" to learn about using the Peripheral API to connect with peripherals. When a Modem is connected, peripheral.getType() will return \"modem\".\
8608\
8609Methods exposed by Modems:\
8610open( channel )\
8611isOpen( channel )\
8612close( channel )\
8613closeAll()\
8614transmit( channel, replyChannel, message )\
8615isWireless()\
8616\
8617Events fired by Modems:\
8618\"modem_message\" when a message is received on an open channel. Arguments are name, channel, replyChannel, message, distance",
8619 changelog = "New Features in ComputerCraft 1.73:\
8620\
8621* The \"exec\" program, commands.exec() and all related Command Computer functions now return the console output of the command.\
8622* Fixed two multiplayer crash bugs.\
8623\
8624New Features in ComputerCraft 1.7:\
8625\
8626* Added Command Computers\
8627* Added new API: commands\
8628* Added new programs: commands, exec\
8629* Added textutils.serializeJSON()\
8630* Added ILuaContext.executeMainThreadTask() for peripheral developers\
8631* Disk Drives and Printers can now be renamed with Anvils\
8632* Fixed various bugs, crashes and exploits\
8633* Fixed problems with HD texture packs\
8634* Documented the new features in the in-game help\
8635\
8636New Features in ComputerCraft 1.65:\
8637\
8638* Fixed a multiplayer-only crash with turtle.place()\
8639* Fixed some problems with http.post()\
8640* Fixed fs.getDrive() returning incorrect results on remote peripherals\
8641\
8642New Features in ComputerCraft 1.64:\
8643\
8644* Ported to Minecraft 1.7.10\
8645* New turtle functions: turtle.inspect(), turtle.inspectUp(), turtle.inspectDown(), turtle.getItemDetail()\
8646* Lots of bug and crash fixes, a huge stability improvement over previous versions\
8647\
8648New Features in ComputerCraft 1.63:\
8649\
8650* Turtles can now be painted with dyes, and cleaned with water buckets\
8651* Added a new game: Redirection - ComputerCraft Edition\
8652* Turtle label nameplates now only show when the Turtle is moused-over\
8653* The HTTP API is now enabled by default, and can be configured with a whitelist of permitted domains\
8654* http.get() and http.post() now accept parameters to control the request headers\
8655* New fs function: fs.getDir( path )\
8656* Fixed some bugs\
8657\
8658New Features in ComputerCraft 1.62:\
8659\
8660* Added IRC-style commands to the \"chat\" program\
8661* Fixed some bugs and crashes\
8662\
8663New Features in ComputerCraft 1.6:\
8664\
8665* Added Pocket Computers\
8666* Added a multi-tasking system for Advanced Computers and Turtles\
8667* Turtles can now swap out their tools and peripherals at runtime\
8668* Turtles can now carry two tools or peripherals at once in any combination\
8669* Turtles and Computers can now be labelled using Name Tags and Anvils\
8670* Added a configurable fuel limit for Turtles\
8671* Added hostnames, protocols and long distance routing to the rednet API\
8672* Added a peer-to-peer chat program to demonstrate new rednet capabilities\
8673* Added a new game, only on Pocket Computers: \"falling\" by GopherATL\
8674* File system commands in the shell now accept wildcard arguments\
8675* The shell now accepts long arguments in quotes\
8676* Terminal redirection now no longer uses a stack-based system. Instead: term.current() gets the current terminal object and term.redirect() replaces it. term.restore() has been removed.\
8677* Added a new Windowing API for addressing sub-areas of the terminal\
8678* New programs: fg, bg, multishell, chat, repeat, redstone, equip, unequip\
8679* Improved programs: copy, move, delete, rename, paint, shell\
8680* Removed programs: redset, redprobe, redpulse\
8681* New APIs: window, multishell\
8682* New turtle functions: turtle.equipLeft() and turtle.equipRight()\
8683* New peripheral functions: peripheral.find( [type] )\
8684* New rednet functions: rednet.host( protocol, hostname ), rednet.unhost( protocol ), rednet.locate( protocol, [hostname] )\
8685* New fs function: fs.find( wildcard )\
8686* New shell functions: shell.openTab(), shell.switchTab( [number] )\
8687* New event \"term_resize\" fired when the size of a terminal changes\
8688* Improved rednet functions: rednet.send(), rednet.broadcast() and rednet.receive() now take optional protocol parameters\
8689* turtle.craft(0) and turtle.refuel(0) now return true if there is a valid recipe or fuel item, but do not craft of refuel anything\
8690* turtle.suck( [limit] ) can now be used to limit the number of items picked up\
8691* Users of turtle.dig() and turtle.attack() can now specify which side of the turtle to look for a tool to use (by default, both will be considered)\
8692* textutils.serialise( text ) now produces human-readable output\
8693* Refactored most of the codebase and fixed many old bugs and instabilities, turtles should never ever lose their content now\
8694* Fixed the \"turtle_inventory\" event firing when it shouldn't have\
8695* Added error messages to many more turtle functions after they return false\
8696* Documented all new programs and API changes in the \"help\" system\
8697\
8698New Features in ComputerCraft 1.58:\
8699\
8700* Fixed a long standing bug where turtles could lose their identify if they travel too far away\
8701* Fixed use of deprecated code, ensuring mod compatibility with the latest versions of Minecraft Forge, and world compatibility with future versions of Minecraft\
8702\
8703New Features in ComputerCraft 1.57:\
8704\
8705* Ported to Minecraft 1.6.4\
8706* Added two new Treasure Disks: Conway’s Game of Life by vilsol and Protector by fredthead\
8707* Fixed a very nasty item duplication bug\
8708\
8709New Features in ComputerCraft 1.56:\
8710\
8711* Added Treasure Disks: Floppy Disks in dungeons which contain interesting community made programs. Find them all!\
8712* All turtle functions now return additional error messages when they fail.\
8713* Resource Packs with Lua Programs can now be edited when extracted to a folder, for easier editing.\
8714\
8715New Features in ComputerCraft 1.55:\
8716\
8717* Ported to Minecraft 1.6.2\
8718* Added Advanced Turtles\
8719* Added \"turtle_inventory\" event. Fires when any change is made to the inventory of a turtle\
8720* Added missing functions io.close, io.flush, io.input, io.lines, io.output\
8721* Tweaked the screen colours used by Advanced Computers, Monitors and Turtles\
8722* Added new features for Peripheral authors\
8723* Lua programs can now be included in Resource Packs\
8724\
8725New Features in ComputerCraft 1.52:\
8726\
8727* Ported to Minecraft 1.5.1\
8728\
8729New Features in ComputerCraft 1.51:\
8730\
8731* Ported to Minecraft 1.5\
8732* Added Wired Modems\
8733* Added Networking Cables\
8734* Made Wireless Modems more expensive to craft\
8735* New redstone API functions: getAnalogInput(), setAnalogOutput(), getAnalogOutput()\
8736* Peripherals can now be controlled remotely over wired networks. New peripheral API function: getNames()\
8737* New event: \"monitor_resize\" when the size of a monitor changes\
8738* Except for labelled computers and turtles, ComputerCraft blocks no longer drop items in creative mode\
8739* The pick block function works in creative mode now works for all ComputerCraft blocks\
8740* All blocks and items now use the IDs numbers assigned by FTB by default\
8741* Fixed turtles sometimes placing blocks with incorrect orientations\
8742* Fixed Wireless modems being able to send messages to themselves\
8743* Fixed turtle.attack() having a very short range\
8744* Various bugfixes\
8745\
8746New Features in ComputerCraft 1.5:\
8747\
8748* Redesigned Wireless Modems; they can now send and receive on multiple channels, independent of the computer ID. To use these features, interface with modem peripherals directly. The rednet API still functions as before\
8749* Floppy Disks can now be dyed with multiple dyes, just like armour\
8750* The \"excavate\" program now retains fuel in it's inventory, so can run unattended\
8751* turtle.place() now tries all possible block orientations before failing\
8752* turtle.refuel(0) returns true if a fuel item is selected\
8753* turtle.craft(0) returns true if the inventory is a valid recipe\
8754* The in-game help system now has documentation for all the peripherals and their methods, including the new modem functionality\
8755* A romantic surprise\
8756\
8757New Features in ComputerCraft 1.48:\
8758\
8759* Ported to Minecraft 1.4.6\
8760* Advanced Monitors now emit a \"monitor_touch\" event when right clicked\
8761* Advanced Monitors are now cheaper to craft\
8762* Turtles now get slightly less fuel from items\
8763* Computers can now interact with Command Blocks (if enabled in ComputerCraft.cfg)\
8764* New API function: os.day()\
8765* A christmas surprise\
8766\
8767New Features in ComputerCraft 1.45:\
8768\
8769* Added Advanced Computers\
8770* Added Advanced Monitors\
8771* New program: paint by nitrogenfingers\
8772* New API: paintutils\
8773* New term functions: term.setBackgroundColor, term.setTextColor, term.isColor\
8774* New turtle function: turtle.transferTo\
8775\
8776New Features in ComputerCraft 1.43:\
8777\
8778* Added Printed Pages\
8779* Added Printed Books\
8780* Fixed incompatibility with Forge 275 and above\
8781* Labelled Turtles now keep their fuel when broken\
8782\
8783New Features in ComputerCraft 1.42:\
8784\
8785* Ported to Minecraft 1.3.2\
8786* Added Printers\
8787* Floppy Disks can be dyed different colours\
8788* Wireless Crafty Turtles can now be crafted\
8789* New textures\
8790* New forge config file\
8791* Bug fixes\
8792\
8793New Features in ComputerCraft 1.4:\
8794\
8795* Ported to Forge Mod Loader. ComputerCraft can now be ran directly from the .zip without extraction\
8796* Added Farming Turtles\
8797* Added Felling Turtles\
8798* Added Digging Turtles\
8799* Added Melee Turtles\
8800* Added Crafty Turtles\
8801* Added 14 new Turtle Combinations accessible by combining the turtle upgrades above\
8802* Labelled computers and turtles can now be crafted into turtles or other turtle types without losing their ID, label and data\
8803* Added a \"Turtle Upgrade API\" for mod developers to create their own tools and peripherals for turtles\
8804* Turtles can now attack entities with turtle.attack(), and collect their dropped items\
8805* Turtles can now use turtle.place() with any item the player can, and can interact with entities\
8806* Turtles can now craft items with turtle.craft()\
8807* Turtles can now place items into inventories with turtle.drop()\
8808* Changed the behaviour of turtle.place() and turtle.drop() to only consider the currently selected slot\
8809* Turtles can now pick up items from the ground, or from inventories, with turtle.suck()\
8810* Turtles can now compare items in their inventories\
8811* Turtles can place signs with text on them with turtle.place( [signText] )\
8812* Turtles now optionally require fuel items to move, and can refuel themselves\
8813* The size of the the turtle inventory has been increased to 16\
8814* The size of the turtle screen has been increased\
8815* New turtle functions: turtle.compareTo( [slotNum] ), turtle.craft(), turtle.attack(), turtle.attackUp(), turtle.attackDown(), turtle.dropUp(), turtle.dropDown(), turtle.getFuelLevel(), turtle.refuel()\
8816* New disk function: disk.getID()\
8817* New turtle programs: craft, refuel\
8818* \"excavate\" program now much smarter: Will return items to a chest when full, attack mobs, and refuel itself automatically\
8819* New API: keys\
8820* Added optional Floppy Disk and Hard Drive space limits for computers and turtles\
8821* New fs function: fs.getFreeSpace( path ), also fs.getDrive() works again\
8822* The send and receive range of wireless modems now increases with altitude, allowing long range networking from high-altitude computers (great for GPS networks)\
8823* http.request() now supports https:// URLs\
8824* Right clicking a Disk Drive with a Floppy Disk or a Record when sneaking will insert the item into the Disk Drive automatically\
8825* The default size of the computer screen has been increased\
8826* Several stability and security fixes. LuaJ can now no longer leave dangling threads when a computer is unloaded, turtles can no longer be destroyed by tree leaves or walking off the edge of the loaded map. Computers no longer crash when used with RedPower frames.\
8827\
8828New Features in ComputerCraft 1.31:\
8829\
8830* Ported to Minecraft 1.2.3\
8831* Added Monitors (thanks to Cloudy)\
8832* Updated LuaJ to a newer, less memory hungry version\
8833* rednet_message event now has a third parameter, \"distance\", to support position triangulation.\
8834* New programs: gps, monitor, pastebin.\
8835* Added a secret program. Use with large monitors!\
8836* New apis: gps, vector\
8837* New turtle functions: turtle.compare(), turtle.compareUp(), turtle.compareDown(), turtle.drop( quantity )\
8838* New http functions: http.post().\
8839* New term functions: term.redirect(), term.restore()\
8840* New textutils functions: textutils.urlEncode()\
8841* New rednet functions: rednet.isOpen()\
8842* New config options: modem_range, modem_rangeDuringStorm\
8843* Bug fixes, program tweaks, and help updates\
8844\
8845New Features in ComputerCraft 1.3:\
8846\
8847* Ported to Minecraft Forge\
8848* Added Turtles\
8849* Added Wireless Modems\
8850* Added Mining Turtles\
8851* Added Wireless Turtles\
8852* Added Wireless Mining Turtles\
8853* Computers and Disk Drives no longer get destroyed by water.\
8854* Computers and Turtles can now be labelled with the label program, and labelled devices keep their state when destroyed.\
8855* Computers/Turtles can connect to adjacent devices, and turn them on and off\
8856* User programs now give line numbers in their error messages\
8857* New APIs: turtle, peripheral\
8858* New programs for turtles: tunnel, excavate, go, turn, dance\
8859* New os functions: os.getComputerLabel(), os.setComputerLabel()\
8860* Added \"filter\" parameter to os.pullEvent()\
8861* New shell function: shell.getCurrentProgram()\
8862* New textutils functions: textutils.serialize(), textutils.unserialize(), textutils.tabulate(), textutils.pagedTabulate(), textutils.slowWrite()\
8863* New io file function: file:lines()\
8864* New fs function: fs.getSize()\
8865* Disk Drives can now play records from other mods\
8866* Bug fixes, program tweaks, and help updates\
8867\
8868New Features in ComputerCraft 1.2:\
8869\
8870* Added Disk Drives and Floppy Disks\
8871* Added Ctrl+T shortcut to terminate the current program (hold)\
8872* Added Ctrl+S shortcut to shutdown the computer (hold)\
8873* Added Ctrl+R shortcut to reboot the computer (hold)\
8874* New Programs: alias, apis, copy, delete, dj, drive, eject, id, label, list, move, reboot, redset, rename, time, worm.\
8875* New APIs: bit, colours, disk, help, rednet, parallel, textutils.\
8876* New color functions: colors.combine(), colors.subtract(), colors.test()\
8877* New fs functions: fs.getName(), new modes for fs.open()\
8878* New os functions: os.loadAPI(), os.unloadAPI(),\
8879os.clock(), os.time(), os.setAlarm(),\
8880os.reboot(), os.queueEvent()\
8881* New redstone function: redstone.getSides()\
8882* New shell functions: shell.setPath(), shell.programs(), shell.resolveProgram(), shell.setAlias()\
8883* Lots of updates to the help pages\
8884* Bug fixes\
8885\
8886New Features in ComputerCraft 1.1:\
8887\
8888* Added Multiplayer support throughout.\
8889* Added connectivity with RedPower bundled cables\
8890* Added HTTP api, enabled via the mod config, to allow computers to access the real world internet\
8891* Added command history to the shell.\
8892* Programs which spin in an infinite loop without yielding will no longer freeze minecraft\
8893* Help updates and bug fixes\
8894\
8895New Features in ComputerCraft 1.0:\
8896\
8897* First Release!\
8898",
8899 hello = "hello prints the text \"Hello World!\" to the screen.",
8900 excavate = "excavate is a program for Mining Turtles. When excavate is run, the turtle will mine a rectangular shaft into the ground, collecting blocks as it goes, and return to the surface once bedrock is hit.\
8901\
8902ex:\
8903\"excavate 3\" will mine a 3x3 shaft.\
8904",
8905 dance = "dance is a program for Turtles. Turtles love to get funky.",
8906 paint = "paint is a program for creating images on Advanced Computers. Select colors from the color pallette on the right, and click on the canvas to draw. Press Ctrl to access the menu and save your pictures.\
8907\
8908ex:\
8909\"edit mario\" opens an image called \"mario\" for editing.\
8910",
8911 equip = "equip is a program for Turtles. equip will equip an item from the Turtle's inventory for use as a tool of peripheral.\
8912\
8913ex:\
8914\"equip 5 left\" will equip the item from slot 5 of the turtle onto the left side of the turtle\
8915",
8916 apis = "apis lists the currently loaded APIs available to programs in CraftOS.\
8917\
8918Type \"help <api>\" to see help for a specific api.\
8919Call os.loadAPI( path ) to load extra apis.\
8920",
8921 bundled = "To set bundled outputs:\
8922c = colors.combine( colors.red, colors.blue )\
8923rs.setBundledOutput( \"left\", c )\
8924\
8925c = colors.combine( c, colors.green )\
8926rs.setBundledOutput( \"left\", c )\
8927\
8928c = colors.subtract( c, colors.blue )\
8929rs.setBundledOutput( \"left\", c )\
8930\
8931To get bundled inputs:\
8932c = rs.getBundledInput( \"right\" )\
8933red = colors.test( c, colors.red )\
8934\
8935Type \"help colors\" for the list of wire colors.\
8936",
8937 drives = "The Disk Drive is a peripheral device available for CraftOS. Type \"help peripheral\" to learn about using the Peripheral API to connect with peripherals. When a Disk Drive is connected, peripheral.getType() will return \"drive\".\
8938\
8939Methods exposed by the Disk Drive:\
8940isDiskPresent()\
8941getDiskLabel()\
8942setDiskLabel( label )\
8943hasData()\
8944getMountPath()\
8945hasAudio()\
8946getAudioTitle()\
8947playAudio()\
8948stopAudio()\
8949ejectDisk()\
8950getDiskID()\
8951\
8952Events fired by the Disk Drive:\
8953\"disk\" when a disk or other item is inserted into the drive. Argument is the name of the drive.\
8954\"disk_eject\" when a disk is removed from a drive. Argument is the name of the drive.\
8955Type \"help events\" to learn about the event system.",
8956 gps = "gps can be used to host a GPS server, or to determine a position using trilateration.\
8957Type \"help gpsapi\" for help using GPS functions in lua programs.\
8958\
8959ex:\
8960\"gps locate\" will connect to nearby GPS servers, and try to determine the position of the computer or turtle.\
8961\"gps host\" will try to determine the position, and host a GPS server if successful.\
8962\"gps host 10 20 30\" will host a GPS server, using the manually entered position 10,20,30. \
8963\
8964Take care when manually entering host positions. If the positions entered into multiple GPS hosts\
8965are not consistent, the results of locate calls will be incorrect.",
8966 commands = "On a Command Computer, \"commands\" will list all the commands available for use. Use \"exec\" to execute them.\
8967Type \"help commandsapi\" for help using commands in lua programs.\
8968",
8969 lua = "lua is an interactive prompt for the lua programming language. It's a useful tool for learning the language.",
8970 adventure = "adventure is a text adventure game for CraftOS. To navigate around the world of adventure, type simple instructions to the interpreter, for example: \"go north\", \"punch tree\", \"craft planks\", \"mine coal with pickaxe\", \"hit creeper with sword\"",
8971 id = "id prints the unique identifier of this computer, or a Disk in an attached Disk Drive.\
8972\
8973ex:\
8974\"id\" will print this Computers ID and label\
8975\"id left\" will print the ID and label of the disk in the Disk Drive on the left",
8976 monitors = "The Monitor is a peripheral device available for CraftOS. Type \"help peripheral\" to learn about using the Peripheral API to connect with peripherals. When a Monitor is connected, peripheral.getType() will return \"monitor\". A wrapped monitor can be used with term.redirect() to send all terminal output to the monitor.\
8977\
8978Methods exposed by the Monitor:\
8979write( text )\
8980clear()\
8981clearLine()\
8982getCursorPos()\
8983setCursorPos( x, y )\
8984setCursorBlink( blink )\
8985isColor()\
8986setTextColor( color )\
8987setBackgroundColor( color )\
8988getSize()\
8989scroll( n )\
8990\
8991Events fired by the Monitor:\
8992\"monitor_touch\" when an Advanced Monitor is touched by the player. Arguments are name, x, y\
8993\"monitor_resize\" when the size of a Monitor changes. Argument is the name of the monitor.",
8994 mkdir = "mkdir creates a directory in the current location.\
8995\
8996ex:\
8997\"mkdir foo\" creates a directory named \"foo\".\
8998\"mkdir ../foo\" creates a directory named \"foo\" in the directory above the current directory.",
8999 math = "math is a standard Lua5.1 API.\
9000Refer to http://www.lua.org/manual/5.1/ for more information.",
9001 turtle = "turtle is an api availiable on Turtles, which controls their movement.\
9002Functions in the Turtle API:\
9003turtle.forward()\
9004turtle.back()\
9005turtle.up()\
9006turtle.down()\
9007turtle.turnLeft()\
9008turtle.turnRight()\
9009turtle.select( slotNum )\
9010turtle.getSelectedSlot()\
9011turtle.getItemCount( [slotNum] )\
9012turtle.getItemSpace( [slotNum] )\
9013turtle.getItemDetail( [slotNum] )\
9014turtle.equipLeft()\
9015turtle.equipRight()\
9016turtle.dig( [toolSide] )\
9017turtle.digUp( [toolSide] )\
9018turtle.digDown( [toolSide] )\
9019turtle.place()\
9020turtle.placeUp()\
9021turtle.placeDown()\
9022turtle.attack( [toolSide] )\
9023turtle.attackUp( [toolSide] )\
9024turtle.attackDown( [toolSide] )\
9025turtle.detect()\
9026turtle.detectUp()\
9027turtle.detectDown()\
9028turtle.compare()\
9029turtle.compareUp()\
9030turtle.compareDown()\
9031turtle.inspect()\
9032turtle.inspectUp()\
9033turtle.inspectDown()\
9034turtle.inspectSlot( [slotNum] )\
9035turtle.compareTo( slotNum )\
9036turtle.transferTo( slotNum, [quantity] )\
9037turtle.drop( [quantity] )\
9038turtle.dropUp( [quantity] )\
9039turtle.dropDown( [quantity] )\
9040turtle.suck( [quantity] )\
9041turtle.suckUp( [quantity] )\
9042turtle.suckDown( [quantity] )\
9043turtle.getFuelLevel()\
9044turtle.getFuelLimit()\
9045turtle.refuel( [quantity] )\
9046turtle.craft( [quantity] ) (requires Crafty Turtle)\
9047\
9048Events fired by the Turtle API:\
9049\"turtle_inventory\" when any of the items in the inventory are changed. Use comparison operations to inspect the changes.\
9050",
9051 licenses = {
9052 luaj = "Copyright (c) 2007 LuaJ. All rights reserved.\
9053\
9054Permission is hereby granted, free of charge, to any person obtaining a copy\
9055of this software and associated documentation files (the \"Software\"), to deal\
9056in the Software without restriction, including without limitation the rights\
9057to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\
9058copies of the Software, and to permit persons to whom the Software is\
9059furnished to do so, subject to the following conditions:\
9060\
9061The above copyright notice and this permission notice shall be included in\
9062all copies or substantial portions of the Software.\
9063\
9064THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\
9065IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\
9066FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\
9067AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\
9068LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\
9069OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\
9070THE SOFTWARE.\
9071",
9072 },
9073 colors = "Functions in the colors api\
9074(used for redstone.setBundledOutput):\
9075colors.combine( color1, color2, color3, ... )\
9076colors.subtract( colors, color1, color2, ... )\
9077colors.test( colors, color )\
9078\
9079Color constants in the colors api, in ascending bit order:\
9080colors.white, colors.orange, colors.magenta, colors.lightBlue, colors.yellow, colors.lime, colors.pink, colors.gray, colors.lightGray, colors.cyan, colors.purple, colors.blue, colors.brown, colors.green, colors.red, colors.black.",
9081 http = "Functions in the HTTP API:\
9082http.checkURL( url )\
9083http.request( url, [postData], [headers] )\
9084http.get( url, [headers] )\
9085http.post( url, postData, [headers] )\
9086\
9087The HTTP API may be disabled in ComputerCraft.cfg\
9088A period of time after a http.request() call is made, a \"http_success\" or \"http_failure\" event will be raised. Arguments are the url and a file handle if successful. http.get() and http.post() block until this event fires instead.\
9089",
9090 help = "help is the help tool you're currently using.\
9091Type \"help index\" to see all help topics.\
9092Type \"help\" to see the help intro.\
9093Type \"help helpapi\" for information on the help Lua API.",
9094 drive = "drive tells you which disk drive the current or specified directory is located in.\
9095\
9096ex:\
9097\"drive\" tell you the disk drive of the current directory.\
9098\"drive foo\" tells you the disk drive of the subdirectory \"foo\"",
9099 alias = "alias assigns shell commands to run other programs.\
9100\
9101ex:\
9102\"alias dir ls\" will make the \"dir\" command run the \"ls\" program\
9103\"alias dir\" will remove the alias set on \"dir\"\
9104\"alias\" will list all current aliases.",
9105 programming = "To learn the lua programming language, visit http://lua-users.org/wiki/TutorialDirectory.\
9106\
9107To experiment with lua in CraftOS, run the \"lua\" program and start typing code.\
9108To create programs, use \"edit\" to create files, then type their names in the shell to run them. If you name a program \"startup\" and place it in the root or on a disk drive, it will run automatically when the computer starts.\
9109\
9110To terminate a program stuck in a loop, hold Ctrl+T for 1 second.\
9111To quickly shutdown a computer, hold Ctrl+S for 1 second.\
9112To quickly reboot a computer, hold Ctrl+R for 1 second.\
9113\
9114To learn about the programming APIs availiable, type \"apis\" or \"help apis\".\
9115If you get stuck, visit the forums at http://www.computercraft.info/ for advice and tutorials.",
9116 },
9117 autorun = {
9118 [ ".ignoreme" ] = "--[[\
9119Alright then, don't ignore me. This file is to ensure the existance of the \"autorun\" folder, files placed in this folder\
9120using resource packs will always run when computers startup.\
9121]]",
9122 },
9123 apis = {
9124 colours = "-- Colours (for lovers of british spelling)\
9125local fnFile, err = loadfile(\"/rom/apis/colors\")\
9126if not fnFile then\
9127 error( err )\
9128end\
9129\
9130local tColors = {}\
9131setmetatable( tColors, { __index = _G } )\
9132setfenv( fnFile, tColors )\
9133fnFile( tColors )\
9134\
9135local tColours = getfenv()\
9136for k,v in pairs( tColors ) do\
9137 tColours[k] = v\
9138end\
9139\
9140tColours.gray = nil\
9141tColours.grey = tColors.gray\
9142\
9143tColours.lightGray = nil\
9144tColours.lightGrey = tColors.lightGray\
9145",
9146 parallel = "\
9147local function create( first, ... )\
9148 if first ~= nil then\
9149 if type( first ) ~= \"function\" then\
9150 error( \"Expected function, got \"..type( first ), 3 )\
9151 end\
9152 return coroutine.create(first), create( ... )\
9153 end\
9154 return nil\
9155end\
9156\
9157local function runUntilLimit( _routines, _limit )\
9158 local count = #_routines\
9159 local living = count\
9160 \
9161 local tFilters = {}\
9162 local eventData = {}\
9163 while true do\
9164 for n=1,count do\
9165 local r = _routines[n]\
9166 if r then\
9167 if tFilters[r] == nil or tFilters[r] == eventData[1] or eventData[1] == \"terminate\" then\
9168 local ok, param = coroutine.resume( r, unpack(eventData) )\
9169 if not ok then\
9170 error( param, 0 )\
9171 else\
9172 tFilters[r] = param\
9173 end\
9174 if coroutine.status( r ) == \"dead\" then\
9175 _routines[n] = nil\
9176 living = living - 1\
9177 if living <= _limit then\
9178 return n\
9179 end\
9180 end\
9181 end\
9182 end\
9183 end\
9184 for n=1,count do\
9185 local r = _routines[n]\
9186 if r and coroutine.status( r ) == \"dead\" then\
9187 _routines[n] = nil\
9188 living = living - 1\
9189 if living <= _limit then\
9190 return n\
9191 end\
9192 end\
9193 end\
9194 eventData = { os.pullEventRaw() }\
9195 end\
9196end\
9197\
9198function waitForAny( ... )\
9199 local routines = { create( ... ) }\
9200 return runUntilLimit( routines, #routines - 1 )\
9201end\
9202\
9203function waitForAll( ... )\
9204 local routines = { create( ... ) }\
9205 runUntilLimit( routines, 0 )\
9206end\
9207",
9208 peripheral = "local native = peripheral\
9209\
9210function getNames()\
9211 local tResults = {}\
9212 for n,sSide in ipairs( rs.getSides() ) do\
9213 if native.isPresent( sSide ) then\
9214 table.insert( tResults, sSide )\
9215 if native.getType( sSide ) == \"modem\" and not native.call( sSide, \"isWireless\" ) then\
9216 local tRemote = native.call( sSide, \"getNamesRemote\" )\
9217 for n,sName in ipairs( tRemote ) do\
9218 table.insert( tResults, sName )\
9219 end\
9220 end\
9221 end\
9222 end\
9223 return tResults\
9224end\
9225\
9226function isPresent( _sSide )\
9227 if type( _sSide ) ~= \"string\" then\
9228 error( \"Expected string\", 2 )\
9229 end\
9230 if native.isPresent( _sSide ) then\
9231 return true\
9232 end\
9233 for n,sSide in ipairs( rs.getSides() ) do\
9234 if native.getType( sSide ) == \"modem\" and not native.call( sSide, \"isWireless\" ) then\
9235 if native.call( sSide, \"isPresentRemote\", _sSide ) then\
9236 return true\
9237 end\
9238 end\
9239 end\
9240 return false\
9241end\
9242\
9243function getType( _sSide )\
9244 if type( _sSide ) ~= \"string\" then\
9245 error( \"Expected string\", 2 )\
9246 end\
9247 if native.isPresent( _sSide ) then\
9248 return native.getType( _sSide )\
9249 end\
9250 for n,sSide in ipairs( rs.getSides() ) do\
9251 if native.getType( sSide ) == \"modem\" and not native.call( sSide, \"isWireless\" ) then\
9252 if native.call( sSide, \"isPresentRemote\", _sSide ) then\
9253 return native.call( sSide, \"getTypeRemote\", _sSide ) \
9254 end\
9255 end\
9256 end\
9257 return nil\
9258end\
9259\
9260function getMethods( _sSide )\
9261 if type( _sSide ) ~= \"string\" then\
9262 error( \"Expected string\", 2 )\
9263 end\
9264 if native.isPresent( _sSide ) then\
9265 return native.getMethods( _sSide )\
9266 end\
9267 for n,sSide in ipairs( rs.getSides() ) do\
9268 if native.getType( sSide ) == \"modem\" and not native.call( sSide, \"isWireless\" ) then\
9269 if native.call( sSide, \"isPresentRemote\", _sSide ) then\
9270 return native.call( sSide, \"getMethodsRemote\", _sSide ) \
9271 end\
9272 end\
9273 end\
9274 return nil\
9275end\
9276\
9277function call( _sSide, _sMethod, ... )\
9278 if type( _sSide ) ~= \"string\" or type( _sMethod ) ~= \"string\" then\
9279 error( \"Expected string, string\", 2 )\
9280 end\
9281 if native.isPresent( _sSide ) then\
9282 return native.call( _sSide, _sMethod, ... )\
9283 end\
9284 for n,sSide in ipairs( rs.getSides() ) do\
9285 if native.getType( sSide ) == \"modem\" and not native.call( sSide, \"isWireless\" ) then\
9286 if native.call( sSide, \"isPresentRemote\", _sSide ) then\
9287 return native.call( sSide, \"callRemote\", _sSide, _sMethod, ... ) \
9288 end\
9289 end\
9290 end\
9291 return nil\
9292end\
9293\
9294function wrap( _sSide )\
9295 if type( _sSide ) ~= \"string\" then\
9296 error( \"Expected string\", 2 )\
9297 end\
9298 if peripheral.isPresent( _sSide ) then\
9299 local tMethods = peripheral.getMethods( _sSide )\
9300 local tResult = {}\
9301 for n,sMethod in ipairs( tMethods ) do\
9302 tResult[sMethod] = function( ... )\
9303 return peripheral.call( _sSide, sMethod, ... )\
9304 end\
9305 end\
9306 return tResult\
9307 end\
9308 return nil\
9309end\
9310\
9311function find( sType, fnFilter )\
9312 if type( sType ) ~= \"string\" or (fnFilter ~= nil and type( fnFilter ) ~= \"function\") then\
9313 error( \"Expected string, [function]\", 2 )\
9314 end\
9315 local tResults = {}\
9316 for n,sName in ipairs( peripheral.getNames() ) do\
9317 if peripheral.getType( sName ) == sType then\
9318 local wrapped = peripheral.wrap( sName )\
9319 if fnFilter == nil or fnFilter( sName, wrapped ) then\
9320 table.insert( tResults, wrapped )\
9321 end\
9322 end\
9323 end\
9324 return unpack( tResults )\
9325end\
9326",
9327 help = "\
9328local sPath = \"/rom/help\"\
9329\
9330function path()\
9331 return sPath\
9332end\
9333\
9334function setPath( _sPath )\
9335 sPath = _sPath\
9336end\
9337\
9338function lookup( _sTopic )\
9339 -- Look on the path variable\
9340 for sPath in string.gmatch(sPath, \"[^:]+\") do\
9341 sPath = fs.combine( sPath, _sTopic )\
9342 if fs.exists( sPath ) and not fs.isDir( sPath ) then\
9343 return sPath\
9344 end\
9345 end\
9346 \
9347 -- Not found\
9348 return nil\
9349end\
9350\
9351function topics()\
9352 local tItems = {}\
9353 \
9354 -- Add topics from the path\
9355 for sPath in string.gmatch(sPath, \"[^:]+\") do\
9356 if fs.isDir( sPath ) then\
9357 local tList = fs.list( sPath )\
9358 for n,sFile in pairs( tList ) do\
9359 if string.sub( sFile, 1, 1 ) ~= \".\" then\
9360 if not fs.isDir( fs.combine( sPath, sFile ) ) then\
9361 tItems[ sFile ] = true\
9362 end\
9363 end\
9364 end\
9365 end\
9366 end \
9367\
9368 -- Sort and return\
9369 local tItemList = {}\
9370 for sItem, b in pairs( tItems ) do\
9371 table.insert( tItemList, sItem )\
9372 end\
9373 table.sort( tItemList )\
9374 return tItemList\
9375end\
9376",
9377 keys = "\
9378-- Minecraft key code bindings\
9379-- See http://www.minecraftwiki.net/wiki/Key_codes for more info\
9380\
9381local nothing = 42\
9382local tKeys = {\
9383 nil, \"one\", \"two\", \"three\", \"four\", -- 1\
9384 \"five\", \"six\", \"seven\", \"eight\", \"nine\", -- 6\
9385 \"zero\", \"minus\", \"equals\", \"backspace\",\"tab\", -- 11\
9386 \"q\", \"w\", \"e\", \"r\", \"t\", -- 16\
9387 \"y\", \"u\", \"i\", \"o\", \"p\", -- 21\
9388 \"leftBracket\",\"rightBracket\",\"enter\",\"leftCtrl\",\"a\", -- 26\
9389 \"s\", \"d\", \"f\", \"g\", \"h\", -- 31\
9390 \"j\", \"k\", \"l\", \"semiColon\",\"apostrophe\", -- 36\
9391 \"grave\", \"leftShift\",\"backslash\",\"z\", \"x\", -- 41\
9392 \"c\", \"v\", \"b\", \"n\", \"m\", -- 46\
9393 \"comma\", \"period\", \"slash\", \"rightShift\",\"multiply\", -- 51\
9394 \"leftAlt\", \"space\", \"capsLock\", \"f1\", \"f2\", -- 56\
9395 \"f3\", \"f4\", \"f5\", \"f6\", \"f7\", -- 61\
9396 \"f8\", \"f9\", \"f10\", \"numLock\", \"scollLock\", -- 66 \
9397 \"numPad7\", \"numPad8\", \"numPad9\", \"numPadSubtract\",\"numPad4\", -- 71\
9398 \"numPad5\", \"numPad6\", \"numPadAdd\",\"numPad1\", \"numPad2\", -- 76\
9399 \"numPad3\", \"numPad0\", \"numPadDecimal\",nil, nil, -- 81\
9400 nil, \"f11\", \"f12\", nil, nil, -- 86\
9401 nil, nil, nil, nil, nil, -- 91\
9402 nil, nil, nil, nil, \"f13\", -- 96\
9403 \"f14\", \"f15\", nil, nil, nil, -- 101\
9404 nil, nil, nil, nil, nil, -- 106\
9405 nil, \"kana\", nil, nil, nil, -- 111\
9406 nil, nil, nil, nil, nil, -- 116 \
9407 \"convert\", nil, \"noconvert\",nil, \"yen\", -- 121\
9408 nil, nil, nil, nil, nil, -- 126\
9409 nil, nil, nil, nil, nil, -- 131\
9410 nil, nil, nil, nil, nil, -- 136\
9411 \"numPadEquals\",nil, nil, \"cimcumflex\",\"at\", -- 141\
9412 \"colon\", \"underscore\",\"kanji\", \"stop\", \"ax\", -- 146\
9413 nil, \"numPadEnter\",\"rightCtrl\",nil, nil, -- 151\
9414 nil, nil, nil, nil, nil, -- 156\
9415 nil, nil, nil, nil, nil, -- 161\
9416 nil, nil, nil, nil, nil, -- 166\
9417 nil, nil, nil, nil, nil, -- 171\
9418 nil, nil, nil, \"numPadComma\",nil, -- 176\
9419 \"numPadDivide\",nil, nil, \"rightAlt\", nil, -- 181\
9420 nil, nil, nil, nil, nil, -- 186\
9421 nil, nil, nil, nil, nil, -- 191\
9422 nil, \"pause\", nil, \"home\", \"up\", -- 196\
9423 \"pageUp\", nil, \"left\", nil, \"right\", -- 201\
9424 nil, \"end\", \"down\", \"pageDown\", \"insert\", -- 206\
9425 \"delete\" -- 211\
9426}\
9427\
9428local keys = getfenv()\
9429for nKey, sKey in pairs( tKeys ) do\
9430 keys[sKey] = nKey\
9431end\
9432keys[\"return\"] = keys.enter\
9433\
9434function getName( _nKey )\
9435 return tKeys[ _nKey ]\
9436end\
9437",
9438 textutils = "\
9439function slowWrite( sText, nRate )\
9440 nRate = nRate or 20\
9441 if nRate < 0 then\
9442 error( \"Rate must be positive\", 2 )\
9443 end\
9444 local nSleep = 1 / nRate\
9445 \
9446 sText = tostring( sText )\
9447 local x,y = term.getCursorPos(x,y)\
9448 local len = string.len( sText )\
9449 \
9450 for n=1,len do\
9451 term.setCursorPos( x, y )\
9452 sleep( nSleep )\
9453 local nLines = write( string.sub( sText, 1, n ) )\
9454 local newX, newY = term.getCursorPos()\
9455 y = newY - nLines\
9456 end\
9457end\
9458\
9459function slowPrint( sText, nRate )\
9460 slowWrite( sText, nRate)\
9461 print()\
9462end\
9463\
9464function formatTime( nTime, bTwentyFourHour )\
9465 local sTOD = nil\
9466 if not bTwentyFourHour then\
9467 if nTime >= 12 then\
9468 sTOD = \"PM\"\
9469 else\
9470 sTOD = \"AM\"\
9471 end\
9472 if nTime >= 13 then\
9473 nTime = nTime - 12\
9474 end\
9475 end\
9476\
9477 local nHour = math.floor(nTime)\
9478 local nMinute = math.floor((nTime - nHour)*60)\
9479 if sTOD then\
9480 return string.format( \"%d:%02d %s\", nHour, nMinute, sTOD )\
9481 else\
9482 return string.format( \"%d:%02d\", nHour, nMinute )\
9483 end\
9484end\
9485\
9486local function makePagedScroll( _term, _nFreeLines )\
9487 local nativeScroll = _term.scroll\
9488 local nFreeLines = _nFreeLines or 0\
9489 return function( _n )\
9490 for n=1,_n do\
9491 nativeScroll( 1 )\
9492 \
9493 if nFreeLines <= 0 then\
9494 local w,h = _term.getSize()\
9495 _term.setCursorPos( 1, h )\
9496 _term.write( \"Press any key to continue\" )\
9497 os.pullEvent( \"key\" )\
9498 _term.clearLine()\
9499 _term.setCursorPos( 1, h )\
9500 else\
9501 nFreeLines = nFreeLines - 1\
9502 end\
9503 end\
9504 end\
9505end\
9506\
9507function pagedPrint( _sText, _nFreeLines )\
9508 -- Setup a redirector\
9509 local oldTerm = term.current()\
9510 local newTerm = {}\
9511 for k,v in pairs( oldTerm ) do\
9512 newTerm[k] = v\
9513 end\
9514 newTerm.scroll = makePagedScroll( oldTerm, _nFreeLines )\
9515 term.redirect( newTerm )\
9516\
9517 -- Print the text\
9518 local result\
9519 local ok, err = pcall( function()\
9520 result = print( _sText )\
9521 end )\
9522\
9523 -- Removed the redirector\
9524 term.redirect( oldTerm )\
9525\
9526 -- Propogate errors\
9527 if not ok then\
9528 error( err, 0 )\
9529 end\
9530 return result\
9531end\
9532\
9533local function tabulateCommon( bPaged, ... )\
9534 local tAll = { ... }\
9535 \
9536 local w,h = term.getSize()\
9537 local nMaxLen = w / 8\
9538 for n, t in ipairs( tAll ) do\
9539 if type(t) == \"table\" then\
9540 for n, sItem in pairs(t) do\
9541 nMaxLen = math.max( string.len( sItem ) + 1, nMaxLen )\
9542 end\
9543 end\
9544 end\
9545 local nCols = math.floor( w / nMaxLen )\
9546 local nLines = 0\
9547 local function newLine()\
9548 if bPaged and nLines >= (h-3) then\
9549 pagedPrint()\
9550 else\
9551 print()\
9552 end\
9553 nLines = nLines + 1\
9554 end\
9555 \
9556 local function drawCols( _t )\
9557 local nCol = 1\
9558 for n, s in ipairs( _t ) do\
9559 if nCol > nCols then\
9560 nCol = 1\
9561 newLine()\
9562 end\
9563\
9564 local cx, cy = term.getCursorPos()\
9565 cx = 1 + ((nCol - 1) * nMaxLen)\
9566 term.setCursorPos( cx, cy )\
9567 term.write( s )\
9568\
9569 nCol = nCol + 1 \
9570 end\
9571 print()\
9572 end\
9573 for n, t in ipairs( tAll ) do\
9574 if type(t) == \"table\" then\
9575 if #t > 0 then\
9576 drawCols( t )\
9577 end\
9578 elseif type(t) == \"number\" then\
9579 term.setTextColor( t )\
9580 end\
9581 end \
9582end\
9583\
9584function tabulate( ... )\
9585 tabulateCommon( false, ... )\
9586end\
9587\
9588function pagedTabulate( ... )\
9589 tabulateCommon( true, ... )\
9590end\
9591\
9592local g_tLuaKeywords = {\
9593 [ \"and\" ] = true,\
9594 [ \"break\" ] = true,\
9595 [ \"do\" ] = true,\
9596 [ \"else\" ] = true,\
9597 [ \"elseif\" ] = true,\
9598 [ \"end\" ] = true,\
9599 [ \"false\" ] = true,\
9600 [ \"for\" ] = true,\
9601 [ \"function\" ] = true,\
9602 [ \"if\" ] = true,\
9603 [ \"in\" ] = true,\
9604 [ \"local\" ] = true,\
9605 [ \"nil\" ] = true,\
9606 [ \"not\" ] = true,\
9607 [ \"or\" ] = true,\
9608 [ \"repeat\" ] = true,\
9609 [ \"return\" ] = true,\
9610 [ \"then\" ] = true,\
9611 [ \"true\" ] = true,\
9612 [ \"until\" ] = true,\
9613 [ \"while\" ] = true,\
9614}\
9615\
9616local function serializeImpl( t, tTracking, sIndent )\
9617 local sType = type(t)\
9618 if sType == \"table\" then\
9619 if tTracking[t] ~= nil then\
9620 error( \"Cannot serialize table with recursive entries\", 0 )\
9621 end\
9622 tTracking[t] = true\
9623\
9624 if next(t) == nil then\
9625 -- Empty tables are simple\
9626 return \"{}\"\
9627 else\
9628 -- Other tables take more work\
9629 local sResult = \"{\\n\"\
9630 local sSubIndent = sIndent .. \" \"\
9631 local tSeen = {}\
9632 for k,v in ipairs(t) do\
9633 tSeen[k] = true\
9634 sResult = sResult .. sSubIndent .. serializeImpl( v, tTracking, sSubIndent ) .. \",\\n\"\
9635 end\
9636 for k,v in pairs(t) do\
9637 if not tSeen[k] then\
9638 local sEntry\
9639 if type(k) == \"string\" and not g_tLuaKeywords[k] and string.match( k, \"^[%a_][%a%d_]*$\" ) then\
9640 sEntry = k .. \" = \" .. serializeImpl( v, tTracking, sSubIndent ) .. \",\\n\"\
9641 else\
9642 sEntry = \"[ \" .. serializeImpl( k, tTracking, sSubIndent ) .. \" ] = \" .. serializeImpl( v, tTracking, sSubIndent ) .. \",\\n\"\
9643 end\
9644 sResult = sResult .. sSubIndent .. sEntry\
9645 end\
9646 end\
9647 sResult = sResult .. sIndent .. \"}\"\
9648 return sResult\
9649 end\
9650 \
9651 elseif sType == \"string\" then\
9652 return string.format( \"%q\", t )\
9653 \
9654 elseif sType == \"number\" or sType == \"boolean\" or sType == \"nil\" then\
9655 return tostring(t)\
9656 \
9657 else\
9658 error( \"Cannot serialize type \"..sType, 0 )\
9659 \
9660 end\
9661end\
9662\
9663EMPTY_ARRAY = {}\
9664\
9665local function serializeJSONImpl( t, tTracking )\
9666 local sType = type(t)\
9667 if t == EMPTY_ARRAY then\
9668 return \"[]\"\
9669\
9670 elseif sType == \"table\" then\
9671 if tTracking[t] ~= nil then\
9672 error( \"Cannot serialize table with recursive entries\", 0 )\
9673 end\
9674 tTracking[t] = true\
9675\
9676 if next(t) == nil then\
9677 -- Empty tables are simple\
9678 return \"{}\"\
9679 else\
9680 -- Other tables take more work\
9681 local sObjectResult = \"{\"\
9682 local sArrayResult = \"[\"\
9683 local nObjectSize = 0\
9684 local nArraySize = 0\
9685 for k,v in pairs(t) do\
9686 if type(k) == \"string\" then\
9687 local sEntry = serializeJSONImpl( k, tTracking ) .. \":\" .. serializeJSONImpl( v, tTracking )\
9688 if nObjectSize == 0 then\
9689 sObjectResult = sObjectResult .. sEntry\
9690 else\
9691 sObjectResult = sObjectResult .. \",\" .. sEntry\
9692 end\
9693 nObjectSize = nObjectSize + 1\
9694 end\
9695 end\
9696 for n,v in ipairs(t) do\
9697 local sEntry = serializeJSONImpl( v, tTracking )\
9698 if nArraySize == 0 then\
9699 sArrayResult = sArrayResult .. sEntry\
9700 else\
9701 sArrayResult = sArrayResult .. \",\" .. sEntry\
9702 end\
9703 nArraySize = nArraySize + 1\
9704 end\
9705 sObjectResult = sObjectResult .. \"}\"\
9706 sArrayResult = sArrayResult .. \"]\"\
9707 if nObjectSize > 0 or nArraySize == 0 then\
9708 return sObjectResult\
9709 else\
9710 return sArrayResult\
9711 end\
9712 end\
9713\
9714 elseif sType == \"string\" then\
9715 return string.format( \"%q\", t )\
9716\
9717 elseif sType == \"number\" or sType == \"boolean\" then\
9718 return tostring(t)\
9719\
9720 else\
9721 error( \"Cannot serialize type \"..sType, 0 )\
9722\
9723 end\
9724end\
9725\
9726function serialize( t )\
9727 local tTracking = {}\
9728 return serializeImpl( t, tTracking, \"\" )\
9729end\
9730\
9731function unserialize( s )\
9732 local func = loadstring( \"return \"..s, \"unserialize\" )\
9733 if func then\
9734 setfenv( func, {} )\
9735 local ok, result = pcall( func )\
9736 if ok then\
9737 return result\
9738 end\
9739 end\
9740 return nil\
9741end\
9742\
9743function serializeJSON( t )\
9744 local tTracking = {}\
9745 return serializeJSONImpl( t, tTracking )\
9746end\
9747\
9748function urlEncode( str )\
9749 if str then\
9750 str = string.gsub(str, \"\\n\", \"\\r\\n\")\
9751 str = string.gsub(str, \"([^%w ])\", function(c)\
9752 return string.format(\"%%%02X\", string.byte(c))\
9753 end )\
9754 str = string.gsub(str, \" \", \"+\")\
9755 end\
9756 return str \
9757end\
9758\
9759-- GB versions\
9760serialise = serialize\
9761unserialise = unserialize\
9762serialiseJSON = serializeJSON\
9763",
9764 gps = "\
9765CHANNEL_GPS = 65534\
9766\
9767local function trilaterate( A, B, C )\
9768 local a2b = B.vPosition - A.vPosition\
9769 local a2c = C.vPosition - A.vPosition\
9770 \
9771 if math.abs( a2b:normalize():dot( a2c:normalize() ) ) > 0.999 then\
9772 return nil\
9773 end\
9774 \
9775 local d = a2b:length()\
9776 local ex = a2b:normalize( )\
9777 local i = ex:dot( a2c )\
9778 local ey = (a2c - (ex * i)):normalize()\
9779 local j = ey:dot( a2c )\
9780 local ez = ex:cross( ey )\
9781\
9782 local r1 = A.nDistance\
9783 local r2 = B.nDistance\
9784 local r3 = C.nDistance\
9785 \
9786 local x = (r1*r1 - r2*r2 + d*d) / (2*d)\
9787 local y = (r1*r1 - r3*r3 - x*x + (x-i)*(x-i) + j*j) / (2*j)\
9788 \
9789 local result = A.vPosition + (ex * x) + (ey * y)\
9790\
9791 local zSquared = r1*r1 - x*x - y*y\
9792 if zSquared > 0 then\
9793 local z = math.sqrt( zSquared )\
9794 local result1 = result + (ez * z)\
9795 local result2 = result - (ez * z)\
9796 \
9797 local rounded1, rounded2 = result1:round( 0.01 ), result2:round( 0.01 )\
9798 if rounded1.x ~= rounded2.x or rounded1.y ~= rounded2.y or rounded1.z ~= rounded2.z then\
9799 return rounded1, rounded2\
9800 else\
9801 return rounded1\
9802 end\
9803 end\
9804 return result:round( 0.01 )\
9805 \
9806end\
9807\
9808local function narrow( p1, p2, fix )\
9809 local dist1 = math.abs( (p1 - fix.vPosition):length() - fix.nDistance )\
9810 local dist2 = math.abs( (p2 - fix.vPosition):length() - fix.nDistance )\
9811 \
9812 if math.abs(dist1 - dist2) < 0.01 then\
9813 return p1, p2\
9814 elseif dist1 < dist2 then\
9815 return p1:round( 0.01 )\
9816 else\
9817 return p2:round( 0.01 )\
9818 end\
9819end\
9820\
9821function locate( _nTimeout, _bDebug )\
9822 -- Let command computers use their magic fourth-wall-breaking special abilities\
9823 if commands then\
9824 return commands.getBlockPosition()\
9825 end\
9826\
9827 -- Find a modem\
9828 local sModemSide = nil\
9829 for n,sSide in ipairs( rs.getSides() ) do\
9830 if peripheral.getType( sSide ) == \"modem\" and peripheral.call( sSide, \"isWireless\" ) then \
9831 sModemSide = sSide\
9832 break\
9833 end\
9834 end\
9835\
9836 if sModemSide == nil then\
9837 if _bDebug then\
9838 print( \"No wireless modem attached\" )\
9839 end\
9840 return nil\
9841 end\
9842 \
9843 if _bDebug then\
9844 print( \"Finding position...\" )\
9845 end\
9846 \
9847 -- Open a channel\
9848 local modem = peripheral.wrap( sModemSide )\
9849 local bCloseChannel = false\
9850 if not modem.isOpen( os.getComputerID() ) then\
9851 modem.open( os.getComputerID() )\
9852 bCloseChannel = true\
9853 end\
9854 \
9855 -- Send a ping to listening GPS hosts\
9856 modem.transmit( CHANNEL_GPS, os.getComputerID(), \"PING\" )\
9857 \
9858 -- Wait for the responses\
9859 local tFixes = {}\
9860 local pos1, pos2 = nil, nil\
9861 local timeout = os.startTimer( _nTimeout or 2 )\
9862 while true do\
9863 local e, p1, p2, p3, p4, p5 = os.pullEvent()\
9864 if e == \"modem_message\" then\
9865 -- We received a message from a modem\
9866 local sSide, sChannel, sReplyChannel, tMessage, nDistance = p1, p2, p3, p4, p5\
9867 if sSide == sModemSide and sChannel == os.getComputerID() and sReplyChannel == CHANNEL_GPS then\
9868 -- Received the correct message from the correct modem: use it to determine position\
9869 if type(tMessage) == \"table\" and #tMessage == 3 then\
9870 local tFix = { vPosition = vector.new( tMessage[1], tMessage[2], tMessage[3] ), nDistance = nDistance }\
9871 if _bDebug then\
9872 print( tFix.nDistance..\" metres from \"..tostring( tFix.vPosition ) )\
9873 end\
9874 if tFix.nDistance == 0 then\
9875 pos1, pos2 = tFix.vPosition, nil\
9876 else\
9877 table.insert( tFixes, tFix )\
9878 if #tFixes >= 3 then\
9879 if not pos1 then\
9880 pos1, pos2 = trilaterate( tFixes[1], tFixes[2], tFixes[#tFixes] )\
9881 else\
9882 pos1, pos2 = narrow( pos1, pos2, tFixes[#tFixes] )\
9883 end\
9884 end\
9885 end\
9886 if pos1 and not pos2 then\
9887 break\
9888 end\
9889 end\
9890 end\
9891 \
9892 elseif e == \"timer\" then\
9893 -- We received a timeout\
9894 local timer = p1\
9895 if timer == timeout then\
9896 break\
9897 end\
9898 \
9899 end \
9900 end\
9901 \
9902 -- Close the channel, if we opened one\
9903 if bCloseChannel then\
9904 modem.close( os.getComputerID() )\
9905 end\
9906 \
9907 -- Return the response\
9908 if pos1 and pos2 then\
9909 if _bDebug then\
9910 print( \"Ambiguous position\" )\
9911 print( \"Could be \"..pos1.x..\",\"..pos1.y..\",\"..pos1.z..\" or \"..pos2.x..\",\"..pos2.y..\",\"..pos2.z )\
9912 end\
9913 return nil\
9914 elseif pos1 then\
9915 if _bDebug then\
9916 print( \"Position is \"..pos1.x..\",\"..pos1.y..\",\"..pos1.z )\
9917 end\
9918 return pos1.x, pos1.y, pos1.z\
9919 else\
9920 if _bDebug then\
9921 print( \"Could not determine position\" )\
9922 end\
9923 return nil\
9924 end\
9925end\
9926",
9927 disk = "\
9928local function isDrive( name )\
9929 return peripheral.getType( name ) == \"drive\"\
9930end\
9931\
9932function isPresent( name )\
9933 if isDrive( name ) then\
9934 return peripheral.call( name, \"isDiskPresent\" )\
9935 end\
9936 return false\
9937end\
9938\
9939function getLabel( name )\
9940 if isDrive( name ) then\
9941 return peripheral.call( name, \"getDiskLabel\" )\
9942 end\
9943 return nil\
9944end\
9945\
9946function setLabel( name, label )\
9947 if isDrive( name ) then\
9948 peripheral.call( name, \"setDiskLabel\", label )\
9949 end\
9950end\
9951\
9952function hasData( name )\
9953 if isDrive( name ) then\
9954 return peripheral.call( name, \"hasData\" )\
9955 end\
9956 return false\
9957end\
9958\
9959function getMountPath( name )\
9960 if isDrive( name ) then\
9961 return peripheral.call( name, \"getMountPath\" )\
9962 end\
9963 return nil\
9964end\
9965\
9966function hasAudio( name )\
9967 if isDrive( name ) then\
9968 return peripheral.call( name, \"hasAudio\" )\
9969 end\
9970 return false\
9971end\
9972\
9973function getAudioTitle( name )\
9974 if isDrive( name ) then\
9975 return peripheral.call( name, \"getAudioTitle\" )\
9976 end\
9977 return nil\
9978end\
9979\
9980function playAudio( name )\
9981 if isDrive( name ) then\
9982 peripheral.call( name, \"playAudio\" )\
9983 end\
9984end\
9985\
9986function stopAudio( name )\
9987 if not name then\
9988 for n,sName in ipairs( peripheral.getNames() ) do\
9989 stopAudio( sName )\
9990 end\
9991 else\
9992 if isDrive( name ) then\
9993 peripheral.call( name, \"stopAudio\" )\
9994 end\
9995 end\
9996end\
9997\
9998function eject( name )\
9999 if isDrive( name ) then\
10000 peripheral.call( name, \"ejectDisk\" )\
10001 end\
10002end\
10003\
10004function getID( name )\
10005 if isDrive( name ) then\
10006 return peripheral.call( name, \"getDiskID\" )\
10007 end\
10008 return nil\
10009end\
10010\
10011",
10012 window = "\
10013function create( parent, nX, nY, nWidth, nHeight, bStartVisible )\
10014\
10015 if type( parent ) ~= \"table\" or\
10016 type( nX ) ~= \"number\" or\
10017 type( nY ) ~= \"number\" or\
10018 type( nWidth ) ~= \"number\" or\
10019 type( nHeight ) ~= \"number\" or\
10020 (bStartVisible ~= nil and type( bStartVisible ) ~= \"boolean\") then\
10021 error( \"Expected object, number, number, number, number, [boolean]\", 2 )\
10022 end\
10023\
10024 if parent == term then\
10025 error( \"term is not a recommended window parent, try term.current() instead\", 2 )\
10026 end\
10027\
10028 -- Setup\
10029 local bVisible = (bStartVisible ~= false)\
10030 local nCursorX = 1\
10031 local nCursorY = 1\
10032 local bCursorBlink = false\
10033 local nTextColor = colors.white\
10034 local nBackgroundColor = colors.black\
10035 local sEmpty = string.rep( \" \", nWidth )\
10036 local tLines = {}\
10037 do\
10038 local tEmpty = { { sEmpty, nTextColor, nBackgroundColor } }\
10039 for y=1,nHeight do\
10040 tLines[y] = tEmpty\
10041 end\
10042 end\
10043\
10044 -- Helper functions\
10045 local function updateCursorPos()\
10046 if nCursorX >= 1 and nCursorY >= 1 and\
10047 nCursorX <= nWidth and nCursorY <= nHeight then\
10048 parent.setCursorPos( nX + nCursorX - 1, nY + nCursorY - 1 )\
10049 else\
10050 parent.setCursorPos( 0, 0 )\
10051 end\
10052 end\
10053 \
10054 local function updateCursorBlink()\
10055 parent.setCursorBlink( bCursorBlink )\
10056 end\
10057 \
10058 local function updateCursorColor()\
10059 parent.setTextColor( nTextColor )\
10060 end\
10061 \
10062 local function redrawLine( n )\
10063 parent.setCursorPos( nX, nY + n - 1 )\
10064 local tLine = tLines[ n ]\
10065 for m=1,#tLine do\
10066 local tBit = tLine[ m ]\
10067 parent.setTextColor( tBit[2] )\
10068 parent.setBackgroundColor( tBit[3] )\
10069 parent.write( tBit[1] )\
10070 end\
10071 end\
10072\
10073 local function lineLen( tLine )\
10074 local nLength = 0\
10075 for n=1,#tLine do\
10076 nLength = nLength + string.len( tLine[n][1] )\
10077 end\
10078 return nLength\
10079 end\
10080\
10081 local function lineSub( tLine, nStart, nEnd )\
10082 --assert( math.floor(nStart) == nStart )\
10083 --assert( math.floor(nEnd) == nEnd )\
10084 --assert( nStart >= 1 )\
10085 --assert( nEnd >= nStart )\
10086 --assert( nEnd <= lineLen( tLine ) )\
10087 local tSubLine = {}\
10088 local nBitStart = 1\
10089 for n=1,#tLine do\
10090 local tBit = tLine[n]\
10091 local sBit = tBit[1]\
10092 local nBitEnd = nBitStart + string.len( sBit ) - 1\
10093 if nBitEnd >= nStart and nBitStart <= nEnd then\
10094 if nBitStart >= nStart and nBitEnd <= nEnd then\
10095 -- Include bit wholesale\
10096 table.insert( tSubLine, tBit )\
10097 --assert( lineLen( tSubLine ) == (math.min(nEnd, nBitEnd) - nStart + 1) )\
10098 elseif nBitStart < nStart and nBitEnd <= nEnd then\
10099 -- Include end of bit\
10100 table.insert( tSubLine, {\
10101 string.sub( sBit, nStart - nBitStart + 1 ),\
10102 tBit[2], tBit[3]\
10103 } )\
10104 --assert( lineLen( tSubLine ) == (math.min(nEnd, nBitEnd) - nStart + 1) )\
10105 elseif nBitStart >= nStart and nBitEnd > nEnd then\
10106 -- Include beginning of bit\
10107 table.insert( tSubLine, {\
10108 string.sub( sBit, 1, nEnd - nBitStart + 1 ),\
10109 tBit[2], tBit[3]\
10110 } )\
10111 --assert( lineLen( tSubLine ) == (math.min(nEnd, nBitEnd) - nStart + 1) )\
10112 else\
10113 -- Include middle of bit\
10114 table.insert( tSubLine, {\
10115 string.sub( sBit, nStart - nBitStart + 1, nEnd - nBitStart + 1 ),\
10116 tBit[2], tBit[3]\
10117 } )\
10118 --assert( lineLen( tSubLine ) == (math.min(nEnd, nBitEnd) - nStart + 1) )\
10119 end\
10120 end\
10121 nBitStart = nBitEnd + 1\
10122 end\
10123 --assert( lineLen( tSubLine ) == (nEnd - nStart + 1) )\
10124 return tSubLine\
10125 end\
10126\
10127 local function lineJoin( tLine1, tLine2 )\
10128 local tNewLine = {}\
10129 if tLine1[#tLine1][2] == tLine2[1][2] and\
10130 tLine1[#tLine1][3] == tLine2[1][3] then\
10131 -- Merge middle bits\
10132 for n=1,#tLine1-1 do\
10133 table.insert( tNewLine, tLine1[n] )\
10134 end\
10135 table.insert( tNewLine, {\
10136 tLine1[#tLine1][1] .. tLine2[1][1],\
10137 tLine2[1][2], tLine2[1][3]\
10138 } )\
10139 for n=2,#tLine2 do\
10140 table.insert( tNewLine, tLine2[n] )\
10141 end\
10142 --assert( lineLen( tNewLine ) == lineLen(tLine1) + lineLen(tLine2) )\
10143 else\
10144 -- Just concatenate\
10145 for n=1,#tLine1 do\
10146 table.insert( tNewLine, tLine1[n] )\
10147 end\
10148 for n=1,#tLine2 do\
10149 table.insert( tNewLine, tLine2[n] )\
10150 end\
10151 --assert( lineLen( tNewLine ) == lineLen(tLine1) + lineLen(tLine2) )\
10152 end\
10153 return tNewLine\
10154 end\
10155\
10156 local function redraw()\
10157 for n=1,nHeight do\
10158 redrawLine( n )\
10159 end\
10160 end\
10161\
10162 local window = {}\
10163\
10164 -- Terminal implementation\
10165 function window.write( sText )\
10166 local nLen = string.len( sText )\
10167 local nStart = nCursorX\
10168 local nEnd = nStart + nLen - 1\
10169 if nCursorY >= 1 and nCursorY <= nHeight then\
10170 -- Work out where to put new line\
10171 --assert( math.floor(nStart) == nStart )\
10172 --assert( math.floor(nEnd) == nEnd )\
10173 if nStart <= nWidth and nEnd >= 1 then\
10174 -- Construct new line\
10175 local tLine = tLines[ nCursorY ]\
10176 if nStart == 1 and nEnd == nWidth then\
10177 -- Exactly replace line\
10178 tLine = {\
10179 { sText, nTextColor, nBackgroundColor }\
10180 }\
10181 --assert( lineLen( tLine ) == nWidth )\
10182 elseif nStart <= 1 and nEnd >= nWidth then\
10183 -- Overwrite line with subset\
10184 tLine = {\
10185 { string.sub( sText, 1 - nStart + 1, nWidth - nStart + 1 ), nTextColor, nBackgroundColor }\
10186 }\
10187 --assert( lineLen( tLine ) == nWidth )\
10188 elseif nStart <= 1 then\
10189 -- Overwrite beginning of line\
10190 tLine = lineJoin(\
10191 { { string.sub( sText, 1 - nStart + 1 ), nTextColor, nBackgroundColor } },\
10192 lineSub( tLine, nEnd + 1, nWidth )\
10193 )\
10194 --assert( lineLen( tLine ) == nWidth )\
10195 elseif nEnd >= nWidth then\
10196 -- Overwrite end of line\
10197 tLine = lineJoin(\
10198 lineSub( tLine, 1, nStart - 1 ),\
10199 { { string.sub( sText, 1, nWidth - nStart + 1 ), nTextColor, nBackgroundColor } }\
10200 )\
10201 --assert( lineLen( tLine ) == nWidth )\
10202 else\
10203 -- Overwrite middle of line\
10204 tLine = lineJoin(\
10205 lineJoin(\
10206 lineSub( tLine, 1, nStart - 1 ),\
10207 { { sText, nTextColor, nBackgroundColor } }\
10208 ),\
10209 lineSub( tLine, nEnd + 1, nWidth )\
10210 )\
10211 --assert( lineLen( tLine ) == nWidth )\
10212 end\
10213\
10214 -- Store and redraw new line\
10215 tLines[ nCursorY ] = tLine\
10216 if bVisible then\
10217 redrawLine( nCursorY )\
10218 end\
10219 end\
10220 end\
10221\
10222 -- Move and redraw cursor\
10223 nCursorX = nEnd + 1\
10224 if bVisible then\
10225 updateCursorColor()\
10226 updateCursorPos()\
10227 end\
10228 end\
10229\
10230 function window.clear()\
10231 local tEmpty = { { sEmpty, nTextColor, nBackgroundColor } }\
10232 for y=1,nHeight do\
10233 tLines[y] = tEmpty\
10234 end\
10235 if bVisible then\
10236 redraw()\
10237 updateCursorColor()\
10238 updateCursorPos()\
10239 end\
10240 end\
10241\
10242 function window.clearLine()\
10243 if nCursorY >= 1 and nCursorY <= nHeight then\
10244 tLines[ nCursorY ] = { { sEmpty, nTextColor, nBackgroundColor } }\
10245 if bVisible then\
10246 redrawLine( nCursorY )\
10247 updateCursorColor()\
10248 updateCursorPos()\
10249 end\
10250 end\
10251 end\
10252\
10253 function window.getCursorPos()\
10254 return nCursorX, nCursorY\
10255 end\
10256\
10257 function window.setCursorPos( x, y )\
10258 nCursorX = math.floor( x )\
10259 nCursorY = math.floor( y )\
10260 if bVisible then\
10261 updateCursorPos()\
10262 end\
10263 end\
10264\
10265 function window.setCursorBlink( blink )\
10266 bCursorBlink = blink\
10267 if bVisible then\
10268 updateCursorBlink()\
10269 end\
10270 end\
10271\
10272 function window.isColor()\
10273 return parent.isColor()\
10274 end\
10275\
10276 function window.isColour()\
10277 return parent.isColor()\
10278 end\
10279\
10280 local function setTextColor( color )\
10281 if not parent.isColor() then\
10282 if color ~= colors.white and color ~= colors.black then\
10283 error( \"Colour not supported\", 3 )\
10284 end\
10285 end\
10286 nTextColor = color\
10287 if bVisible then\
10288 updateCursorColor()\
10289 end\
10290 end\
10291\
10292 function window.setTextColor( color )\
10293 setTextColor( color )\
10294 end\
10295\
10296 function window.setTextColour( color )\
10297 setTextColor( color )\
10298 end\
10299\
10300 local function setBackgroundColor( color )\
10301 if not parent.isColor() then\
10302 if color ~= colors.white and color ~= colors.black then\
10303 error( \"Colour not supported\", 3 )\
10304 end\
10305 end\
10306 nBackgroundColor = color\
10307 end\
10308\
10309 function window.setBackgroundColor( color )\
10310 setBackgroundColor( color )\
10311 end\
10312\
10313 function window.setBackgroundColour( color )\
10314 setBackgroundColor( color )\
10315 end\
10316\
10317 function window.getSize()\
10318 return nWidth, nHeight\
10319 end\
10320\
10321 function window.scroll( n )\
10322 if n ~= 0 then\
10323 local tNewLines = {}\
10324 local tEmpty = { { sEmpty, nTextColor, nBackgroundColor } }\
10325 for newY=1,nHeight do\
10326 local y = newY + n\
10327 if y >= 1 and y <= nHeight then\
10328 tNewLines[newY] = tLines[y]\
10329 else\
10330 tNewLines[newY] = tEmpty\
10331 end\
10332 end\
10333 tLines = tNewLines\
10334 if bVisible then\
10335 redraw()\
10336 updateCursorColor()\
10337 updateCursorPos()\
10338 end\
10339 end\
10340 end\
10341\
10342 -- Other functions\
10343 function window.setVisible( bVis )\
10344 if bVisible ~= bVis then\
10345 bVisible = bVis\
10346 if bVisible then\
10347 window.redraw()\
10348 end\
10349 end\
10350 end\
10351\
10352 function window.redraw()\
10353 if bVisible then\
10354 redraw()\
10355 updateCursorBlink()\
10356 updateCursorColor()\
10357 updateCursorPos()\
10358 end\
10359 end\
10360\
10361 function window.restoreCursor()\
10362 if bVisible then\
10363 updateCursorBlink()\
10364 updateCursorColor()\
10365 updateCursorPos()\
10366 end\
10367 end\
10368\
10369 function window.getPosition()\
10370 return nX, nY\
10371 end\
10372\
10373 function window.reposition( nNewX, nNewY, nNewWidth, nNewHeight )\
10374 nX = nNewX\
10375 nY = nNewY\
10376 if nNewWidth and nNewHeight then\
10377 sEmpty = string.rep( \" \", nNewWidth )\
10378 local tNewLines = {}\
10379 local tEmpty = { { sEmpty, nTextColor, nBackgroundColor } }\
10380 for y=1,nNewHeight do\
10381 if y > nHeight then\
10382 tNewLines[y] = tEmpty\
10383 else\
10384 if nNewWidth == nWidth then\
10385 tNewLines[y] = tLines[y]\
10386 elseif nNewWidth < nWidth then\
10387 tNewLines[y] = lineSub( tLines[y], 1, nNewWidth )\
10388 else\
10389 tNewLines[y] = lineJoin( tLines[y], { { string.sub( sEmpty, nWidth + 1, nNewWidth ), nTextColor, nBackgroundColor } } )\
10390 end\
10391 end\
10392 end\
10393 nWidth = nNewWidth\
10394 nHeight = nNewHeight\
10395 tLines = tNewLines\
10396 end\
10397 if bVisible then\
10398 window.redraw()\
10399 end\
10400 end\
10401\
10402 if bVisible then\
10403 window.redraw()\
10404 end\
10405 return window\
10406end\
10407",
10408 turtle = {
10409 turtle = "\
10410if not turtle then\
10411 error( \"Cannot load turtle API on computer\", 2 )\
10412end\
10413native = turtle.native or turtle\
10414\
10415local function addCraftMethod( object )\
10416 if peripheral.getType( \"left\" ) == \"workbench\" then\
10417 object.craft = function( ... )\
10418 return peripheral.call( \"left\", \"craft\", ... )\
10419 end\
10420 elseif peripheral.getType( \"right\" ) == \"workbench\" then\
10421 object.craft = function( ... )\
10422 return peripheral.call( \"right\", \"craft\", ... )\
10423 end\
10424 else\
10425 object.craft = nil\
10426 end\
10427end\
10428\
10429-- Put commands into environment table\
10430local env = getfenv()\
10431for k,v in pairs( native ) do\
10432 if k == \"equipLeft\" or k == \"equipRight\" then\
10433 env[k] = function( ... )\
10434 local result, err = v( ... )\
10435 addCraftMethod( turtle )\
10436 return result, err\
10437 end\
10438 else\
10439 env[k] = v\
10440 end\
10441end\
10442addCraftMethod( env )\
10443",
10444 },
10445 io = "-- Definition for the IO API\
10446\
10447local g_defaultInput = {\
10448 bFileHandle = true,\
10449 bClosed = false,\
10450 close = function( self )\
10451 end,\
10452 read = function( self, _sFormat )\
10453 if _sFormat and _sFormat ~= \"*l\" then\
10454 error( \"Unsupported format\" )\
10455 end\
10456 return _G.read()\
10457 end,\
10458 lines = function( self )\
10459 return function()\
10460 return _G.read()\
10461 end\
10462 end,\
10463}\
10464\
10465local g_defaultOutput = {\
10466 bFileHandle = true,\
10467 bClosed = false,\
10468 close = function( self )\
10469 end,\
10470 write = function( self, _sText )\
10471 _G.write( _sText )\
10472 end,\
10473 flush = function( self )\
10474 end,\
10475}\
10476\
10477local g_currentInput = g_defaultInput\
10478local g_currentOutput = g_defaultOutput\
10479\
10480function close( _file )\
10481 (_file or g_currentOutput):close()\
10482end\
10483\
10484function flush()\
10485 g_currentOutput:flush()\
10486end\
10487\
10488function input( _arg )\
10489 if _G.type( _arg ) == \"string\" then\
10490 g_currentInput = open( _arg, \"r\" )\
10491 elseif _G.type( _arg ) == \"table\" then\
10492 g_currentInput = _arg\
10493 elseif _G.type( _arg ) == \"nil\" then\
10494 return g_currentInput\
10495 else\
10496 error( \"Expected file name or file handle\" )\
10497 end\
10498end\
10499\
10500function lines( _sFileName )\
10501 if _sFileName then\
10502 return open( _sFileName, \"r\" ):lines()\
10503 else\
10504 return g_currentInput:lines()\
10505 end\
10506end\
10507\
10508function open( _sPath, _sMode )\
10509 local sMode = _sMode or \"r\"\
10510 local file = fs.open( _sPath, sMode )\
10511 if not file then\
10512 return nil\
10513 end\
10514 \
10515 if sMode == \"r\"then\
10516 return {\
10517 bFileHandle = true,\
10518 bClosed = false, \
10519 close = function( self )\
10520 file.close()\
10521 self.bClosed = true\
10522 end,\
10523 read = function( self, _sFormat )\
10524 local sFormat = _sFormat or \"*l\"\
10525 if sFormat == \"*l\" then\
10526 return file.readLine()\
10527 elseif sFormat == \"*a\" then\
10528 return file.readAll()\
10529 else\
10530 error( \"Unsupported format\" )\
10531 end\
10532 return nil\
10533 end,\
10534 lines = function( self )\
10535 return function()\
10536 local sLine = file.readLine()\
10537 if sLine == nil then\
10538 file.close()\
10539 self.bClosed = true\
10540 end\
10541 return sLine\
10542 end\
10543 end,\
10544 }\
10545 elseif sMode == \"w\" or sMode == \"a\" then\
10546 return {\
10547 bFileHandle = true,\
10548 bClosed = false, \
10549 close = function( self )\
10550 file.close()\
10551 self.bClosed = true\
10552 end,\
10553 write = function( self, _sText )\
10554 file.write( _sText )\
10555 end,\
10556 flush = function( self )\
10557 file.flush()\
10558 end,\
10559 }\
10560 \
10561 elseif sMode == \"rb\" then\
10562 return {\
10563 bFileHandle = true,\
10564 bClosed = false, \
10565 close = function( self )\
10566 file.close()\
10567 self.bClosed = true\
10568 end,\
10569 read = function( self )\
10570 return file.read()\
10571 end,\
10572 }\
10573 \
10574 elseif sMode == \"wb\" or sMode == \"ab\" then\
10575 return {\
10576 bFileHandle = true,\
10577 bClosed = false, \
10578 close = function( self )\
10579 file.close()\
10580 self.bClosed = true\
10581 end,\
10582 write = function( self, _number )\
10583 file.write( _number )\
10584 end,\
10585 flush = function( self )\
10586 file.flush()\
10587 end,\
10588 }\
10589 \
10590 else\
10591 file.close()\
10592 error( \"Unsupported mode\" )\
10593 \
10594 end\
10595end\
10596\
10597function output( _arg )\
10598 if _G.type( _arg ) == \"string\" then\
10599 g_currentOutput = open( _arg, \"w\" )\
10600 elseif _G.type( _arg ) == \"table\" then\
10601 g_currentOutput = _arg\
10602 elseif _G.type( _arg ) == \"nil\" then\
10603 return g_currentOutput\
10604 else\
10605 error( \"Expected file name or file handle\" )\
10606 end\
10607end\
10608\
10609function read( ... )\
10610 return input():read( ... )\
10611end\
10612\
10613function type( _handle )\
10614 if _G.type( _handle ) == \"table\" and _handle.bFileHandle == true then\
10615 if _handle.bClosed then\
10616 return \"closed file\"\
10617 else\
10618 return \"file\"\
10619 end\
10620 end\
10621 return nil\
10622end\
10623\
10624function write( ... )\
10625 return output():write( ... )\
10626end\
10627",
10628 colors = "-- Colors\
10629white = 1\
10630orange = 2\
10631magenta = 4\
10632lightBlue = 8\
10633yellow = 16\
10634lime = 32\
10635pink = 64\
10636gray = 128\
10637lightGray = 256\
10638cyan = 512\
10639purple = 1024\
10640blue = 2048\
10641brown = 4096\
10642green = 8192\
10643red = 16384\
10644black = 32768\
10645\
10646function combine( ... )\
10647 local r = 0\
10648 for n,c in ipairs( { ... } ) do\
10649 r = bit.bor(r,c)\
10650 end\
10651 return r\
10652end\
10653\
10654function subtract( colors, ... )\
10655 local r = colors\
10656 for n,c in ipairs( { ... } ) do\
10657 r = bit.band(r, bit.bnot(c))\
10658 end\
10659 return r\
10660end\
10661\
10662function test( colors, color )\
10663 return ((bit.band(colors, color)) == color)\
10664end",
10665 vector = "\
10666local vector = {\
10667 add = function( self, o )\
10668 return vector.new(\
10669 self.x + o.x,\
10670 self.y + o.y,\
10671 self.z + o.z\
10672 )\
10673 end,\
10674 sub = function( self, o )\
10675 return vector.new(\
10676 self.x - o.x,\
10677 self.y - o.y,\
10678 self.z - o.z\
10679 )\
10680 end,\
10681 mul = function( self, m )\
10682 return vector.new(\
10683 self.x * m,\
10684 self.y * m,\
10685 self.z * m\
10686 )\
10687 end,\
10688 div = function( self, m )\
10689 return vector.new(\
10690 self.x / m,\
10691 self.y / m,\
10692 self.z / m\
10693 )\
10694 end,\
10695 unm = function( self )\
10696 return vector.new(\
10697 -self.x,\
10698 -self.y,\
10699 -self.z\
10700 )\
10701 end,\
10702 dot = function( self, o )\
10703 return self.x*o.x + self.y*o.y + self.z*o.z\
10704 end,\
10705 cross = function( self, o )\
10706 return vector.new(\
10707 self.y*o.z - self.z*o.y,\
10708 self.z*o.x - self.x*o.z,\
10709 self.x*o.y - self.y*o.x\
10710 )\
10711 end,\
10712 length = function( self )\
10713 return math.sqrt( self.x*self.x + self.y*self.y + self.z*self.z )\
10714 end,\
10715 normalize = function( self )\
10716 return self:mul( 1 / self:length() )\
10717 end,\
10718 round = function( self, nTolerance )\
10719 nTolerance = nTolerance or 1.0\
10720 return vector.new(\
10721 math.floor( (self.x + (nTolerance * 0.5)) / nTolerance ) * nTolerance,\
10722 math.floor( (self.y + (nTolerance * 0.5)) / nTolerance ) * nTolerance,\
10723 math.floor( (self.z + (nTolerance * 0.5)) / nTolerance ) * nTolerance\
10724 )\
10725 end,\
10726 tostring = function( self )\
10727 return self.x..\",\"..self.y..\",\"..self.z\
10728 end,\
10729}\
10730\
10731local vmetatable = {\
10732 __index = vector,\
10733 __add = vector.add,\
10734 __sub = vector.sub,\
10735 __mul = vector.mul,\
10736 __div = vector.div,\
10737 __unm = vector.unm,\
10738 __tostring = vector.tostring,\
10739}\
10740\
10741function new( x, y, z )\
10742 local v = {\
10743 x = x or 0,\
10744 y = y or 0,\
10745 z = z or 0\
10746 }\
10747 setmetatable( v, vmetatable )\
10748 return v\
10749end\
10750",
10751 rednet = "\
10752CHANNEL_BROADCAST = 65535\
10753CHANNEL_REPEAT = 65533\
10754\
10755local tReceivedMessages = {}\
10756local tReceivedMessageTimeouts = {}\
10757local tHostnames = {}\
10758\
10759function open( sModem )\
10760 if type( sModem ) ~= \"string\" then\
10761 error( \"expected string\", 2 )\
10762 end\
10763 if peripheral.getType( sModem ) ~= \"modem\" then \
10764 error( \"No such modem: \"..sModem, 2 )\
10765 end\
10766 peripheral.call( sModem, \"open\", os.getComputerID() )\
10767 peripheral.call( sModem, \"open\", CHANNEL_BROADCAST )\
10768end\
10769\
10770function close( sModem )\
10771 if sModem then\
10772 -- Close a specific modem\
10773 if type( sModem ) ~= \"string\" then\
10774 error( \"expected string\", 2 )\
10775 end\
10776 if peripheral.getType( sModem ) ~= \"modem\" then\
10777 error( \"No such modem: \"..sModem, 2 )\
10778 end\
10779 peripheral.call( sModem, \"close\", os.getComputerID() )\
10780 peripheral.call( sModem, \"close\", CHANNEL_BROADCAST )\
10781 else\
10782 -- Close all modems\
10783 for n,sModem in ipairs( peripheral.getNames() ) do\
10784 if isOpen( sModem ) then\
10785 close( sModem )\
10786 end\
10787 end\
10788 end\
10789end\
10790\
10791function isOpen( sModem )\
10792 if sModem then\
10793 -- Check if a specific modem is open\
10794 if type( sModem ) ~= \"string\" then\
10795 error( \"expected string\", 2 )\
10796 end\
10797 if peripheral.getType( sModem ) == \"modem\" then\
10798 return peripheral.call( sModem, \"isOpen\", os.getComputerID() ) and peripheral.call( sModem, \"isOpen\", CHANNEL_BROADCAST )\
10799 end\
10800 else\
10801 -- Check if any modem is open\
10802 for n,sModem in ipairs( peripheral.getNames() ) do\
10803 if isOpen( sModem ) then\
10804 return true\
10805 end\
10806 end\
10807 end\
10808 return false\
10809end\
10810\
10811function send( nRecipient, message, sProtocol )\
10812 -- Generate a (probably) unique message ID\
10813 -- We could do other things to guarantee uniqueness, but we really don't need to\
10814 -- Store it to ensure we don't get our own messages back\
10815 local nMessageID = math.random( 1, 2147483647 )\
10816 tReceivedMessages[ nMessageID ] = true\
10817 tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = nMessageID\
10818\
10819 -- Create the message\
10820 local nReplyChannel = os.getComputerID()\
10821 local tMessage = {\
10822 nMessageID = nMessageID,\
10823 nRecipient = nRecipient,\
10824 message = message,\
10825 sProtocol = sProtocol,\
10826 }\
10827\
10828 if nRecipient == os.getComputerID() then\
10829 -- Loopback to ourselves\
10830 os.queueEvent( \"rednet_message\", nReplyChannel, message, sProtocol )\
10831\
10832 else\
10833 -- Send on all open modems, to the target and to repeaters\
10834 local sent = false\
10835 for n,sModem in ipairs( peripheral.getNames() ) do\
10836 if isOpen( sModem ) then\
10837 peripheral.call( sModem, \"transmit\", nRecipient, nReplyChannel, tMessage );\
10838 peripheral.call( sModem, \"transmit\", CHANNEL_REPEAT, nReplyChannel, tMessage );\
10839 sent = true\
10840 end\
10841 end\
10842 end\
10843end\
10844\
10845function broadcast( message, sProtocol )\
10846 send( CHANNEL_BROADCAST, message, sProtocol )\
10847end\
10848\
10849function receive( sProtocolFilter, nTimeout )\
10850 -- The parameters used to be ( nTimeout ), detect this case for backwards compatibility\
10851 if type(sProtocolFilter) == \"number\" and nTimeout == nil then\
10852 sProtocolFilter, nTimeout = nil, sProtocolFilter\
10853 end\
10854\
10855 -- Start the timer\
10856 local timer = nil\
10857 local sFilter = nil\
10858 if nTimeout then\
10859 timer = os.startTimer( nTimeout )\
10860 sFilter = nil\
10861 else\
10862 sFilter = \"rednet_message\"\
10863 end\
10864\
10865 -- Wait for events\
10866 while true do\
10867 local sEvent, p1, p2, p3 = os.pullEvent( sFilter )\
10868 if sEvent == \"rednet_message\" then\
10869 -- Return the first matching rednet_message\
10870 local nSenderID, message, sProtocol = p1, p2, p3\
10871 if sProtocolFilter == nil or sProtocol == sProtocolFilter then\
10872 return nSenderID, message, sProtocol\
10873 end\
10874 elseif sEvent == \"timer\" then\
10875 -- Return nil if we timeout\
10876 if p1 == timer then\
10877 return nil\
10878 end\
10879 end\
10880 end\
10881end\
10882\
10883function host( sProtocol, sHostname )\
10884 if type( sProtocol ) ~= \"string\" or type( sHostname ) ~= \"string\" then\
10885 error( \"expected string, string\", 2 )\
10886 end\
10887 if sHostname == \"localhost\" then\
10888 error( \"Reserved hostname\", 2 )\
10889 end\
10890 if tHostnames[ sProtocol ] ~= sHostname then\
10891 if lookup( sProtocol, sHostname ) ~= nil then\
10892 error( \"Hostname in use\", 2 )\
10893 end\
10894 tHostnames[ sProtocol ] = sHostname\
10895 end\
10896end\
10897\
10898function unhost( sProtocol )\
10899 if type( sProtocol ) ~= \"string\" then\
10900 error( \"expected string\", 2 )\
10901 end\
10902 tHostnames[ sProtocol ] = nil\
10903end\
10904\
10905function lookup( sProtocol, sHostname )\
10906 if type( sProtocol ) ~= \"string\" then\
10907 error( \"expected string\", 2 )\
10908 end\
10909\
10910 -- Build list of host IDs\
10911 local tResults = nil\
10912 if sHostname == nil then\
10913 tResults = {}\
10914 end\
10915\
10916 -- Check localhost first\
10917 if tHostnames[ sProtocol ] then\
10918 if sHostname == nil then\
10919 table.insert( tResults, os.getComputerID() )\
10920 elseif sHostname == \"localhost\" or sHostname == tHostnames[ sProtocol ] then\
10921 return os.getComputerID()\
10922 end\
10923 end\
10924\
10925 if not isOpen() then\
10926 if tResults then\
10927 return unpack( tResults )\
10928 end\
10929 return nil\
10930 end\
10931\
10932 -- Broadcast a lookup packet\
10933 broadcast( {\
10934 sType = \"lookup\",\
10935 sProtocol = sProtocol,\
10936 sHostname = sHostname,\
10937 }, \"dns\" )\
10938\
10939 -- Start a timer\
10940 local timer = os.startTimer( 2 )\
10941\
10942 -- Wait for events\
10943 while true do\
10944 local event, p1, p2, p3 = os.pullEvent()\
10945 if event == \"rednet_message\" then\
10946 -- Got a rednet message, check if it's the response to our request\
10947 local nSenderID, tMessage, sMessageProtocol = p1, p2, p3\
10948 if sMessageProtocol == \"dns\" and tMessage.sType == \"lookup response\" then\
10949 if tMessage.sProtocol == sProtocol then\
10950 if sHostname == nil then\
10951 table.insert( tResults, nSenderID )\
10952 elseif tMessage.sHostname == sHostname then\
10953 return nSenderID\
10954 end\
10955 end\
10956 end\
10957 else\
10958 -- Got a timer event, check it's the end of our timeout\
10959 if p1 == timer then\
10960 break\
10961 end\
10962 end\
10963 end\
10964 if tResults then\
10965 return unpack( tResults )\
10966 end\
10967 return nil\
10968end\
10969\
10970local bRunning = false\
10971function run()\
10972 if bRunning then\
10973 error( \"rednet is already running\", 2 )\
10974 end\
10975 bRunning = true\
10976 \
10977 while bRunning do\
10978 local sEvent, p1, p2, p3, p4 = os.pullEventRaw()\
10979 if sEvent == \"modem_message\" then\
10980 -- Got a modem message, process it and add it to the rednet event queue\
10981 local sModem, nChannel, nReplyChannel, tMessage = p1, p2, p3, p4\
10982 if isOpen( sModem ) and ( nChannel == os.getComputerID() or nChannel == CHANNEL_BROADCAST ) then\
10983 if type( tMessage ) == \"table\" and tMessage.nMessageID then\
10984 if not tReceivedMessages[ tMessage.nMessageID ] then\
10985 tReceivedMessages[ tMessage.nMessageID ] = true\
10986 tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = nMessageID\
10987 os.queueEvent( \"rednet_message\", nReplyChannel, tMessage.message, tMessage.sProtocol )\
10988 end\
10989 end\
10990 end\
10991\
10992 elseif sEvent == \"rednet_message\" then\
10993 -- Got a rednet message (queued from above), respond to dns lookup\
10994 local nSenderID, tMessage, sProtocol = p1, p2, p3\
10995 if sProtocol == \"dns\" and tMessage.sType == \"lookup\" then\
10996 local sHostname = tHostnames[ tMessage.sProtocol ]\
10997 if sHostname ~= nil and (tMessage.sHostname == nil or tMessage.sHostname == sHostname) then\
10998 rednet.send( nSenderID, {\
10999 sType = \"lookup response\",\
11000 sHostname = sHostname,\
11001 sProtocol = tMessage.sProtocol,\
11002 }, \"dns\" )\
11003 end\
11004 end\
11005\
11006 elseif sEvent == \"timer\" then\
11007 -- Got a timer event, use it to clear the event queue\
11008 local nTimer = p1\
11009 local nMessage = tReceivedMessageTimeouts[ nTimer ]\
11010 if nMessage then\
11011 tReceivedMessageTimeouts[ nTimer ] = nil\
11012 tReceivedMessages[ nMessage ] = nil\
11013 end\
11014 end\
11015 end\
11016end\
11017",
11018 paintutils = "\
11019local function drawPixelInternal( xPos, yPos )\
11020 term.setCursorPos( xPos, yPos )\
11021 term.write(\" \")\
11022end\
11023\
11024local tColourLookup = {}\
11025for n=1,16 do\
11026 tColourLookup[ string.byte( \"0123456789abcdef\",n,n ) ] = 2^(n-1)\
11027end\
11028\
11029function loadImage( sPath )\
11030 if type( sPath ) ~= \"string\" then\
11031 error( \"Expected path\", 2 )\
11032 end\
11033\
11034 local tImage = {}\
11035 if fs.exists( sPath ) then\
11036 local file = io.open(sPath, \"r\" )\
11037 local sLine = file:read()\
11038 while sLine do\
11039 local tLine = {}\
11040 for x=1,sLine:len() do\
11041 tLine[x] = tColourLookup[ string.byte(sLine,x,x) ] or 0\
11042 end\
11043 table.insert( tImage, tLine )\
11044 sLine = file:read()\
11045 end\
11046 file:close()\
11047 return tImage\
11048 end\
11049 return nil\
11050end\
11051\
11052function drawPixel( xPos, yPos, nColour )\
11053 if type( xPos ) ~= \"number\" or type( yPos ) ~= \"number\" or (nColour ~= nil and type( nColour ) ~= \"number\") then\
11054 error( \"Expected x, y, colour\", 2 )\
11055 end\
11056 if nColour then\
11057 term.setBackgroundColor( nColour )\
11058 end\
11059 drawPixelInternal( xPos, yPos )\
11060end\
11061\
11062function drawLine( startX, startY, endX, endY, nColour )\
11063 if type( startX ) ~= \"number\" or type( startX ) ~= \"number\" or\
11064 type( endX ) ~= \"number\" or type( endY ) ~= \"number\" or\
11065 (nColour ~= nil and type( nColour ) ~= \"number\") then\
11066 error( \"Expected startX, startY, endX, endY, colour\", 2 )\
11067 end\
11068 \
11069 startX = math.floor(startX)\
11070 startY = math.floor(startY)\
11071 endX = math.floor(endX)\
11072 endY = math.floor(endY)\
11073\
11074 if nColour then\
11075 term.setBackgroundColor( nColour )\
11076 end\
11077 if startX == endX and startY == endY then\
11078 drawPixelInternal( startX, startY )\
11079 return\
11080 end\
11081 \
11082 local minX = math.min( startX, endX )\
11083 if minX == startX then\
11084 minY = startY\
11085 maxX = endX\
11086 maxY = endY\
11087 else\
11088 minY = endY\
11089 maxX = startX\
11090 maxY = startY\
11091 end\
11092\
11093 -- TODO: clip to screen rectangle?\
11094 \
11095 local xDiff = maxX - minX\
11096 local yDiff = maxY - minY\
11097 \
11098 if xDiff > math.abs(yDiff) then\
11099 local y = minY\
11100 local dy = yDiff / xDiff\
11101 for x=minX,maxX do\
11102 drawPixelInternal( x, math.floor( y + 0.5 ) )\
11103 y = y + dy\
11104 end\
11105 else\
11106 local x = minX\
11107 local dx = xDiff / yDiff\
11108 if maxY >= minY then\
11109 for y=minY,maxY do\
11110 drawPixelInternal( math.floor( x + 0.5 ), y )\
11111 x = x + dx\
11112 end\
11113 else\
11114 for y=minY,maxY,-1 do\
11115 drawPixelInternal( math.floor( x + 0.5 ), y )\
11116 x = x - dx\
11117 end\
11118 end\
11119 end\
11120end\
11121\
11122function drawBox( startX, startY, endX, endY, nColour )\
11123 if type( startX ) ~= \"number\" or type( startX ) ~= \"number\" or\
11124 type( endX ) ~= \"number\" or type( endY ) ~= \"number\" or\
11125 (nColour ~= nil and type( nColour ) ~= \"number\") then\
11126 error( \"Expected startX, startY, endX, endY, colour\", 2 )\
11127 end\
11128\
11129 startX = math.floor(startX)\
11130 startY = math.floor(startY)\
11131 endX = math.floor(endX)\
11132 endY = math.floor(endY)\
11133\
11134 if nColour then\
11135 term.setBackgroundColor( nColour )\
11136 end\
11137 if startX == endX and startY == endY then\
11138 drawPixelInternal( startX, startY )\
11139 return\
11140 end\
11141\
11142 local minX = math.min( startX, endX )\
11143 if minX == startX then\
11144 minY = startY\
11145 maxX = endX\
11146 maxY = endY\
11147 else\
11148 minY = endY\
11149 maxX = startX\
11150 maxY = startY\
11151 end\
11152\
11153 for x=minX,maxX do\
11154 drawPixelInternal( x, minY )\
11155 drawPixelInternal( x, maxY )\
11156 end\
11157\
11158 if (maxY - minY) >= 2 then\
11159 for y=(minY+1),(maxY-1) do\
11160 drawPixelInternal( minX, y )\
11161 drawPixelInternal( maxX, y )\
11162 end\
11163 end\
11164end\
11165\
11166function drawFilledBox( startX, startY, endX, endY, nColour )\
11167 if type( startX ) ~= \"number\" or type( startX ) ~= \"number\" or\
11168 type( endX ) ~= \"number\" or type( endY ) ~= \"number\" or\
11169 (nColour ~= nil and type( nColour ) ~= \"number\") then\
11170 error( \"Expected startX, startY, endX, endY, colour\", 2 )\
11171 end\
11172\
11173 startX = math.floor(startX)\
11174 startY = math.floor(startY)\
11175 endX = math.floor(endX)\
11176 endY = math.floor(endY)\
11177\
11178 if nColour then\
11179 term.setBackgroundColor( nColour )\
11180 end\
11181 if startX == endX and startY == endY then\
11182 drawPixelInternal( startX, startY )\
11183 return\
11184 end\
11185\
11186 local minX = math.min( startX, endX )\
11187 if minX == startX then\
11188 minY = startY\
11189 maxX = endX\
11190 maxY = endY\
11191 else\
11192 minY = endY\
11193 maxX = startX\
11194 maxY = startY\
11195 end\
11196\
11197 for x=minX,maxX do\
11198 for y=minY,maxY do\
11199 drawPixelInternal( x, y )\
11200 end\
11201 end\
11202end\
11203\
11204function drawImage( tImage, xPos, yPos )\
11205 if type( tImage ) ~= \"table\" or type( xPos ) ~= \"number\" or type( yPos ) ~= \"number\" then\
11206 error( \"Expected image, x, y\", 2 )\
11207 end\
11208 for y=1,#tImage do\
11209 local tLine = tImage[y]\
11210 for x=1,#tLine do\
11211 if tLine[x] > 0 then\
11212 term.setBackgroundColor( tLine[x] )\
11213 drawPixelInternal( x + xPos - 1, y + yPos - 1 )\
11214 end\
11215 end\
11216 end\
11217end\
11218",
11219 term = "\
11220local native = (term.native and term.native()) or term\
11221local redirectTarget = native\
11222\
11223local function wrap( _sFunction )\
11224 return function( ... )\
11225 return redirectTarget[ _sFunction ]( ... )\
11226 end\
11227end\
11228\
11229local term = {}\
11230\
11231term.redirect = function( target )\
11232 if target == nil or type( target ) ~= \"table\" then\
11233 error( \"Invalid redirect target\", 2 )\
11234 end\
11235 if target == term then\
11236 error( \"term is not a recommended redirect target, try term.current() instead\", 2 )\
11237 end\
11238 for k,v in pairs( native ) do\
11239 if type( k ) == \"string\" and type( v ) == \"function\" then\
11240 if type( target[k] ) ~= \"function\" then\
11241 target[k] = function()\
11242 error( \"Redirect object is missing method \"..k..\".\", 2 )\
11243 end\
11244 end\
11245 end\
11246 end\
11247 local oldRedirectTarget = redirectTarget\
11248 redirectTarget = target\
11249 return oldRedirectTarget\
11250end\
11251\
11252term.current = function()\
11253 return redirectTarget\
11254end\
11255\
11256term.native = function()\
11257 -- NOTE: please don't use this function unless you have to.\
11258 -- If you're running in a redirected or multitasked enviorment, term.native() will NOT be\
11259 -- the current terminal when your program starts up. It is far better to use term.current()\
11260 return native\
11261end\
11262\
11263for k,v in pairs( native ) do\
11264 if type( k ) == \"string\" and type( v ) == \"function\" then\
11265 if term[k] == nil then\
11266 term[k] = wrap( k )\
11267 end\
11268 end\
11269end\
11270 \
11271local env = getfenv()\
11272for k,v in pairs( term ) do\
11273 env[k] = v\
11274end\
11275",
11276 command = {
11277 commands = "\
11278if not commands then\
11279 error( \"Cannot load command API on normal computer\", 2 )\
11280end\
11281native = commands.native or commands\
11282\
11283local function collapseArgs( errorDepth, arg1, ... )\
11284 if arg1 ~= nil then\
11285 if type(arg1) == \"boolean\" or type(arg1) == \"number\" or type(arg1) == \"string\" then\
11286 return tostring(arg1) .. \" \" .. collapseArgs( errorDepth + 1, ... )\
11287 elseif type(arg1) == \"table\" then\
11288 return textutils.serialiseJSON(arg1) .. \" \" .. collapseArgs( errorDepth + 1, ... )\
11289 else\
11290 error( \"Expected string, number, boolean or table\", errorDepth )\
11291 end\
11292 end\
11293 return \"\"\
11294end\
11295\
11296-- Put native functions into the environment\
11297local env = getfenv()\
11298for k,v in pairs( native ) do\
11299 env[k] = v\
11300end\
11301\
11302-- Create wrapper functions for all the commands\
11303local tAsync = {}\
11304local tCommands = native.list()\
11305for n,sCommandName in ipairs(tCommands) do\
11306 if env[ sCommandName ] == nil then\
11307 env[ sCommandName ] = function( ... )\
11308 local sCommand = sCommandName .. \" \" .. collapseArgs( 3, ... )\
11309 return native.exec( sCommand )\
11310 end\
11311 tAsync[ sCommandName ] = function( ... )\
11312 local sCommand = sCommandName .. \" \" .. collapseArgs( 3, ... )\
11313 return native.execAsync( sCommand )\
11314 end\
11315 end\
11316end\
11317env.async = tAsync\
11318",
11319 },
11320 },
11321 startup = "\
11322-- Setup paths\
11323local sPath = \".:/rom/programs\"\
11324if term.isColor() then\
11325 sPath = sPath..\":/rom/programs/advanced\"\
11326end\
11327if turtle then\
11328 sPath = sPath..\":/rom/programs/turtle\"\
11329else\
11330 sPath = sPath..\":/rom/programs/rednet:/rom/programs/fun\"\
11331 if term.isColor() then\
11332 sPath = sPath..\":/rom/programs/fun/advanced\"\
11333 end\
11334end\
11335if pocket then\
11336 sPath = sPath..\":/rom/programs/pocket\"\
11337end\
11338if commands then\
11339 sPath = sPath..\":/rom/programs/command\"\
11340end\
11341if http then\
11342 sPath = sPath..\":/rom/programs/http\"\
11343end\
11344shell.setPath( sPath )\
11345help.setPath( \"/rom/help\" )\
11346\
11347-- Setup aliases\
11348shell.setAlias( \"ls\", \"list\" )\
11349shell.setAlias( \"dir\", \"list\" )\
11350shell.setAlias( \"cp\", \"copy\" )\
11351shell.setAlias( \"mv\", \"move\" )\
11352shell.setAlias( \"rm\", \"delete\" )\
11353shell.setAlias( \"clr\", \"clear\" )\
11354shell.setAlias( \"rs\", \"redstone\" )\
11355shell.setAlias( \"sh\", \"shell\" )\
11356if term.isColor() then\
11357 shell.setAlias( \"background\", \"bg\" )\
11358 shell.setAlias( \"foreground\", \"fg\" )\
11359end\
11360\
11361-- Run autorun files\
11362if fs.exists( \"/rom/autorun\" ) and fs.isDir( \"/rom/autorun\" ) then\
11363 local tFiles = fs.list( \"/rom/autorun\" )\
11364 table.sort( tFiles )\
11365 for n, sFile in ipairs( tFiles ) do\
11366 if string.sub( sFile, 1, 1 ) ~= \".\" then\
11367 local sPath = \"/rom/autorun/\"..sFile\
11368 if not fs.isDir( sPath ) then\
11369 shell.run( sPath )\
11370 end\
11371 end\
11372 end\
11373end\
11374\
11375-- Run the user created startup, either from disk drives or the root\
11376local sUserStartup = shell.resolveProgram( \"/startup\" )\
11377local bEnableDiskStartup = (commands == nil)\
11378if bEnableDiskStartup then\
11379 for n,sName in pairs( peripheral.getNames() ) do\
11380 if disk.isPresent( sName ) and disk.hasData( sName ) then\
11381 local sDiskStartup = shell.resolveProgram( \"/\" .. disk.getMountPath( sName ) .. \"/startup\" )\
11382 if sDiskStartup then\
11383 sUserStartup = sDiskStartup\
11384 break\
11385 end\
11386 end\
11387 end\
11388end\
11389if sUserStartup then\
11390 shell.run( sUserStartup )\
11391end\
11392",
11393 },
11394 fos = "--Start Environment Variables Setup\
11395environment = {\
11396 [\"system\"]={\
11397 [\"keys\"]={},\
11398 [\"terminal\"]={\
11399 [\"cmds\"]={}\
11400 },\
11401 [\"dirs\"]={}\
11402 },\
11403 [\"colors\"]={}\
11404}\
11405 --System\
11406 environment.system.branch = \"dev1\"\
11407 environment.system.keys = {nil,\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"0\",nil,nil,nil,nil,\"q\",\"w\",\"e\",\"r\",\"t\",\"y\",\"u\",\"i\",\"o\",\"p\",nil,nil,nil,nil,\"a\",\"s\",\"d\",\"f\",\"g\",\"h\",\"j\",\"k\",\"l\",nil,nil,nil,nil,nil,\"z\",\"x\",\"c\",\"v\",\"b\",\"n\",\"m\"}\
11408 environment.system.user = nil\
11409 environment.system.dirs = {\"bin\",\"boot\",\"dev\",\"etc\",\"home\",\"lib\",\"lost+found\",\"misc\",\"mnt\",\"net\",\"opt\",\"proc\",\"root\",\"sbin\",\"tmp\",\"usr\",\"var\"}\
11410 --Colors\
11411 environment.colors.background = colors.black\
11412 environment.colors.text = colors.white\
11413 environment.colors.vanity = colors.red\
11414--End Environmental Variable Setup\
11415\
11416_G[\"exitcmd\"] = false\
11417\
11418users = {\"fisher\"}\
11419passwords = {\"fish39575\"}\
11420\
11421\
11422function reset()\
11423 term.setBackgroundColor(environment.colors.background)\
11424 term.setTextColor(environment.colors.text)\
11425end\
11426\
11427function auth(user,pass)\
11428 for i = 1,#users do\
11429 if user == users[i] then\
11430 if pass == passwords[i] then\
11431 environment.system.user = user\
11432 return true\
11433 end\
11434 end\
11435 end\
11436 return false\
11437end\
11438\
11439function invisread()\
11440 returnstr = \"\"\
11441 term.setCursorBlink(true)\
11442 while true do\
11443 evnt = {os.pullEvent(\"key\")}\
11444 if evnt[2] == 14 then\
11445 returnstr = returnstr:sub(1,#returnstr-1)\
11446 elseif evnt[2] == 28 then\
11447 break\
11448 else\
11449 returnstr = returnstr..environment.system.keys[evnt[2]]\
11450 end\
11451 end\
11452 term.setCursorBlink(false)\
11453 return returnstr\
11454end\
11455\
11456function login()\
11457 reset()\
11458 term.setCursorPos(1,1)\
11459 term.clear()\
11460 print(\"\")\
11461 print(\"FishOS Core release \"..environment.system.branch..\" \"..os.computerID())\
11462 print(\"\")\
11463 write(\"FOSC \"..os.computerID()..\" login: \")\
11464 user = read()\
11465 write(\"Password: \")\
11466 pass = invisread()\
11467 tbl = {}\
11468 table.insert(tbl,user)\
11469 table.insert(tbl,pass)\
11470 return tbl\
11471end\
11472\
11473for i = 1,#users do\
11474 if not fs.isDir(\"home/\"..users[i]) then\
11475 fs.makeDir(\"home/\"..users[i])\
11476 end\
11477end\
11478\
11479for i = 1,#environment.system.dirs do\
11480 if not fs.isDir(environment.system.dirs[i]) then\
11481 fs.makeDir(environment.system.dirs[i])\
11482 end\
11483end\
11484\
11485function boot()\
11486 while true do\
11487 l = login()\
11488 if auth(l[1],l[2]) then\
11489 print(\"Welcome to FishOS Core Release \"..environment.system.branch..\" \"..os.computerID())\
11490 print(\" \")\
11491 print(\" * Documentation: /usr/share/doc/\")\
11492 print(\" * Support: XMedders ingame\")\
11493 print(\" \")\
11494 print(\"[num] Packages can be updated.\")\
11495 print(\"[num] updates are security updates.\")\
11496 print(\" \")\
11497 print(\" \")\
11498 write(\"The programs included with the FishOS system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/copyright\")\
11499 print(\" \")\
11500 write(\"FishOS comes with no warranty, but ask XMedders ingame for a new copy and he will give ya one :D\")\
11501 print(\" \")\
11502 print(\" \")\
11503 print(\" \")\
11504 print(\"Press any Key to continue\")\
11505 os.pullEvent(\"key\")\
11506 while true do\
11507 if _G[\"exitcmd\"] then\
11508 break\
11509 end\
11510 if shell.dir() == \"\" then\
11511 dir = \"\"\
11512 else\
11513 dir = \"/\"..shell.dir()\
11514 end\
11515 write(environment.system.user..\"@\"..os.getComputerLabel()..\"-\"..os.computerID()..\":~\"..dir..\"$ \")\
11516 console = read(nil, environment.system.terminal.cmds)\
11517 table.insert(environment.system.terminal.cmds,console)\
11518 found = false\
11519 if console:gsub(\" \",\"\") ~= \"\" then\
11520 args = {}\
11521 for arg in console:gmatch(\"%w+\") do table.insert(args, arg) end\
11522 file = fs.find(\"/bin/\"..args[1])\
11523 if #file >= 1 then\
11524 found = true\
11525 shell.run(\"/bin/\"..console)\
11526 end\
11527 end\
11528 if not found then\
11529 shell.run(console)\
11530 end\
11531 reset()\
11532 end\
11533 end\
11534 if _G[\"exitcmd\"] then\
11535 break\
11536 end\
11537 end\
11538end\
11539\
11540boot()",
11541 etc = {
11542 [ "meme.ff" ] = "hi\
11543",
11544 },
11545 tmp = {},
11546 boot = {},
11547 [ "lost+found" ] = {},
11548 root = {},
11549 proc = {},
11550}