· 7 years ago · Jan 26, 2019, 11:02 PM
1{
2 data = {
3 [ "help/pocket.txt" ] = "pocket is an API available on pocket computers, which allows modifying its upgrades.\
4Functions in the pocket API:\
5pocket.equipBack()\
6pocket.unequipBack()\
7\
8When equipping upgrades, it will search your inventory for a suitable upgrade, starting in the selected slot. If one cannot be found then it will check your offhand.",
9 [ "help/chat.txt" ] = "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.\
10\
11ex:\
12\"chat host forgecraft\" will create a chatroom with the name \"forgecraft\"\
13\"chat join forgecraft direwolf20\" will connect to the chatroom with the name \"forgecraft\", using the nickname \"direwolf20\"",
14 [ "apis/keys.lua" ] = "\
15-- Minecraft key code bindings\
16-- See http://www.minecraftwiki.net/wiki/Key_codes for more info\
17\
18local tKeys = {\
19 nil, \"one\", \"two\", \"three\", \"four\", -- 1\
20 \"five\", \"six\", \"seven\", \"eight\", \"nine\", -- 6\
21 \"zero\", \"minus\", \"equals\", \"backspace\",\"tab\", -- 11\
22 \"q\", \"w\", \"e\", \"r\", \"t\", -- 16\
23 \"y\", \"u\", \"i\", \"o\", \"p\", -- 21\
24 \"leftBracket\",\"rightBracket\",\"enter\",\"leftCtrl\",\"a\", -- 26\
25 \"s\", \"d\", \"f\", \"g\", \"h\", -- 31\
26 \"j\", \"k\", \"l\", \"semiColon\",\"apostrophe\", -- 36\
27 \"grave\", \"leftShift\",\"backslash\",\"z\", \"x\", -- 41\
28 \"c\", \"v\", \"b\", \"n\", \"m\", -- 46\
29 \"comma\", \"period\", \"slash\", \"rightShift\",\"multiply\", -- 51\
30 \"leftAlt\", \"space\", \"capsLock\", \"f1\", \"f2\", -- 56\
31 \"f3\", \"f4\", \"f5\", \"f6\", \"f7\", -- 61\
32 \"f8\", \"f9\", \"f10\", \"numLock\", \"scrollLock\", -- 66\
33 \"numPad7\", \"numPad8\", \"numPad9\", \"numPadSubtract\",\"numPad4\", -- 71\
34 \"numPad5\", \"numPad6\", \"numPadAdd\",\"numPad1\", \"numPad2\", -- 76\
35 \"numPad3\", \"numPad0\", \"numPadDecimal\",nil, nil, -- 81\
36 nil, \"f11\", \"f12\", nil, nil, -- 86\
37 nil, nil, nil, nil, nil, -- 91\
38 nil, nil, nil, nil, \"f13\", -- 96\
39 \"f14\", \"f15\", nil, nil, nil, -- 101\
40 nil, nil, nil, nil, nil, -- 106\
41 nil, \"kana\", nil, nil, nil, -- 111\
42 nil, nil, nil, nil, nil, -- 116\
43 \"convert\", nil, \"noconvert\",nil, \"yen\", -- 121\
44 nil, nil, nil, nil, nil, -- 126\
45 nil, nil, nil, nil, nil, -- 131\
46 nil, nil, nil, nil, nil, -- 136\
47 \"numPadEquals\",nil, nil, \"circumflex\",\"at\", -- 141\
48 \"colon\", \"underscore\",\"kanji\", \"stop\", \"ax\", -- 146\
49 nil, nil, nil, nil, nil, -- 151\
50 \"numPadEnter\",\"rightCtrl\",nil, nil, nil, -- 156\
51 nil, nil, nil, nil, nil, -- 161\
52 nil, nil, nil, nil, nil, -- 166\
53 nil, nil, nil, nil, nil, -- 171\
54 nil, nil, nil, \"numPadComma\",nil, -- 176\
55 \"numPadDivide\",nil, nil, \"rightAlt\", nil, -- 181\
56 nil, nil, nil, nil, nil, -- 186\
57 nil, nil, nil, nil, nil, -- 191\
58 nil, \"pause\", nil, \"home\", \"up\", -- 196\
59 \"pageUp\", nil, \"left\", nil, \"right\", -- 201\
60 nil, \"end\", \"down\", \"pageDown\", \"insert\", -- 206\
61 \"delete\" -- 211\
62}\
63\
64local keys = _ENV\
65for nKey, sKey in pairs( tKeys ) do\
66 keys[sKey] = nKey\
67end\
68keys[\"return\"] = keys.enter\
69--backwards compatibility to earlier, typo prone, versions\
70keys.scollLock = keys.scrollLock\
71keys.cimcumflex = keys.circumflex\
72\
73function getName( _nKey )\
74 if type( _nKey ) ~= \"number\" then\
75 error( \"bad argument #1 (expected number, got \" .. type( _nKey ) .. \")\", 2 )\
76 end\
77 return tKeys[ _nKey ]\
78end",
79 [ "programs/fun/advanced/levels/3.dat" ] = "2\
80 77777777\
81777888188777\
827b78777787b7\
8378787 78787\
8478787 78787\
8578887 78887\
86777877778777\
87 78838887\
88 77777777",
89 [ "programs/fun/advanced/levels/7.dat" ] = "3\
90728777778b7\
9178888888887\
9278777877787\
93787 787 787\
94787 7877788\
95787 7888889\
9688777877777\
97e888887\
987777887",
99 [ "help/textutils.txt" ] = "Functions in the Text Utilities API:\
100textutils.slowPrint( text )\
101textutils.tabulate( table, table2, ... )\
102textutils.pagedTabulate( table, table2, ... )\
103textutils.formatTime( time, bTwentyFourHour )\
104textutils.serialize( table )\
105textutils.unserialize( string )\
106textutils.serializeJSON( table, [useNBTStyle] )\
107textutils.urlEncode( string )\
108textutils.complete( string, table )",
109 [ "help/shell.txt" ] = "shell is the toplevel program which interprets commands and runs program.\
110Type \"help shellapi\" for information about the shell lua api.",
111 [ "programs/clear.lua" ] = "term.clear()\
112term.setCursorPos( 1, 1 )",
113 [ "programs/fun/advanced/levels/1.dat" ] = "1\
114 777\
115 7b7\
116 787\
1177777778777\
1187188888887\
1197777777777",
120 [ "help/math.txt" ] = "math is a standard Lua5.1 API.\
121Refer to http://www.lua.org/manual/5.1/ for more information.",
122 [ "help/hello.txt" ] = "hello prints the text \"Hello World!\" to the screen.",
123 [ "help/drives.txt" ] = "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\".\
124\
125Methods exposed by the Disk Drive:\
126isDiskPresent()\
127getDiskLabel()\
128setDiskLabel( label )\
129hasData()\
130getMountPath()\
131hasAudio()\
132getAudioTitle()\
133playAudio()\
134stopAudio()\
135ejectDisk()\
136getDiskID()\
137\
138Events fired by the Disk Drive:\
139\"disk\" when a disk or other item is inserted into the drive. Argument is the name of the drive.\
140\"disk_eject\" when a disk is removed from a drive. Argument is the name of the drive.\
141Type \"help events\" to learn about the event system.",
142 [ "help/table.txt" ] = "table is a standard Lua5.1 API.\
143Refer to http://www.lua.org/manual/5.1/ for more information.",
144 [ "help/worm.txt" ] = "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!",
145 [ "help/move.txt" ] = "mv moves a file or directory from one location to another.\
146\
147ex:\
148\"mv foo bar\" renames the file \"foo\" to \"bar\".\
149\"mv foo bar/foo\" moves the file \"foo\" to a folder called \"bar\".\
150\"mv disk/* disk2\" moves the contents of one disk to another",
151 [ "help/speakers.txt" ] = "The Speaker is a peripheral device available for CraftOS. Type \"help peripheral\" to learn about using the Peripheral API to connect with peripherals. When a Speaker is connected, peripheral.getType() will return \"speaker\".\
152\
153Methods exposed by the Speaker:\
154playSound( sResourceName, nVolume, nPitch )\
155playNote( sInstrumentName, nVolume, nPitch )\
156\
157Resource name is the same as used by the /playsound command, such as \"minecraft:entity.cow.ambient\".\
158Instruments are as follows: \"harp\", \"bass\", \"snare\", \"hat\", and \"basedrum\" with the addition of \"flute\", \"bell\", \"chime\", and \"guitar\" in Minecraft versions 1.12 and above.\
159Ticks is the amount of times a noteblock has been tuned (right clicked).",
160 [ "apis/vector.lua" ] = "\
161local vector = {\
162 add = function( self, o )\
163 return vector.new(\
164 self.x + o.x,\
165 self.y + o.y,\
166 self.z + o.z\
167 )\
168 end,\
169 sub = function( self, o )\
170 return vector.new(\
171 self.x - o.x,\
172 self.y - o.y,\
173 self.z - o.z\
174 )\
175 end,\
176 mul = function( self, m )\
177 return vector.new(\
178 self.x * m,\
179 self.y * m,\
180 self.z * m\
181 )\
182 end,\
183 div = function( self, m )\
184 return vector.new(\
185 self.x / m,\
186 self.y / m,\
187 self.z / m\
188 )\
189 end,\
190 unm = function( self )\
191 return vector.new(\
192 -self.x,\
193 -self.y,\
194 -self.z\
195 )\
196 end,\
197 dot = function( self, o )\
198 return self.x*o.x + self.y*o.y + self.z*o.z\
199 end,\
200 cross = function( self, o )\
201 return vector.new(\
202 self.y*o.z - self.z*o.y,\
203 self.z*o.x - self.x*o.z,\
204 self.x*o.y - self.y*o.x\
205 )\
206 end,\
207 length = function( self )\
208 return math.sqrt( self.x*self.x + self.y*self.y + self.z*self.z )\
209 end,\
210 normalize = function( self )\
211 return self:mul( 1 / self:length() )\
212 end,\
213 round = function( self, nTolerance )\
214 nTolerance = nTolerance or 1.0\
215 return vector.new(\
216 math.floor( (self.x + (nTolerance * 0.5)) / nTolerance ) * nTolerance,\
217 math.floor( (self.y + (nTolerance * 0.5)) / nTolerance ) * nTolerance,\
218 math.floor( (self.z + (nTolerance * 0.5)) / nTolerance ) * nTolerance\
219 )\
220 end,\
221 tostring = function( self )\
222 return self.x..\",\"..self.y..\",\"..self.z\
223 end,\
224}\
225\
226local vmetatable = {\
227 __index = vector,\
228 __add = vector.add,\
229 __sub = vector.sub,\
230 __mul = vector.mul,\
231 __div = vector.div,\
232 __unm = vector.unm,\
233 __tostring = vector.tostring,\
234}\
235\
236function new( x, y, z )\
237 local v = {\
238 x = tonumber(x) or 0,\
239 y = tonumber(y) or 0,\
240 z = tonumber(z) or 0\
241 }\
242 setmetatable( v, vmetatable )\
243 return v\
244end",
245 [ "help/type.txt" ] = "type determines the type of a file or directory. Prints \"file\", \"directory\" or \"does not exist\".",
246 [ "help/tunnel.txt" ] = "tunnel is a program for Mining Turtles. Tunnel will mine a 3x2 tunnel of the depth specified.\
247\
248ex:\
249\"tunnel 20\" will tunnel a tunnel 20 blocks long.",
250 [ "help/redstone.txt" ] = "The redstone program can be used to get, set or pulse redstone inputs and outputs from the computer.\
251\
252ex:\
253\"redstone probe\" will list all the redstone inputs to the computer\
254\"redstone set left true\" turns on the left redstone output.\
255\"redstone set right blue false\" turns off the blue wire in the bundled cable on the right redstone output.\
256\"redstone pulse front 10 1\" emits 10 one second redstone pulses on the front redstone output.\
257\
258Type \"help redstoneapi\" or \"help rs\" for information on the redstone Lua API.",
259 [ "programs/turtle/craft.lua" ] = "\
260if not turtle.craft then\
261 print( \"Requires a Crafty Turtle\" )\
262 return\
263end\
264\
265local tArgs = { ... }\
266local nLimit = nil\
267if #tArgs < 1 then\
268 print( \"Usage: craft [number]\" )\
269 return\
270else\
271 nLimit = tonumber( tArgs[1] )\
272end\
273\
274local nCrafted = 0\
275local nOldCount = turtle.getItemCount( turtle.getSelectedSlot() )\
276if turtle.craft( nLimit ) then\
277 local nNewCount = turtle.getItemCount( turtle.getSelectedSlot() )\
278 if nOldCount <= nLimit then\
279 nCrafted = nNewCount\
280 else\
281 nCrafted = nOldCount - nNewCount\
282 end\
283end\
284\
285if nCrafted > 1 then\
286 print( nCrafted..\" items crafted\" )\
287elseif nCrafted == 1 then\
288 print( \"1 item crafted\" )\
289else\
290 print( \"No items crafted\" )\
291end",
292 [ "programs/move.lua" ] = "\
293local tArgs = { ... }\
294if #tArgs < 2 then\
295 print( \"Usage: mv <source> <destination>\" )\
296 return\
297end\
298\
299local sSource = shell.resolve( tArgs[1] )\
300local sDest = shell.resolve( tArgs[2] )\
301local tFiles = fs.find( sSource )\
302if #tFiles > 0 then\
303 for n,sFile in ipairs( tFiles ) do\
304 if fs.isDir( sDest ) then\
305 fs.move( sFile, fs.combine( sDest, fs.getName(sFile) ) )\
306 elseif #tFiles == 1 then\
307 fs.move( sFile, sDest )\
308 else\
309 printError( \"Cannot overwrite file multiple times\" )\
310 return\
311 end\
312 end\
313else\
314 printError( \"No matching files\" )\
315end",
316 [ "programs/rename.lua" ] = "local tArgs = { ... }\
317if #tArgs < 2 then\
318 print( \"Usage: rename <source> <destination>\" )\
319 return\
320end\
321\
322local sSource = shell.resolve( tArgs[1] )\
323local sDest = shell.resolve( tArgs[2] )\
324\
325if fs.exists( sDest ) then\
326 printError( \"Destination exists\" )\
327end\
328\
329fs.move( sSource, sDest )",
330 [ "programs/fun/advanced/redirection.lua" ] = "--CCRedirection by : RamiLego4Game and Dan200--\
331--Based on Redirection by Dan200: http://www.redirectiongame.com--\
332--Clearing Screen--\
333\
334--Vars--\
335local TermW,TermH = term.getSize()\
336\
337local sLevelTitle\
338local tScreen\
339local oScreen\
340local SizeW,SizeH\
341local aExits\
342local fExit\
343local nSpeed\
344local Speed\
345local fSpeed\
346local fSpeedS\
347local bPaused\
348local Tick\
349local Blocks\
350local XOrgin,YOrgin\
351local fLevel\
352\
353local function reset()\
354 sLevelTitle = \"\"\
355 tScreen = {}\
356 oScreen = {}\
357 SizeW,SizeH = TermW,TermH\
358 aExits = 0\
359 fExit = \"nop\"\
360 nSpeed = 0.6\
361 Speed = nSpeed\
362 fSpeed = 0.2\
363 fSpeedS = false\
364 bPaused = false\
365 Tick = os.startTimer(Speed)\
366 Blocks = 0\
367 XOrgin,YOrgin = 1,1\
368\
369 term.setBackgroundColor(colors.black)\
370 term.setTextColor(colors.white)\
371 term.clear()\
372end\
373\
374local InterFace = {}\
375InterFace.cExit = colors.red\
376InterFace.cSpeedD = colors.white\
377InterFace.cSpeedA = colors.red\
378InterFace.cTitle = colors.red\
379\
380local cG = colors.lightGray\
381local cW = colors.gray\
382local cS = colors.black\
383local cR1 = colors.blue\
384local cR2 = colors.red\
385local cR3 = colors.green\
386local cR4 = colors.yellow\
387\
388local tArgs = { ... }\
389\
390--Functions--\
391local function printCentred( yc, stg )\
392 local xc = math.floor((TermW - string.len(stg)) / 2) + 1\
393 term.setCursorPos(xc,yc)\
394 term.write( stg )\
395end\
396\
397local function centerOrgin()\
398 XOrgin = math.floor((TermW/2)-(SizeW/2))\
399 YOrgin = math.floor((TermH/2)-(SizeH/2))\
400end\
401\
402local function reMap()\
403 tScreen = nil\
404 tScreen = {}\
405 for x=1,SizeW do\
406 tScreen[x] = {}\
407 for y=1,SizeH do\
408 tScreen[x][y] = { space = true, wall = false, ground = false, robot = \"zz\", start = \"zz\", exit = \"zz\" }\
409 end\
410 end\
411end\
412\
413local function tablecopy(t)\
414 local t2 = {}\
415 for k,v in pairs(t) do\
416 t2[k] = v\
417 end\
418 return t2\
419end\
420\
421local function buMap()\
422 oScreen = nil\
423 oScreen = {}\
424 for x=1,SizeW do\
425 oScreen[x] = {}\
426 for y=1,SizeH do\
427 oScreen[x][y] = tablecopy(tScreen[x][y])\
428 end\
429 end\
430end\
431\
432local function addRobot(x,y,side,color)\
433 local obj = tScreen[x][y]\
434 local data = side..color\
435 if obj.wall == nil and obj.robot == nil then\
436 tScreen[x][y].robot = data\
437 else\
438 obj.wall = nil\
439 obj.robot = \"zz\"\
440 tScreen[x][y].robot = data\
441 end\
442end\
443\
444local function addStart(x,y,side,color)\
445 local obj = tScreen[x][y]\
446 local data = side..color\
447 if obj.wall == nil and obj.space == nil then\
448 tScreen[x][y].start = data\
449 else\
450 obj.wall = nil\
451 obj.space = nil\
452 tScreen[x][y].start = data\
453 end\
454 aExits = aExits+1\
455end\
456\
457local function addGround(x,y)\
458 local obj = tScreen[x][y]\
459 if obj.space == nil and obj.exit == nil and obj.wall == nil and obj.robot == nil and obj.start == nil then\
460 tScreen[x][y].ground = true\
461 else\
462 obj.space = nil\
463 obj.exit = \"zz\"\
464 obj.wall = nil\
465 obj.robot = \"zz\"\
466 obj.start = \"zz\"\
467 tScreen[x][y].ground = true\
468 end\
469end\
470\
471local function addExit(x,y,cl)\
472 local obj = tScreen[x][y]\
473 if obj.space == nil and obj.ground == nil and obj.wall == nil and obj.robot == nil and obj.start == nil then\
474 tScreen[x][y].exit = cl\
475 else\
476 obj.space = nil\
477 obj.ground = nil\
478 obj.wall = nil\
479 obj.robot = \"zz\"\
480 obj.start = \"zz\"\
481 tScreen[x][y].exit = cl\
482 end\
483end\
484\
485local function addWall(x,y)\
486 local obj = tScreen[x][y]\
487 if obj == nil then\
488 return error(\"Here X\"..x..\" Y\"..y)\
489 end\
490 if obj.space == nil and obj.exit == nil and obj.ground == nil and obj.robot == nil and obj.start == nil then\
491 tScreen[x][y].wall = true\
492 else\
493 obj.space = nil\
494 obj.exit = nil\
495 obj.ground = nil\
496 obj.robot = nil\
497 obj.start = nil\
498 tScreen[x][y].wall = true\
499 end\
500end\
501\
502local function loadLevel(nNum)\
503 sLevelTitle = \"Level \"..nNum\
504 if nNum == nil then return error(\"nNum == nil\") end\
505 local sDir = fs.getDir( shell.getRunningProgram() )\
506 local sLevelD = sDir .. \"/levels/\" .. tostring(nNum)..\".dat\"\
507 if not ( fs.exists(sLevelD) or fs.isDir(sLevelD) ) then return error(\"Level Not Exists : \"..sLevelD) end\
508 fLevel = fs.open(sLevelD,\"r\")\
509 local Line = 0\
510 local wl = true\
511 Blocks = tonumber(string.sub(fLevel.readLine(),1,1))\
512 local xSize = string.len(fLevel.readLine())+2\
513 local Lines = 3\
514 while wl do\
515 local wLine = fLevel.readLine()\
516 if wLine == nil then\
517 fLevel.close()\
518 wl = false\
519 else\
520 xSize = math.max(string.len(wLine)+2,xSize)\
521 Lines = Lines + 1\
522 end\
523 end\
524 SizeW,SizeH = xSize,Lines\
525 reMap()\
526 fLevel = fs.open(sLevelD,\"r\")\
527 fLevel.readLine()\
528 for Line=2,Lines-1 do\
529 local sLine = fLevel.readLine()\
530 local chars = string.len(sLine)\
531 for char = 1, chars do\
532 local el = string.sub(sLine,char,char)\
533 if el == \"8\" then\
534 addGround(char+1,Line)\
535 elseif el == \"0\" then\
536 addStart(char+1,Line,\"a\",\"a\")\
537 elseif el == \"1\" then\
538 addStart(char+1,Line,\"b\",\"a\")\
539 elseif el == \"2\" then\
540 addStart(char+1,Line,\"c\",\"a\")\
541 elseif el == \"3\" then\
542 addStart(char+1,Line,\"d\",\"a\")\
543 elseif el == \"4\" then\
544 addStart(char+1,Line,\"a\",\"b\")\
545 elseif el == \"5\" then\
546 addStart(char+1,Line,\"b\",\"b\")\
547 elseif el == \"6\" then\
548 addStart(char+1,Line,\"c\",\"b\")\
549 elseif el == \"9\" then\
550 addStart(char+1,Line,\"d\",\"b\")\
551 elseif el == \"b\" then\
552 addExit(char+1,Line,\"a\")\
553 elseif el == \"e\" then\
554 addExit(char+1,Line,\"b\")\
555 elseif el == \"7\" then\
556 addWall(char+1,Line)\
557 end\
558 end\
559 end\
560 fLevel.close()\
561end\
562\
563local function drawStars()\
564 --CCR Background By : RamiLego--\
565 local cStar,cStarG,crStar,crStarB = colors.lightGray,colors.gray,\".\",\"*\"\
566 local DStar,BStar,nStar,gStar = 14,10,16,3\
567 local TermW,TermH = term.getSize()\
568\
569 term.clear()\
570 term.setCursorPos(1,1)\
571 for x=1,TermW do\
572 for y=1,TermH do\
573 local StarT = math.random(1,30)\
574 if StarT == DStar then\
575 term.setCursorPos(x,y)\
576 term.setTextColor(cStar)\
577 write(crStar)\
578 elseif StarT == BStar then\
579 term.setCursorPos(x,y)\
580 term.setTextColor(cStar)\
581 write(crStarB)\
582 elseif StarT == nStar then\
583 term.setCursorPos(x,y)\
584 term.setTextColor(cStarG)\
585 write(crStar)\
586 elseif StarT == gStar then\
587 term.setCursorPos(x,y)\
588 term.setTextColor(cStarG)\
589 write(crStarB)\
590 end\
591 end\
592 end\
593end\
594\
595local function drawMap()\
596 for x=1,SizeW do\
597 for y=1,SizeH do\
598\
599 local obj = tScreen[x][y]\
600 if obj.ground == true then\
601 paintutils.drawPixel(XOrgin+x,YOrgin+y+1,cG)\
602 end\
603 if obj.wall == true then\
604 paintutils.drawPixel(XOrgin+x,YOrgin+y+1,cW)\
605 end\
606\
607 local ex = tostring(tScreen[x][y].exit)\
608 if not(ex == \"zz\" or ex == \"nil\") then\
609 if ex == \"a\" then\
610 ex = cR1\
611 elseif ex == \"b\" then\
612 ex = cR2\
613 elseif ex == \"c\" then\
614 ex = cR3\
615 elseif ex == \"d\" then\
616 ex = cR4\
617 else\
618 return error(\"Exit Color Out\")\
619 end\
620 term.setBackgroundColor(cG)\
621 term.setTextColor(ex)\
622 term.setCursorPos(XOrgin+x,YOrgin+y+1)\
623 print(\"X\")\
624 end\
625\
626 local st = tostring(tScreen[x][y].start)\
627 if not(st == \"zz\" or st == \"nil\") then\
628 local Cr = string.sub(st,2,2)\
629 if Cr == \"a\" then\
630 Cr = cR1\
631 elseif Cr == \"b\" then\
632 Cr = cR2\
633 elseif Cr == \"c\" then\
634 Cr = cR3\
635 elseif Cr == \"d\" then\
636 Cr = cR4\
637 else\
638 return error(\"Start Color Out\")\
639 end\
640\
641 term.setTextColor(Cr)\
642 term.setBackgroundColor(cG)\
643 term.setCursorPos(XOrgin+x,YOrgin+y+1)\
644\
645 local sSide = string.sub(st,1,1)\
646 if sSide == \"a\" then\
647 print(\"^\")\
648 elseif sSide == \"b\" then\
649 print(\">\")\
650 elseif sSide == \"c\" then\
651 print(\"v\")\
652 elseif sSide == \"d\" then\
653 print(\"<\")\
654 else\
655 print(\"@\")\
656 end\
657 end\
658\
659 if obj.space == true then\
660 paintutils.drawPixel(XOrgin+x,YOrgin+y+1,cS)\
661 end\
662\
663 local rb = tostring(tScreen[x][y].robot)\
664 if not(rb == \"zz\" or rb == \"nil\") then\
665 local Cr = string.sub(rb,2,2)\
666 if Cr == \"a\" then\
667 Cr = cR1\
668 elseif Cr == \"b\" then\
669 Cr = cR2\
670 elseif Cr == \"c\" then\
671 Cr = cR3\
672 elseif Cr == \"d\" then\
673 Cr = cR4\
674 else\
675 Cr = colors.white\
676 end\
677 term.setBackgroundColor(Cr)\
678 term.setTextColor(colors.white)\
679 term.setCursorPos(XOrgin+x,YOrgin+y+1)\
680 local sSide = string.sub(rb,1,1)\
681 if sSide == \"a\" then\
682 print(\"^\")\
683 elseif sSide == \"b\" then\
684 print(\">\")\
685 elseif sSide == \"c\" then\
686 print(\"v\")\
687 elseif sSide == \"d\" then\
688 print(\"<\")\
689 else\
690 print(\"@\")\
691 end\
692 end\
693 end\
694 end\
695end\
696\
697local function isBrick(x,y)\
698 local brb = tostring(tScreen[x][y].robot)\
699 local bobj = oScreen[x][y]\
700 if (brb == \"zz\" or brb == \"nil\") and not bobj.wall == true then\
701 return false\
702 else\
703 return true\
704 end\
705end\
706\
707local function gRender(sContext)\
708 if sContext == \"start\" then\
709 for x=1,SizeW do\
710 for y=1,SizeH do\
711 local st = tostring(tScreen[x][y].start)\
712 if not(st == \"zz\" or st == \"nil\") then\
713 local Cr = string.sub(st,2,2)\
714 local sSide = string.sub(st,1,1)\
715 addRobot(x,y,sSide,Cr)\
716 end\
717 end\
718 end\
719 elseif sContext == \"tick\" then\
720 buMap()\
721 for x=1,SizeW do\
722 for y=1,SizeH do\
723 local rb = tostring(oScreen[x][y].robot)\
724 if not(rb == \"zz\" or rb == \"nil\") then\
725 local Cr = string.sub(rb,2,2)\
726 local sSide = string.sub(rb,1,1)\
727 local sobj = oScreen[x][y]\
728 if sobj.space == true then\
729 tScreen[x][y].robot = \"zz\"\
730 if not sSide == \"g\" then\
731 addRobot(x,y,\"g\",Cr)\
732 end\
733 elseif sobj.exit == Cr then\
734 if sSide == \"a\" or sSide == \"b\" or sSide == \"c\" or sSide == \"d\" then\
735 tScreen[x][y].robot = \"zz\"\
736 addRobot(x,y,\"g\",Cr)\
737 aExits = aExits-1\
738 end\
739 elseif sSide == \"a\" then\
740 local obj = isBrick(x,y-1)\
741 tScreen[x][y].robot = \"zz\"\
742 if not obj == true then\
743 addRobot(x,y-1,sSide,Cr)\
744 else\
745 local obj2 = isBrick(x-1,y)\
746 local obj3 = isBrick(x+1,y)\
747 if not obj2 == true and not obj3 == true then\
748 if Cr == \"a\" then\
749 addRobot(x,y,\"d\",Cr)\
750 elseif Cr == \"b\" then\
751 addRobot(x,y,\"b\",Cr)\
752 end\
753 elseif obj == true and obj2 == true and obj3 == true then\
754 addRobot(x,y,\"c\",Cr)\
755 else\
756 if obj3 == true then\
757 addRobot(x,y,\"d\",Cr)\
758 elseif obj2 == true then\
759 addRobot(x,y,\"b\",Cr)\
760 end\
761 end\
762 end\
763 elseif sSide == \"b\" then\
764 local obj = isBrick(x+1,y)\
765 tScreen[x][y].robot = \"zz\"\
766 if not obj == true then\
767 addRobot(x+1,y,sSide,Cr)\
768 else\
769 local obj2 = isBrick(x,y-1)\
770 local obj3 = isBrick(x,y+1)\
771 if not obj2 == true and not obj3 == true then\
772 if Cr == \"a\" then\
773 addRobot(x,y,\"a\",Cr)\
774 elseif Cr == \"b\" then\
775 addRobot(x,y,\"c\",Cr)\
776 end\
777 elseif obj == true and obj2 == true and obj3 == true then\
778 addRobot(x,y,\"d\",Cr)\
779 else\
780 if obj3 == true then\
781 addRobot(x,y,\"a\",Cr)\
782 elseif obj2 == true then\
783 addRobot(x,y,\"c\",Cr)\
784 end\
785 end\
786 end\
787 elseif sSide == \"c\" then\
788 local obj = isBrick(x,y+1)\
789 tScreen[x][y].robot = \"zz\"\
790 if not obj == true then\
791 addRobot(x,y+1,sSide,Cr)\
792 else\
793 local obj2 = isBrick(x-1,y)\
794 local obj3 = isBrick(x+1,y)\
795 if not obj2 == true and not obj3 == true then\
796 if Cr == \"a\" then\
797 addRobot(x,y,\"b\",Cr)\
798 elseif Cr == \"b\" then\
799 addRobot(x,y,\"d\",Cr)\
800 end\
801 elseif obj == true and obj2 == true and obj3 == true then\
802 addRobot(x,y,\"a\",Cr)\
803 else\
804 if obj3 == true then\
805 addRobot(x,y,\"d\",Cr)\
806 elseif obj2 == true then\
807 addRobot(x,y,\"b\",Cr)\
808 end\
809 end\
810 end\
811 elseif sSide == \"d\" then\
812 local obj = isBrick(x-1,y)\
813 tScreen[x][y].robot = \"zz\"\
814 if not obj == true then\
815 addRobot(x-1,y,sSide,Cr)\
816 else\
817 local obj2 = isBrick(x,y-1)\
818 local obj3 = isBrick(x,y+1)\
819 if not obj2 == true and not obj3 == true then\
820 if Cr == \"a\" then\
821 addRobot(x,y,\"c\",Cr)\
822 elseif Cr == \"b\" then\
823 addRobot(x,y,\"a\",Cr)\
824 end\
825 elseif obj == true and obj2 == true and obj3 == true then\
826 addRobot(x,y,\"b\",Cr)\
827 else\
828 if obj3 == true then\
829 addRobot(x,y,\"a\",Cr)\
830 elseif obj2 == true then\
831 addRobot(x,y,\"c\",Cr)\
832 end\
833 end\
834 end\
835 else\
836 addRobot(x,y,sSide,\"g\")\
837 end\
838 end\
839 end\
840 end\
841 end\
842end\
843\
844function InterFace.drawBar()\
845 term.setBackgroundColor( colors.black )\
846 term.setTextColor( InterFace.cTitle )\
847 printCentred( 1, \" \"..sLevelTitle..\" \" )\
848\
849 term.setCursorPos(1,1)\
850 term.setBackgroundColor( cW )\
851 write( \" \" )\
852 term.setBackgroundColor( colors.black )\
853 write( \" x \"..tostring(Blocks)..\" \" )\
854\
855 term.setCursorPos( TermW-8,TermH )\
856 term.setBackgroundColor( colors.black )\
857 term.setTextColour(InterFace.cSpeedD)\
858 write(\" <<\" )\
859 if bPaused then\
860 term.setTextColour(InterFace.cSpeedA)\
861 else\
862 term.setTextColour(InterFace.cSpeedD)\
863 end\
864 write(\" ||\")\
865 if fSpeedS then\
866 term.setTextColour(InterFace.cSpeedA)\
867 else\
868 term.setTextColour(InterFace.cSpeedD)\
869 end\
870 write(\" >>\")\
871\
872 term.setCursorPos( TermW-1, 1 )\
873 term.setBackgroundColor( colors.black )\
874 term.setTextColour( InterFace.cExit )\
875 write(\" X\")\
876 term.setBackgroundColor(colors.black)\
877end\
878\
879function InterFace.render()\
880 local id,p1,p2,p3 = os.pullEvent()\
881 if id == \"mouse_click\" then\
882 if p3 == 1 and p2 == TermW then\
883 return \"end\"\
884 elseif p3 == TermH and p2 >= TermW-7 and p2 <= TermW-6 then\
885 return \"retry\"\
886 elseif p3 == TermH and p2 >= TermW-4 and p2 <= TermW-3 then\
887 bPaused = not bPaused\
888 fSpeedS = false\
889 Speed = (bPaused and 0) or nSpeed\
890 if Speed > 0 then\
891 Tick = os.startTimer(Speed)\
892 else\
893 Tick = nil\
894 end\
895 InterFace.drawBar()\
896 elseif p3 == TermH and p2 >= TermW-1 then\
897 bPaused = false\
898 fSpeedS = not fSpeedS\
899 Speed = (fSpeedS and fSpeed) or nSpeed\
900 Tick = os.startTimer(Speed)\
901 InterFace.drawBar()\
902 elseif p3-1 < YOrgin+SizeH+1 and p3-1 > YOrgin and\
903 p2 < XOrgin+SizeW+1 and p2 > XOrgin then\
904 local eobj = tScreen[p2-XOrgin][p3-YOrgin-1]\
905 local erobj = tostring(tScreen[p2-XOrgin][p3-YOrgin-1].robot)\
906 if (erobj == \"zz\" or erobj == \"nil\") and not eobj.wall == true and not eobj.space == true and Blocks > 0 then\
907 addWall(p2-XOrgin,p3-YOrgin-1)\
908 Blocks = Blocks-1\
909 InterFace.drawBar()\
910 drawMap()\
911 end\
912 end\
913 elseif id == \"timer\" and p1 == Tick then\
914 gRender(\"tick\")\
915 drawMap()\
916 if Speed > 0 then\
917 Tick = os.startTimer(Speed)\
918 else\
919 Tick = nil\
920 end\
921 end\
922end\
923\
924local function startG(LevelN)\
925 drawStars()\
926 loadLevel(LevelN)\
927 centerOrgin()\
928 local create = true\
929 drawMap()\
930 InterFace.drawBar()\
931 gRender(\"start\")\
932 drawMap()\
933\
934 local NExit = true\
935 if aExits == 0 then\
936 NExit = false\
937 end\
938\
939 while true do\
940 local isExit = InterFace.render()\
941 if isExit == \"end\" then\
942 return nil\
943 elseif isExit == \"retry\" then\
944 return LevelN\
945 elseif fExit == \"yes\" then\
946 if fs.exists( fs.getDir( shell.getRunningProgram() ) .. \"/levels/\" .. tostring(LevelN + 1) .. \".dat\" ) then\
947 return LevelN + 1\
948 else\
949 return nil\
950 end\
951 end\
952 if aExits == 0 and NExit == true then\
953 fExit = \"yes\"\
954 end\
955 end\
956end\
957\
958local ok, err = true, nil\
959\
960--Menu--\
961local sStartLevel = tArgs[1]\
962if ok and not sStartLevel then\
963 ok, err = pcall( function()\
964 term.setTextColor(colors.white)\
965 term.setBackgroundColor( colors.black )\
966 term.clear()\
967 drawStars()\
968 term.setTextColor( colors.red )\
969 printCentred( TermH/2 - 1, \" REDIRECTION \" )\
970 printCentred( TermH/2 - 0, \" ComputerCraft Edition \" )\
971 term.setTextColor( colors.yellow )\
972 printCentred( TermH/2 + 2, \" Click to Begin \" )\
973 os.pullEvent( \"mouse_click\" )\
974 end )\
975end\
976\
977--Game--\
978if ok then\
979 ok,err = pcall( function()\
980 local nLevel\
981 if sStartLevel then\
982 nLevel = tonumber( sStartLevel )\
983 else\
984 nLevel = 1\
985 end\
986 while nLevel do\
987 reset()\
988 nLevel = startG(nLevel)\
989 end\
990 end )\
991end\
992\
993--Upsell screen--\
994if ok then\
995 ok, err = pcall( function()\
996 term.setTextColor(colors.white)\
997 term.setBackgroundColor( colors.black )\
998 term.clear()\
999 drawStars()\
1000 term.setTextColor( colors.red )\
1001 if TermW >= 40 then\
1002 printCentred( TermH/2 - 1, \" Thank you for playing Redirection \" )\
1003 printCentred( TermH/2 - 0, \" ComputerCraft Edition \" )\
1004 printCentred( TermH/2 + 2, \" Check out the full game: \" )\
1005 term.setTextColor( colors.yellow )\
1006 printCentred( TermH/2 + 3, \" http://www.redirectiongame.com \" )\
1007 else\
1008 printCentred( TermH/2 - 2, \" Thank you for \" )\
1009 printCentred( TermH/2 - 1, \" playing Redirection \" )\
1010 printCentred( TermH/2 - 0, \" ComputerCraft Edition \" )\
1011 printCentred( TermH/2 + 2, \" Check out the full game: \" )\
1012 term.setTextColor( colors.yellow )\
1013 printCentred( TermH/2 + 3, \" www.redirectiongame.com \" )\
1014 end\
1015 parallel.waitForAll(\
1016 function() sleep(2) end,\
1017 function() os.pullEvent( \"mouse_click\" ) end\
1018 )\
1019 end )\
1020end\
1021\
1022--Clear and exit--\
1023term.setCursorPos(1,1)\
1024term.setTextColor(colors.white)\
1025term.setBackgroundColor(colors.black)\
1026term.clear()\
1027if not ok then\
1028 if err == \"Terminated\" then\
1029 print( \"Check out the full version of Redirection:\" )\
1030 print( \"http://www.redirectiongame.com\" )\
1031 else\
1032 printError( err )\
1033 end\
1034end",
1035 [ "help/credits-emu.txt" ] = "CCEmuX would not be possible without the help of several open source projects:\
1036\
1037## Commons CLI\
1038Apache Commons CLI\
1039Copyright 2001-2017 The Apache Software Foundation\
1040\
1041This product includes software developed at\
1042The Apache Software Foundation (http://www.apache.org/).\
1043\
1044Licensed to the Apache Software Foundation (ASF) under one or more\
1045contributor license agreements. See the NOTICE file distributed with\
1046this work for additional information regarding copyright ownership.\
1047The ASF licenses this file to You under the Apache License, Version 2.0\
1048(the \"License\"); you may not use this file except in compliance with\
1049the License. You may obtain a copy of the License at\
1050\
1051 http://www.apache.org/licenses/LICENSE-2.0\
1052\
1053Unless required by applicable law or agreed to in writing, software\
1054distributed under the License is distributed on an \"AS IS\" BASIS,\
1055WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\
1056See the License for the specific language governing permissions and\
1057limitations under the License.\
1058\
1059## Commons Lang\
1060Apache Commons Lang\
1061Copyright 2001-2017 The Apache Software Foundation\
1062\
1063This product includes software developed at\
1064The Apache Software Foundation (http://www.apache.org/).\
1065\
1066This product includes software from the Spring Framework,\
1067under the Apache License 2.0 (see: StringUtils.containsWhitespace())\
1068\
1069Licensed to the Apache Software Foundation (ASF) under one or more\
1070contributor license agreements. See the NOTICE file distributed with\
1071this work for additional information regarding copyright ownership.\
1072The ASF licenses this file to You under the Apache License, Version 2.0\
1073(the \"License\"); you may not use this file except in compliance with\
1074the License. You may obtain a copy of the License at\
1075\
1076 http://www.apache.org/licenses/LICENSE-2.0\
1077\
1078Unless required by applicable law or agreed to in writing, software\
1079distributed under the License is distributed on an \"AS IS\" BASIS,\
1080WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\
1081See the License for the specific language governing permissions and\
1082limitations under the License.\
1083\
1084## Guava\
1085Copyright (C) 2008 The Guava Authors\
1086\
1087Licensed under the Apache License, Version 2.0 (the \"License\");\
1088you may not use this file except in compliance with the License.\
1089You may obtain a copy of the License at\
1090\
1091http://www.apache.org/licenses/LICENSE-2.0\
1092\
1093Unless required by applicable law or agreed to in writing, software\
1094distributed under the License is distributed on an \"AS IS\" BASIS,\
1095WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\
1096See the License for the specific language governing permissions and\
1097limitations under the License.\
1098\
1099## Log4J\
1100Apache Log4j API\
1101Copyright 1999-2017 The Apache Software Foundation\
1102\
1103This product includes software developed at\
1104The Apache Software Foundation (http://www.apache.org/).\
1105\
1106Licensed to the Apache Software Foundation (ASF) under one or more\
1107contributor license agreements. See the NOTICE file distributed with\
1108this work for additional information regarding copyright ownership.\
1109The ASF licenses this file to You under the Apache license, Version 2.0\
1110(the \"License\"); you may not use this file except in compliance with\
1111the License. You may obtain a copy of the License at\
1112\
1113 http://www.apache.org/licenses/LICENSE-2.0\
1114\
1115Unless required by applicable law or agreed to in writing, software\
1116distributed under the License is distributed on an \"AS IS\" BASIS,\
1117WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\
1118See the license for the specific language governing permissions and\
1119limitations under the license.\
1120\
1121## Netty\
1122Copyright 2012 The Netty Project\
1123\
1124The Netty Project licenses this file to you under the Apache License,\
1125version 2.0 (the \"License\"); you may not use this file except in compliance\
1126with the License. You may obtain a copy of the License at:\
1127\
1128 http://www.apache.org/licenses/LICENSE-2.0\
1129\
1130Unless required by applicable law or agreed to in writing, software\
1131distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\
1132WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\
1133License for the specific language governing permissions and limitations\
1134under the License.",
1135 [ "help/commandsapi.txt" ] = "Functions in the commands API:\
1136commands.exec( command )\
1137commands.execAsync( command )\
1138commands.list()\
1139commands.getBlockPosition()\
1140commands.getBlockInfo( x, y, z )\
1141commands.getBlockInfos( minx, miny, minz, maxx, maxy, maxz )\
1142\
1143The commands API can also be used to invoke commands directly, like so:\
1144commands.say( \"Hello World\" )\
1145commands.give( \"dan200\", \"minecraft:diamond\", 64 )\
1146This works with any command. Use \"commands.async\" instead of \"commands\" to execute asynchronously.\
1147\
1148The commands API is only available on Command Computers.\
1149Visit http://minecraft.gamepedia.com/Commands for documentation on all commands.",
1150 [ "help/io.txt" ] = "io is a standard Lua5.1 API, reimplemented for CraftOS. Not all the features are availiable.\
1151Refer to http://www.lua.org/manual/5.1/ for more information.",
1152 [ "help/dj.txt" ] = "dj plays Music Discs from disk drives attached to the computer.\
1153\
1154ex:\
1155\"dj\" or \"dj play\" plays a random disc.\
1156\"dj play left\" plays the disc in the drive on the left of the computer.\
1157\"dj stop\" stops the current disc.",
1158 [ "help/equip.txt" ] = "equip is a program for Turtles and Pocket Computer. equip will equip an item from the Turtle's inventory for use as a tool of peripheral. On a Pocket Computer you don't need to write a side.\
1159\
1160ex:\
1161\"equip 5 left\" will equip the item from slot 5 of the turtle onto the left side of the turtle\
1162\"equip\" on a Pocket Computer will equip the first item from your inventory.",
1163 [ "programs/advanced/multishell.lua" ] = "\
1164-- Setup process switching\
1165local parentTerm = term.current()\
1166local w,h = parentTerm.getSize()\
1167\
1168local tProcesses = {}\
1169local nCurrentProcess = nil\
1170local nRunningProcess = nil\
1171local bShowMenu = false\
1172local bWindowsResized = false\
1173\
1174local function selectProcess( n )\
1175 if nCurrentProcess ~= n then\
1176 if nCurrentProcess then\
1177 local tOldProcess = tProcesses[ nCurrentProcess ]\
1178 tOldProcess.window.setVisible( false )\
1179 end\
1180 nCurrentProcess = n\
1181 if nCurrentProcess then\
1182 local tNewProcess = tProcesses[ nCurrentProcess ]\
1183 tNewProcess.window.setVisible( true )\
1184 tNewProcess.bInteracted = true\
1185 end\
1186 end\
1187end\
1188\
1189local function setProcessTitle( n, sTitle )\
1190 tProcesses[ n ].sTitle = sTitle\
1191end\
1192\
1193local function resumeProcess( nProcess, sEvent, ... )\
1194 local tProcess = tProcesses[ nProcess ]\
1195 local sFilter = tProcess.sFilter\
1196 if sFilter == nil or sFilter == sEvent or sEvent == \"terminate\" then\
1197 local nPreviousProcess = nRunningProcess\
1198 nRunningProcess = nProcess\
1199 term.redirect( tProcess.terminal )\
1200 local ok, result = coroutine.resume( tProcess.co, sEvent, ... )\
1201 tProcess.terminal = term.current()\
1202 if ok then\
1203 tProcess.sFilter = result\
1204 else\
1205 printError( result )\
1206 end\
1207 nRunningProcess = nPreviousProcess\
1208 end\
1209end\
1210\
1211local function launchProcess( tProgramEnv, sProgramPath, ... )\
1212 local tProgramArgs = table.pack( ... )\
1213 local nProcess = #tProcesses + 1\
1214 local tProcess = {}\
1215 tProcess.sTitle = fs.getName( sProgramPath )\
1216 if bShowMenu then\
1217 tProcess.window = window.create( parentTerm, 1, 2, w, h-1, false )\
1218 else\
1219 tProcess.window = window.create( parentTerm, 1, 1, w, h, false )\
1220 end\
1221 tProcess.co = coroutine.create( function()\
1222 os.run( tProgramEnv, sProgramPath, table.unpack( tProgramArgs, 1, tProgramArgs.n ) )\
1223 if not tProcess.bInteracted then\
1224 term.setCursorBlink( false )\
1225 print( \"Press any key to continue\" )\
1226 os.pullEvent( \"char\" )\
1227 end\
1228 end )\
1229 tProcess.sFilter = nil\
1230 tProcess.terminal = tProcess.window\
1231 tProcess.bInteracted = false\
1232 tProcesses[ nProcess ] = tProcess\
1233 resumeProcess( nProcess )\
1234 return nProcess\
1235end\
1236\
1237local function cullProcess( nProcess )\
1238 local tProcess = tProcesses[ nProcess ]\
1239 if coroutine.status( tProcess.co ) == \"dead\" then\
1240 if nCurrentProcess == nProcess then\
1241 selectProcess( nil )\
1242 end\
1243 table.remove( tProcesses, nProcess )\
1244 if nCurrentProcess == nil then\
1245 if nProcess > 1 then\
1246 selectProcess( nProcess - 1 )\
1247 elseif #tProcesses > 0 then\
1248 selectProcess( 1 )\
1249 end\
1250 end\
1251 return true\
1252 end\
1253 return false\
1254end\
1255\
1256local function cullProcesses()\
1257 local culled = false\
1258 for n=#tProcesses,1,-1 do\
1259 culled = culled or cullProcess( n )\
1260 end\
1261 return culled\
1262end\
1263\
1264-- Setup the main menu\
1265local menuMainTextColor, menuMainBgColor, menuOtherTextColor, menuOtherBgColor\
1266if parentTerm.isColor() then\
1267 menuMainTextColor, menuMainBgColor = colors.yellow, colors.black\
1268 menuOtherTextColor, menuOtherBgColor = colors.black, colors.gray\
1269else\
1270 menuMainTextColor, menuMainBgColor = colors.white, colors.black\
1271 menuOtherTextColor, menuOtherBgColor = colors.black, colors.gray\
1272end\
1273\
1274local function redrawMenu()\
1275 if bShowMenu then\
1276 -- Draw menu\
1277 parentTerm.setCursorPos( 1, 1 )\
1278 parentTerm.setBackgroundColor( menuOtherBgColor )\
1279 parentTerm.clearLine()\
1280 for n=1,#tProcesses do\
1281 if n == nCurrentProcess then\
1282 parentTerm.setTextColor( menuMainTextColor )\
1283 parentTerm.setBackgroundColor( menuMainBgColor )\
1284 else\
1285 parentTerm.setTextColor( menuOtherTextColor )\
1286 parentTerm.setBackgroundColor( menuOtherBgColor )\
1287 end\
1288 parentTerm.write( \" \" .. tProcesses[n].sTitle .. \" \" )\
1289 end\
1290\
1291 -- Put the cursor back where it should be\
1292 local tProcess = tProcesses[ nCurrentProcess ]\
1293 if tProcess then\
1294 tProcess.window.restoreCursor()\
1295 end\
1296 end\
1297end\
1298\
1299local function resizeWindows()\
1300 local windowY, windowHeight\
1301 if bShowMenu then\
1302 windowY = 2\
1303 windowHeight = h-1\
1304 else\
1305 windowY = 1\
1306 windowHeight = h\
1307 end\
1308 for n=1,#tProcesses do\
1309 local tProcess = tProcesses[n]\
1310 local window = tProcess.window\
1311 local x,y = tProcess.window.getCursorPos()\
1312 if y > windowHeight then\
1313 tProcess.window.scroll( y - windowHeight )\
1314 tProcess.window.setCursorPos( x, windowHeight )\
1315 end\
1316 tProcess.window.reposition( 1, windowY, w, windowHeight )\
1317 end\
1318 bWindowsResized = true\
1319end\
1320\
1321local function setMenuVisible( bVis )\
1322 if bShowMenu ~= bVis then\
1323 bShowMenu = bVis\
1324 resizeWindows()\
1325 redrawMenu()\
1326 end\
1327end\
1328\
1329local multishell = {}\
1330\
1331function multishell.getFocus()\
1332 return nCurrentProcess\
1333end\
1334\
1335function multishell.setFocus( n )\
1336 if type( n ) ~= \"number\" then\
1337 error( \"bad argument #1 (expected number, got \" .. type( n ) .. \")\", 2 )\
1338 end\
1339 if n >= 1 and n <= #tProcesses then\
1340 selectProcess( n )\
1341 redrawMenu()\
1342 return true\
1343 end\
1344 return false\
1345end\
1346\
1347function multishell.getTitle( n )\
1348 if type( n ) ~= \"number\" then\
1349 error( \"bad argument #1 (expected number, got \" .. type( n ) .. \")\", 2 )\
1350 end\
1351 if n >= 1 and n <= #tProcesses then\
1352 return tProcesses[n].sTitle\
1353 end\
1354 return nil\
1355end\
1356\
1357function multishell.setTitle( n, sTitle )\
1358 if type( n ) ~= \"number\" then\
1359 error( \"bad argument #1 (expected number, got \" .. type( n ) .. \")\", 2 )\
1360 end\
1361 if type( sTitle ) ~= \"string\" then\
1362 error( \"bad argument #2 (expected string, got \" .. type( sTitle ) .. \")\", 2 )\
1363 end\
1364 if n >= 1 and n <= #tProcesses then\
1365 setProcessTitle( n, sTitle )\
1366 redrawMenu()\
1367 end\
1368end\
1369\
1370function multishell.getCurrent()\
1371 return nRunningProcess\
1372end\
1373\
1374function multishell.launch( tProgramEnv, sProgramPath, ... )\
1375 if type( tProgramEnv ) ~= \"table\" then\
1376 error( \"bad argument #1 (expected table, got \" .. type( tProgramEnv ) .. \")\", 2 )\
1377 end\
1378 if type( sProgramPath ) ~= \"string\" then\
1379 error( \"bad argument #2 (expected string, got \" .. type( sProgramPath ) .. \")\", 2 )\
1380 end\
1381 local previousTerm = term.current()\
1382 setMenuVisible( (#tProcesses + 1) >= 2 )\
1383 local nResult = launchProcess( tProgramEnv, sProgramPath, ... )\
1384 redrawMenu()\
1385 term.redirect( previousTerm )\
1386 return nResult\
1387end\
1388\
1389function multishell.getCount()\
1390 return #tProcesses\
1391end\
1392\
1393-- Begin\
1394parentTerm.clear()\
1395setMenuVisible( false )\
1396selectProcess( launchProcess( {\
1397 [\"shell\"] = shell,\
1398 [\"multishell\"] = multishell,\
1399}, \"/rom/programs/shell.lua\" ) )\
1400redrawMenu()\
1401\
1402-- Run processes\
1403while #tProcesses > 0 do\
1404 -- Get the event\
1405 local tEventData = table.pack( os.pullEventRaw() )\
1406 local sEvent = tEventData[1]\
1407 if sEvent == \"term_resize\" then\
1408 -- Resize event\
1409 w,h = parentTerm.getSize()\
1410 resizeWindows()\
1411 redrawMenu()\
1412\
1413 elseif sEvent == \"char\" or sEvent == \"key\" or sEvent == \"key_up\" or sEvent == \"paste\" or sEvent == \"terminate\" then\
1414 -- Keyboard event\
1415 -- Passthrough to current process\
1416 resumeProcess( nCurrentProcess, table.unpack( tEventData, 1, tEventData.n ) )\
1417 if cullProcess( nCurrentProcess ) then\
1418 setMenuVisible( #tProcesses >= 2 )\
1419 redrawMenu()\
1420 end\
1421\
1422 elseif sEvent == \"mouse_click\" then\
1423 -- Click event\
1424 local button, x, y = tEventData[2], tEventData[3], tEventData[4]\
1425 if bShowMenu and y == 1 then\
1426 -- Switch process\
1427 local tabStart = 1\
1428 for n=1,#tProcesses do\
1429 local tabEnd = tabStart + string.len( tProcesses[n].sTitle ) + 1\
1430 if x >= tabStart and x <= tabEnd then\
1431 selectProcess( n )\
1432 redrawMenu()\
1433 break\
1434 end\
1435 tabStart = tabEnd + 1\
1436 end\
1437 else\
1438 -- Passthrough to current process\
1439 resumeProcess( nCurrentProcess, sEvent, button, x, (bShowMenu and y-1) or y )\
1440 if cullProcess( nCurrentProcess ) then\
1441 setMenuVisible( #tProcesses >= 2 )\
1442 redrawMenu()\
1443 end\
1444 end\
1445\
1446 elseif sEvent == \"mouse_drag\" or sEvent == \"mouse_up\" or sEvent == \"mouse_scroll\" then\
1447 -- Other mouse event\
1448 local p1, x, y = tEventData[2], tEventData[3], tEventData[4]\
1449 if not (bShowMenu and y == 1) then\
1450 -- Passthrough to current process\
1451 resumeProcess( nCurrentProcess, sEvent, p1, x, (bShowMenu and y-1) or y )\
1452 if cullProcess( nCurrentProcess ) then\
1453 setMenuVisible( #tProcesses >= 2 )\
1454 redrawMenu()\
1455 end\
1456 end\
1457\
1458 else\
1459 -- Other event\
1460 -- Passthrough to all processes\
1461 local nLimit = #tProcesses -- Storing this ensures any new things spawned don't get the event\
1462 for n=1,nLimit do\
1463 resumeProcess( n, table.unpack( tEventData, 1, tEventData.n ) )\
1464 end\
1465 if cullProcesses() then\
1466 setMenuVisible( #tProcesses >= 2 )\
1467 redrawMenu()\
1468 end\
1469 end\
1470\
1471 if bWindowsResized then\
1472 -- Pass term_resize to all processes\
1473 local nLimit = #tProcesses -- Storing this ensures any new things spawned don't get the event\
1474 for n=1,nLimit do\
1475 resumeProcess( n, \"term_resize\" )\
1476 end\
1477 bWindowsResized = false\
1478 if cullProcesses() then\
1479 setMenuVisible( #tProcesses >= 2 )\
1480 redrawMenu()\
1481 end\
1482 end\
1483end\
1484\
1485-- Shutdown\
1486term.redirect( parentTerm )",
1487 [ "programs/fun/adventure.lua" ] = "\
1488local tBiomes = {\
1489 \"in a forest\",\
1490 \"in a pine forest\",\
1491 \"knee deep in a swamp\",\
1492 \"in a mountain range\",\
1493 \"in a desert\",\
1494 \"in a grassy plain\",\
1495 \"in frozen tundra\",\
1496}\
1497\
1498local function hasTrees( _nBiome )\
1499 return _nBiome <= 3\
1500end\
1501\
1502local function hasStone( _nBiome )\
1503 return _nBiome == 4\
1504end\
1505\
1506local function hasRivers( _nBiome )\
1507 return _nBiome ~= 3 and _nBiome ~= 5\
1508end\
1509\
1510local items = {\
1511 [\"no tea\"] = {\
1512 droppable = false,\
1513 desc = \"Pull yourself together man.\",\
1514 },\
1515 [\"a pig\"] = {\
1516 heavy = true,\
1517 creature = true,\
1518 drops = { \"some pork\" },\
1519 aliases = { \"pig\" },\
1520 desc = \"The pig has a square nose.\",\
1521 },\
1522 [\"a cow\"] = {\
1523 heavy = true,\
1524 creature = true,\
1525 aliases = { \"cow\" },\
1526 desc = \"The cow stares at you blankly.\",\
1527 },\
1528 [\"a sheep\"] = {\
1529 heavy = true,\
1530 creature = true,\
1531 hitDrops = { \"some wool\" },\
1532 aliases = { \"sheep\" },\
1533 desc = \"The sheep is fluffy.\",\
1534 },\
1535 [\"a chicken\"] = {\
1536 heavy = true,\
1537 creature = true,\
1538 drops = { \"some chicken\" },\
1539 aliases = { \"chicken\" },\
1540 desc = \"The chicken looks delicious.\",\
1541 },\
1542 [\"a creeper\"] = {\
1543 heavy = true,\
1544 creature = true,\
1545 monster = true,\
1546 aliases = { \"creeper\" },\
1547 desc = \"The creeper needs a hug.\",\
1548 },\
1549 [\"a skeleton\"] = {\
1550 heavy = true,\
1551 creature = true,\
1552 monster = true,\
1553 aliases = { \"skeleton\" },\
1554 nocturnal = true,\
1555 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.\",\
1556 },\
1557 [\"a zombie\"] = {\
1558 heavy = true,\
1559 creature = true,\
1560 monster = true,\
1561 aliases = { \"zombie\" },\
1562 nocturnal = true,\
1563 desc = \"All he wants to do is eat your brains.\",\
1564 },\
1565 [\"a spider\"] = {\
1566 heavy = true,\
1567 creature = true,\
1568 monster = true,\
1569 aliases = { \"spider\" },\
1570 desc = \"Dozens of eyes stare back at you.\",\
1571 },\
1572 [\"a cave entrance\"] = {\
1573 heavy = true,\
1574 aliases = { \"cave entance\", \"cave\", \"entrance\" },\
1575 desc = \"The entrance to the cave is dark, but it looks like you can climb down.\",\
1576 },\
1577 [\"an exit to the surface\"] = {\
1578 heavy = true,\
1579 aliases = { \"exit to the surface\", \"exit\", \"opening\" },\
1580 desc = \"You can just see the sky through the opening.\",\
1581 },\
1582 [\"a river\"] = {\
1583 heavy = true,\
1584 aliases = { \"river\" },\
1585 desc = \"The river flows majestically towards the horizon. It doesn't do anything else.\",\
1586 },\
1587 [\"some wood\"] = {\
1588 aliases = { \"wood\" },\
1589 material = true,\
1590 desc = \"You could easilly craft this wood into planks.\",\
1591 },\
1592 [\"some planks\"] = {\
1593 aliases = { \"planks\", \"wooden planks\", \"wood planks\" },\
1594 desc = \"You could easilly craft these planks into sticks.\",\
1595 },\
1596 [\"some sticks\"] = {\
1597 aliases = { \"sticks\", \"wooden sticks\", \"wood sticks\" },\
1598 desc = \"A perfect handle for torches or a pickaxe.\",\
1599 },\
1600 [\"a crafting table\"] = {\
1601 aliases = { \"crafting table\", \"craft table\", \"work bench\", \"workbench\", \"crafting bench\", \"table\", },\
1602 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.\",\
1603 },\
1604 [\"a furnace\"] = {\
1605 aliases = { \"furnace\" },\
1606 desc = \"It's a furnace. Between you and me, these don't actually do anything in this game.\",\
1607 },\
1608 [\"a wooden pickaxe\"] = {\
1609 aliases = { \"pickaxe\", \"pick\", \"wooden pick\", \"wooden pickaxe\", \"wood pick\", \"wood pickaxe\" },\
1610 tool = true,\
1611 toolLevel = 1,\
1612 toolType = \"pick\",\
1613 desc = \"The pickaxe looks good for breaking stone and coal.\",\
1614 },\
1615 [\"a stone pickaxe\"] = {\
1616 aliases = { \"pickaxe\", \"pick\", \"stone pick\", \"stone pickaxe\" },\
1617 tool = true,\
1618 toolLevel = 2,\
1619 toolType = \"pick\",\
1620 desc = \"The pickaxe looks good for breaking iron.\",\
1621 },\
1622 [\"an iron pickaxe\"] = {\
1623 aliases = { \"pickaxe\", \"pick\", \"iron pick\", \"iron pickaxe\" },\
1624 tool = true,\
1625 toolLevel = 3,\
1626 toolType = \"pick\",\
1627 desc = \"The pickaxe looks strong enough to break diamond.\",\
1628 },\
1629 [\"a diamond pickaxe\"] = {\
1630 aliases = { \"pickaxe\", \"pick\", \"diamond pick\", \"diamond pickaxe\" },\
1631 tool = true,\
1632 toolLevel = 4,\
1633 toolType = \"pick\",\
1634 desc = \"Best. Pickaxe. Ever.\",\
1635 },\
1636 [\"a wooden sword\"] = {\
1637 aliases = { \"sword\", \"wooden sword\", \"wood sword\" },\
1638 tool = true,\
1639 toolLevel = 1,\
1640 toolType = \"sword\",\
1641 desc = \"Flimsy, but better than nothing.\",\
1642 },\
1643 [\"a stone sword\"] = {\
1644 aliases = { \"sword\", \"stone sword\" },\
1645 tool = true,\
1646 toolLevel = 2,\
1647 toolType = \"sword\",\
1648 desc = \"A pretty good sword.\",\
1649 },\
1650 [\"an iron sword\"] = {\
1651 aliases = { \"sword\", \"iron sword\" },\
1652 tool = true,\
1653 toolLevel = 3,\
1654 toolType = \"sword\",\
1655 desc = \"This sword can slay any enemy.\",\
1656 },\
1657 [\"a diamond sword\"] = {\
1658 aliases = { \"sword\", \"diamond sword\" },\
1659 tool = true,\
1660 toolLevel = 4,\
1661 toolType = \"sword\",\
1662 desc = \"Best. Sword. Ever.\",\
1663 },\
1664 [\"a wooden shovel\"] = {\
1665 aliases = { \"shovel\", \"wooden shovel\", \"wood shovel\" },\
1666 tool = true,\
1667 toolLevel = 1,\
1668 toolType = \"shovel\",\
1669 desc = \"Good for digging holes.\",\
1670 },\
1671 [\"a stone shovel\"] = {\
1672 aliases = { \"shovel\", \"stone shovel\" },\
1673 tool = true,\
1674 toolLevel = 2,\
1675 toolType = \"shovel\",\
1676 desc = \"Good for digging holes.\",\
1677 },\
1678 [\"an iron shovel\"] = {\
1679 aliases = { \"shovel\", \"iron shovel\" },\
1680 tool = true,\
1681 toolLevel = 3,\
1682 toolType = \"shovel\",\
1683 desc = \"Good for digging holes.\",\
1684 },\
1685 [\"a diamond shovel\"] = {\
1686 aliases = { \"shovel\", \"diamond shovel\" },\
1687 tool = true,\
1688 toolLevel = 4,\
1689 toolType = \"shovel\",\
1690 desc = \"Good for digging holes.\",\
1691 },\
1692 [\"some coal\"] = {\
1693 aliases = { \"coal\" },\
1694 ore = true,\
1695 toolLevel = 1,\
1696 toolType = \"pick\",\
1697 desc = \"That coal looks useful for building torches, if only you had a pickaxe to mine it.\",\
1698 },\
1699 [\"some dirt\"] = {\
1700 aliases = { \"dirt\" },\
1701 material = true,\
1702 desc = \"Why not build a mud hut?\",\
1703 },\
1704 [\"some stone\"] = {\
1705 aliases = { \"stone\", \"cobblestone\" },\
1706 material = true,\
1707 ore = true,\
1708 infinite = true,\
1709 toolLevel = 1,\
1710 toolType = \"pick\",\
1711 desc = \"Stone is useful for building things, and making stone pickaxes.\",\
1712 },\
1713 [\"some iron\"] = {\
1714 aliases = { \"iron\" },\
1715 material = true,\
1716 ore = true,\
1717 toolLevel = 2,\
1718 toolType = \"pick\",\
1719 desc = \"That iron looks mighty strong, you'll need a stone pickaxe to mine it.\",\
1720 },\
1721 [\"some diamond\"] = {\
1722 aliases = { \"diamond\", \"diamonds\" },\
1723 material = true,\
1724 ore = true,\
1725 toolLevel = 3,\
1726 toolType = \"pick\",\
1727 desc = \"Sparkly, rare, and impossible to mine without an iron pickaxe.\",\
1728 },\
1729 [\"some torches\"] = {\
1730 aliases = { \"torches\", \"torch\" },\
1731 desc = \"These won't run out for a while.\",\
1732 },\
1733 [\"a torch\"] = {\
1734 aliases = { \"torch\" },\
1735 desc = \"Fire, fire, burn so bright, won't you light my cave tonight?\",\
1736 },\
1737 [\"some wool\"] = {\
1738 aliases = { \"wool\" },\
1739 material = true,\
1740 desc = \"Soft and good for building.\",\
1741 },\
1742 [\"some pork\"] = {\
1743 aliases = { \"pork\", \"porkchops\" },\
1744 food = true,\
1745 desc = \"Delicious and nutricious.\",\
1746 },\
1747 [\"some chicken\"] = {\
1748 aliases = { \"chicken\" },\
1749 food = true,\
1750 desc = \"Finger licking good.\",\
1751 },\
1752}\
1753\
1754local tAnimals = {\
1755 \"a pig\", \"a cow\", \"a sheep\", \"a chicken\",\
1756}\
1757\
1758local tMonsters = {\
1759 \"a creeper\", \"a skeleton\", \"a zombie\", \"a spider\"\
1760}\
1761\
1762local tRecipes = {\
1763 [\"some planks\"] = { \"some wood\" },\
1764 [\"some sticks\"] = { \"some planks\" },\
1765 [\"a crafting table\"] = { \"some planks\" },\
1766 [\"a furnace\"] = { \"some stone\" },\
1767 [\"some torches\"] = { \"some sticks\", \"some coal\" },\
1768\
1769 [\"a wooden pickaxe\"] = { \"some planks\", \"some sticks\" },\
1770 [\"a stone pickaxe\"] = { \"some stone\", \"some sticks\" },\
1771 [\"an iron pickaxe\"] = { \"some iron\", \"some sticks\" },\
1772 [\"a diamond pickaxe\"] = { \"some diamond\", \"some sticks\" },\
1773\
1774 [\"a wooden sword\"] = { \"some planks\", \"some sticks\" },\
1775 [\"a stone sword\"] = { \"some stone\", \"some sticks\" },\
1776 [\"an iron sword\"] = { \"some iron\", \"some sticks\" },\
1777 [\"a diamond sword\"] = { \"some diamond\", \"some sticks\" },\
1778\
1779 [\"a wooden shovel\"] = { \"some planks\", \"some sticks\" },\
1780 [\"a stone shovel\"] = { \"some stone\", \"some sticks\" },\
1781 [\"an iron shovel\"] = { \"some iron\", \"some sticks\" },\
1782 [\"a diamond shovel\"] = { \"some diamond\", \"some sticks\" },\
1783}\
1784\
1785local tGoWest = {\
1786 \"(life is peaceful there)\",\
1787 \"(lots of open air)\",\
1788 \"(to begin life anew)\",\
1789 \"(this is what we'll do)\",\
1790 \"(sun in winter time)\",\
1791 \"(we will do just fine)\",\
1792 \"(where the skies are blue)\",\
1793 \"(this and more we'll do)\",\
1794}\
1795local nGoWest = 0\
1796\
1797local bRunning = true\
1798local tMap = { { {}, }, }\
1799local x,y,z = 0,0,0\
1800local inventory = {\
1801 [\"no tea\"] = items[\"no tea\"],\
1802}\
1803\
1804local nTurn = 0\
1805local nTimeInRoom = 0\
1806local bInjured = false\
1807\
1808local tDayCycle = {\
1809 \"It is daytime.\",\
1810 \"It is daytime.\",\
1811 \"It is daytime.\",\
1812 \"It is daytime.\",\
1813 \"It is daytime.\",\
1814 \"It is daytime.\",\
1815 \"It is daytime.\",\
1816 \"It is daytime.\",\
1817 \"The sun is setting.\",\
1818 \"It is night.\",\
1819 \"It is night.\",\
1820 \"It is night.\",\
1821 \"It is night.\",\
1822 \"It is night.\",\
1823 \"The sun is rising.\",\
1824}\
1825\
1826local function getTimeOfDay()\
1827 return math.fmod( math.floor(nTurn/3), #tDayCycle ) + 1\
1828end\
1829\
1830local function isSunny()\
1831 return (getTimeOfDay() < 10)\
1832end\
1833\
1834local function getRoom( x, y, z, dontCreate )\
1835 tMap[x] = tMap[x] or {}\
1836 tMap[x][y] = tMap[x][y] or {}\
1837 if not tMap[x][y][z] and dontCreate ~= true then\
1838 local room = {\
1839 items = {},\
1840 exits = {},\
1841 nMonsters = 0,\
1842 }\
1843 tMap[x][y][z] = room\
1844\
1845 if y == 0 then\
1846 -- Room is above ground\
1847\
1848 -- Pick biome\
1849 room.nBiome = math.random( 1, #tBiomes )\
1850 room.trees = hasTrees( room.nBiome )\
1851\
1852 -- Add animals\
1853 if math.random(1,3) == 1 then\
1854 for n = 1,math.random(1,2) do\
1855 local sAnimal = tAnimals[ math.random( 1, #tAnimals ) ]\
1856 room.items[ sAnimal ] = items[ sAnimal ]\
1857 end\
1858 end\
1859\
1860 -- Add surface ore\
1861 if math.random(1,5) == 1 or hasStone( room.nBiome ) then\
1862 room.items[ \"some stone\" ] = items[ \"some stone\" ]\
1863 end\
1864 if math.random(1,8) == 1 then\
1865 room.items[ \"some coal\" ] = items[ \"some coal\" ]\
1866 end\
1867 if math.random(1,8) == 1 and hasRivers( room.nBiome ) then\
1868 room.items[ \"a river\" ] = items[ \"a river\" ]\
1869 end\
1870\
1871 -- Add exits\
1872 room.exits = {\
1873 [\"north\"] = true,\
1874 [\"south\"] = true,\
1875 [\"east\"] = true,\
1876 [\"west\"] = true,\
1877 }\
1878 if math.random(1,8) == 1 then\
1879 room.exits[\"down\"] = true\
1880 room.items[\"a cave entrance\"] = items[\"a cave entrance\"]\
1881 end\
1882\
1883 else\
1884 -- Room is underground\
1885 -- Add exits\
1886 local function tryExit( sDir, sOpp, x, y, z )\
1887 local adj = getRoom( x, y, z, true )\
1888 if adj then\
1889 if adj.exits[sOpp] then\
1890 room.exits[sDir] = true\
1891 end\
1892 else\
1893 if math.random(1,3) == 1 then\
1894 room.exits[sDir] = true\
1895 end\
1896 end\
1897 end\
1898\
1899 if y == -1 then\
1900 local above = getRoom( x, y + 1, z )\
1901 if above.exits[\"down\"] then\
1902 room.exits[\"up\"] = true\
1903 room.items[\"an exit to the surface\"] = items[\"an exit to the surface\"]\
1904 end\
1905 else\
1906 tryExit( \"up\", \"down\", x, y + 1, z )\
1907 end\
1908\
1909 if y > -3 then\
1910 tryExit( \"down\", \"up\", x, y - 1, z )\
1911 end\
1912\
1913 tryExit( \"east\", \"west\", x - 1, y, z )\
1914 tryExit( \"west\", \"east\", x + 1, y, z )\
1915 tryExit( \"north\", \"south\", x, y, z + 1 )\
1916 tryExit( \"south\", \"north\", x, y, z - 1 )\
1917\
1918 -- Add ores\
1919 room.items[ \"some stone\" ] = items[ \"some stone\" ]\
1920 if math.random(1,3) == 1 then\
1921 room.items[ \"some coal\" ] = items[ \"some coal\" ]\
1922 end\
1923 if math.random(1,8) == 1 then\
1924 room.items[ \"some iron\" ] = items[ \"some iron\" ]\
1925 end\
1926 if y == -3 and math.random(1,15) == 1 then\
1927 room.items[ \"some diamond\" ] = items[ \"some diamond\" ]\
1928 end\
1929\
1930 -- Turn out the lights\
1931 room.dark = true\
1932 end\
1933 end\
1934 return tMap[x][y][z]\
1935end\
1936\
1937local function itemize( t )\
1938 local item = next( t )\
1939 if item == nil then\
1940 return \"nothing\"\
1941 end\
1942\
1943 local text = \"\"\
1944 while item do\
1945 text = text .. item\
1946\
1947 local nextItem = next( t, item )\
1948 if nextItem ~= nil then\
1949 local nextNextItem = next( t, nextItem )\
1950 if nextNextItem == nil then\
1951 text = text .. \" and \"\
1952 else\
1953 text = text .. \", \"\
1954 end\
1955 end\
1956 item = nextItem\
1957 end\
1958 return text\
1959end\
1960\
1961local function findItem( _tList, _sQuery )\
1962 for sItem, tItem in pairs( _tList ) do\
1963 if sItem == _sQuery then\
1964 return sItem\
1965 end\
1966 if tItem.aliases ~= nil then\
1967 for n, sAlias in pairs( tItem.aliases ) do\
1968 if sAlias == _sQuery then\
1969 return sItem\
1970 end\
1971 end\
1972 end\
1973 end\
1974 return nil\
1975end\
1976\
1977local tMatches = {\
1978 [\"wait\"] = {\
1979 \"wait\",\
1980 },\
1981 [\"look\"] = {\
1982 \"look at the ([%a ]+)\",\
1983 \"look at ([%a ]+)\",\
1984 \"look\",\
1985 \"inspect ([%a ]+)\",\
1986 \"inspect the ([%a ]+)\",\
1987 \"inspect\",\
1988 },\
1989 [\"inventory\"] = {\
1990 \"check self\",\
1991 \"check inventory\",\
1992 \"inventory\",\
1993 \"i\",\
1994 },\
1995 [\"go\"] = {\
1996 \"go (%a+)\",\
1997 \"travel (%a+)\",\
1998 \"walk (%a+)\",\
1999 \"run (%a+)\",\
2000 \"go\",\
2001 },\
2002 [\"dig\"] = {\
2003 \"dig (%a+) using ([%a ]+)\",\
2004 \"dig (%a+) with ([%a ]+)\",\
2005 \"dig (%a+)\",\
2006 \"dig\",\
2007 },\
2008 [\"take\"] = {\
2009 \"pick up the ([%a ]+)\",\
2010 \"pick up ([%a ]+)\",\
2011 \"pickup ([%a ]+)\",\
2012 \"take the ([%a ]+)\",\
2013 \"take ([%a ]+)\",\
2014 \"take\",\
2015 },\
2016 [\"drop\"] = {\
2017 \"put down the ([%a ]+)\",\
2018 \"put down ([%a ]+)\",\
2019 \"drop the ([%a ]+)\",\
2020 \"drop ([%a ]+)\",\
2021 \"drop\",\
2022 },\
2023 [\"place\"] = {\
2024 \"place the ([%a ]+)\",\
2025 \"place ([%a ]+)\",\
2026 \"place\",\
2027 },\
2028 [\"cbreak\"] = {\
2029 \"punch the ([%a ]+)\",\
2030 \"punch ([%a ]+)\",\
2031 \"punch\",\
2032 \"break the ([%a ]+) with the ([%a ]+)\",\
2033 \"break ([%a ]+) with ([%a ]+) \",\
2034 \"break the ([%a ]+)\",\
2035 \"break ([%a ]+)\",\
2036 \"break\",\
2037 },\
2038 [\"mine\"] = {\
2039 \"mine the ([%a ]+) with the ([%a ]+)\",\
2040 \"mine ([%a ]+) with ([%a ]+)\",\
2041 \"mine ([%a ]+)\",\
2042 \"mine\",\
2043 },\
2044 [\"attack\"] = {\
2045 \"attack the ([%a ]+) with the ([%a ]+)\",\
2046 \"attack ([%a ]+) with ([%a ]+)\",\
2047 \"attack ([%a ]+)\",\
2048 \"attack\",\
2049 \"kill the ([%a ]+) with the ([%a ]+)\",\
2050 \"kill ([%a ]+) with ([%a ]+)\",\
2051 \"kill ([%a ]+)\",\
2052 \"kill\",\
2053 \"hit the ([%a ]+) with the ([%a ]+)\",\
2054 \"hit ([%a ]+) with ([%a ]+)\",\
2055 \"hit ([%a ]+)\",\
2056 \"hit\",\
2057 },\
2058 [\"craft\"] = {\
2059 \"craft a ([%a ]+)\",\
2060 \"craft some ([%a ]+)\",\
2061 \"craft ([%a ]+)\",\
2062 \"craft\",\
2063 \"make a ([%a ]+)\",\
2064 \"make some ([%a ]+)\",\
2065 \"make ([%a ]+)\",\
2066 \"make\",\
2067 },\
2068 [\"build\"] = {\
2069 \"build ([%a ]+) out of ([%a ]+)\",\
2070 \"build ([%a ]+) from ([%a ]+)\",\
2071 \"build ([%a ]+)\",\
2072 \"build\",\
2073 },\
2074 [\"eat\"] = {\
2075 \"eat a ([%a ]+)\",\
2076 \"eat the ([%a ]+)\",\
2077 \"eat ([%a ]+)\",\
2078 \"eat\",\
2079 },\
2080 [\"help\"] = {\
2081 \"help me\",\
2082 \"help\",\
2083 },\
2084 [\"exit\"] = {\
2085 \"exit\",\
2086 \"quit\",\
2087 \"goodbye\",\
2088 \"good bye\",\
2089 \"bye\",\
2090 \"farewell\",\
2091 },\
2092}\
2093\
2094local commands = {}\
2095local function doCommand( text )\
2096 if text == \"\" then\
2097 commands[ \"noinput\" ]()\
2098 return\
2099 end\
2100\
2101 for sCommand, t in pairs( tMatches ) do\
2102 for n, sMatch in pairs( t ) do\
2103 local tCaptures = { string.match( text, \"^\" .. sMatch .. \"$\" ) }\
2104 if #tCaptures ~= 0 then\
2105 local fnCommand = commands[ sCommand ]\
2106 if #tCaptures == 1 and tCaptures[1] == sMatch then\
2107 fnCommand()\
2108 else\
2109 fnCommand( table.unpack( tCaptures ) )\
2110 end\
2111 return\
2112 end\
2113 end\
2114 end\
2115 commands[ \"badinput\" ]()\
2116end\
2117\
2118function commands.wait()\
2119 print( \"Time passes...\" )\
2120end\
2121\
2122function commands.look( _sTarget )\
2123 local room = getRoom( x,y,z )\
2124 if room.dark then\
2125 print( \"It is pitch dark.\" )\
2126 return\
2127 end\
2128\
2129 if _sTarget == nil then\
2130 -- Look at the world\
2131 if y == 0 then\
2132 io.write( \"You are standing \" .. tBiomes[room.nBiome] .. \". \" )\
2133 print( tDayCycle[ getTimeOfDay() ] )\
2134 else\
2135 io.write( \"You are underground. \" )\
2136 if next( room.exits ) ~= nil then\
2137 print( \"You can travel \"..itemize( room.exits )..\".\" )\
2138 else\
2139 print()\
2140 end\
2141 end\
2142 if next( room.items ) ~= nil then\
2143 print( \"There is \" .. itemize( room.items ) .. \" here.\" )\
2144 end\
2145 if room.trees then\
2146 print( \"There are trees here.\" )\
2147 end\
2148\
2149 else\
2150 -- Look at stuff\
2151 if room.trees and (_sTarget == \"tree\" or _sTarget == \"trees\") then\
2152 print( \"The trees look easy to break.\" )\
2153 elseif _sTarget == \"self\" or _sTarget == \"myself\" then\
2154 print( \"Very handsome.\" )\
2155 else\
2156 local tItem = nil\
2157 local sItem = findItem( room.items, _sTarget )\
2158 if sItem then\
2159 tItem = room.items[sItem]\
2160 else\
2161 sItem = findItem( inventory, _sTarget )\
2162 if sItem then\
2163 tItem = inventory[sItem]\
2164 end\
2165 end\
2166\
2167 if tItem then\
2168 print( tItem.desc or (\"You see nothing special about \"..sItem..\".\") )\
2169 else\
2170 print( \"You don't see any \".._sTarget..\" here.\" )\
2171 end\
2172 end\
2173 end\
2174end\
2175\
2176function commands.go( _sDir )\
2177 local room = getRoom( x,y,z )\
2178 if _sDir == nil then\
2179 print( \"Go where?\" )\
2180 return\
2181 end\
2182\
2183 if nGoWest ~= nil then\
2184 if _sDir == \"west\" then\
2185 nGoWest = nGoWest + 1\
2186 if nGoWest > #tGoWest then\
2187 nGoWest = 1\
2188 end\
2189 print( tGoWest[ nGoWest ] )\
2190 else\
2191 if nGoWest > 0 or nTurn > 6 then\
2192 nGoWest = nil\
2193 end\
2194 end\
2195 end\
2196\
2197 if room.exits[_sDir] == nil then\
2198 print( \"You can't go that way.\" )\
2199 return\
2200 end\
2201\
2202 if _sDir == \"north\" then\
2203 z = z + 1\
2204 elseif _sDir == \"south\" then\
2205 z = z - 1\
2206 elseif _sDir == \"east\" then\
2207 x = x - 1\
2208 elseif _sDir == \"west\" then\
2209 x = x + 1\
2210 elseif _sDir == \"up\" then\
2211 y = y + 1\
2212 elseif _sDir == \"down\" then\
2213 y = y - 1\
2214 else\
2215 print( \"I don't understand that direction.\" )\
2216 return\
2217 end\
2218\
2219 nTimeInRoom = 0\
2220 doCommand( \"look\" )\
2221end\
2222\
2223function commands.dig( _sDir, _sTool )\
2224 local room = getRoom( x,y,z )\
2225 if _sDir == nil then\
2226 print( \"Dig where?\" )\
2227 return\
2228 end\
2229\
2230 local sTool = nil\
2231 local tTool = nil\
2232 if _sTool ~= nil then\
2233 sTool = findItem( inventory, _sTool )\
2234 if not sTool then\
2235 print( \"You're not carrying a \".._sTool..\".\" )\
2236 return\
2237 end\
2238 tTool = inventory[ sTool ]\
2239 end\
2240\
2241 local bActuallyDigging = (room.exits[ _sDir ] ~= true)\
2242 if bActuallyDigging then\
2243 if sTool == nil or tTool.toolType ~= \"pick\" then\
2244 print( \"You need to use a pickaxe to dig through stone.\" )\
2245 return\
2246 end\
2247 end\
2248\
2249 if _sDir == \"north\" then\
2250 room.exits[\"north\"] = true\
2251 z = z + 1\
2252 getRoom( x, y, z ).exits[\"south\"] = true\
2253\
2254 elseif _sDir == \"south\" then\
2255 room.exits[\"south\"] = true\
2256 z = z - 1\
2257 getRoom( x, y, z ).exits[\"north\"] = true\
2258\
2259 elseif _sDir == \"east\" then\
2260 room.exits[\"east\"] = true\
2261 x = x - 1\
2262 getRoom( x, y, z ).exits[\"west\"] = true\
2263\
2264 elseif _sDir == \"west\" then\
2265 room.exits[\"west\"] = true\
2266 x = x + 1\
2267 getRoom( x, y, z ).exits[\"east\"] = true\
2268\
2269 elseif _sDir == \"up\" then\
2270 if y == 0 then\
2271 print( \"You can't dig that way.\" )\
2272 return\
2273 end\
2274\
2275 room.exits[\"up\"] = true\
2276 if y == -1 then\
2277 room.items[ \"an exit to the surface\" ] = items[ \"an exit to the surface\" ]\
2278 end\
2279 y = y + 1\
2280\
2281 room = getRoom( x, y, z )\
2282 room.exits[\"down\"] = true\
2283 if y == 0 then\
2284 room.items[ \"a cave entrance\" ] = items[ \"a cave entrance\" ]\
2285 end\
2286\
2287 elseif _sDir == \"down\" then\
2288 if y <= -3 then\
2289 print( \"You hit bedrock.\" )\
2290 return\
2291 end\
2292\
2293 room.exits[\"down\"] = true\
2294 if y == 0 then\
2295 room.items[ \"a cave entrance\" ] = items[ \"a cave entrance\" ]\
2296 end\
2297 y = y - 1\
2298\
2299 room = getRoom( x, y, z )\
2300 room.exits[\"up\"] = true\
2301 if y == -1 then\
2302 room.items[ \"an exit to the surface\" ] = items[ \"an exit to the surface\" ]\
2303 end\
2304\
2305 else\
2306 print( \"I don't understand that direction.\" )\
2307 return\
2308 end\
2309\
2310 --\
2311 if bActuallyDigging then\
2312 if _sDir == \"down\" and y == -1 or\
2313 _sDir == \"up\" and y == 0 then\
2314 inventory[ \"some dirt\" ] = items[ \"some dirt\" ]\
2315 inventory[ \"some stone\" ] = items[ \"some stone\" ]\
2316 print( \"You dig \".._sDir..\" using \"..sTool..\" and collect some dirt and stone.\" )\
2317 else\
2318 inventory[ \"some stone\" ] = items[ \"some stone\" ]\
2319 print( \"You dig \".._sDir..\" using \"..sTool..\" and collect some stone.\" )\
2320 end\
2321 end\
2322\
2323 nTimeInRoom = 0\
2324 doCommand( \"look\" )\
2325end\
2326\
2327function commands.inventory()\
2328 print( \"You are carrying \" .. itemize( inventory ) .. \".\" )\
2329end\
2330\
2331function commands.drop( _sItem )\
2332 if _sItem == nil then\
2333 print( \"Drop what?\" )\
2334 return\
2335 end\
2336\
2337 local room = getRoom( x,y,z )\
2338 local sItem = findItem( inventory, _sItem )\
2339 if sItem then\
2340 local tItem = inventory[ sItem ]\
2341 if tItem.droppable == false then\
2342 print( \"You can't drop that.\" )\
2343 else\
2344 room.items[ sItem ] = tItem\
2345 inventory[ sItem ] = nil\
2346 print( \"Dropped.\" )\
2347 end\
2348 else\
2349 print( \"You don't have a \".._sItem..\".\" )\
2350 end\
2351end\
2352\
2353function commands.place( _sItem )\
2354 if _sItem == nil then\
2355 print( \"Place what?\" )\
2356 return\
2357 end\
2358\
2359 if _sItem == \"torch\" or _sItem == \"a torch\" then\
2360 local room = getRoom( x,y,z )\
2361 if inventory[\"some torches\"] or inventory[\"a torch\"] then\
2362 inventory[\"a torch\"] = nil\
2363 room.items[\"a torch\"] = items[\"a torch\"]\
2364 if room.dark then\
2365 print( \"The cave lights up under the torchflame.\" )\
2366 room.dark = false\
2367 elseif y == 0 and not isSunny() then\
2368 print( \"The night gets a little brighter.\" )\
2369 else\
2370 print( \"Placed.\" )\
2371 end\
2372 else\
2373 print( \"You don't have torches.\" )\
2374 end\
2375 return\
2376 end\
2377\
2378 commands.drop( _sItem )\
2379end\
2380\
2381function commands.take( _sItem )\
2382 if _sItem == nil then\
2383 print( \"Take what?\" )\
2384 return\
2385 end\
2386\
2387 local room = getRoom( x,y,z )\
2388 local sItem = findItem( room.items, _sItem )\
2389 if sItem then\
2390 local tItem = room.items[ sItem ]\
2391 if tItem.heavy == true then\
2392 print( \"You can't carry \"..sItem..\".\" )\
2393 elseif tItem.ore == true then\
2394 print( \"You need to mine this ore.\" )\
2395 else\
2396 if tItem.infinite ~= true then\
2397 room.items[ sItem ] = nil\
2398 end\
2399 inventory[ sItem ] = tItem\
2400\
2401 if inventory[\"some torches\"] and inventory[\"a torch\"] then\
2402 inventory[\"a torch\"] = nil\
2403 end\
2404 if sItem == \"a torch\" and y < 0 then\
2405 room.dark = true\
2406 print( \"The cave plunges into darkness.\" )\
2407 else\
2408 print( \"Taken.\" )\
2409 end\
2410 end\
2411 else\
2412 print( \"You don't see a \".._sItem..\" here.\" )\
2413 end\
2414end\
2415\
2416function commands.mine( _sItem, _sTool )\
2417 if _sItem == nil then\
2418 print( \"Mine what?\" )\
2419 return\
2420 end\
2421 if _sTool == nil then\
2422 print( \"Mine \".._sItem..\" with what?\" )\
2423 return\
2424 end\
2425 commands.cbreak( _sItem, _sTool )\
2426end\
2427\
2428function commands.attack( _sItem, _sTool )\
2429 if _sItem == nil then\
2430 print( \"Attack what?\" )\
2431 return\
2432 end\
2433 commands.cbreak( _sItem, _sTool )\
2434end\
2435\
2436function commands.cbreak( _sItem, _sTool )\
2437 if _sItem == nil then\
2438 print( \"Break what?\" )\
2439 return\
2440 end\
2441\
2442 local sTool = nil\
2443 if _sTool ~= nil then\
2444 sTool = findItem( inventory, _sTool )\
2445 if sTool == nil then\
2446 print( \"You're not carrying a \".._sTool..\".\" )\
2447 return\
2448 end\
2449 end\
2450\
2451 local room = getRoom( x,y,z )\
2452 if _sItem == \"tree\" or _sItem == \"trees\" or _sItem == \"a tree\" then\
2453 print( \"The tree breaks into blocks of wood, which you pick up.\" )\
2454 inventory[ \"some wood\" ] = items[ \"some wood\" ]\
2455 return\
2456 elseif _sItem == \"self\" or _sItem == \"myself\" then\
2457 if term.isColour() then\
2458 term.setTextColour( colours.red )\
2459 end\
2460 print( \"You have died.\" )\
2461 print( \"Score: &e0\" )\
2462 term.setTextColour( colours.white )\
2463 bRunning = false\
2464 return\
2465 end\
2466\
2467 local sItem = findItem( room.items, _sItem )\
2468 if sItem then\
2469 local tItem = room.items[ sItem ]\
2470 if tItem.ore == true then\
2471 -- Breaking ore\
2472 if not sTool then\
2473 print( \"You need a tool to break this ore.\" )\
2474 return\
2475 end\
2476 local tTool = inventory[ sTool ]\
2477 if tTool.tool then\
2478 if tTool.toolLevel < tItem.toolLevel then\
2479 print( sTool ..\" is not strong enough to break this ore.\" )\
2480 elseif tTool.toolType ~= tItem.toolType then\
2481 print( \"You need a different kind of tool to break this ore.\" )\
2482 else\
2483 print( \"The ore breaks, dropping \"..sItem..\", which you pick up.\" )\
2484 inventory[ sItem ] = items[ sItem ]\
2485 if tItem.infinite ~= true then\
2486 room.items[ sItem ] = nil\
2487 end\
2488 end\
2489 else\
2490 print( \"You can't break \"..sItem..\" with \"..sTool..\".\")\
2491 end\
2492\
2493 elseif tItem.creature == true then\
2494 -- Fighting monsters (or pigs)\
2495 local toolLevel = 0\
2496 local tTool = nil\
2497 if sTool then\
2498 tTool = inventory[ sTool ]\
2499 if tTool.toolType == \"sword\" then\
2500 toolLevel = tTool.toolLevel\
2501 end\
2502 end\
2503\
2504 local tChances = { 0.2, 0.4, 0.55, 0.8, 1 }\
2505 if math.random() <= tChances[ toolLevel + 1 ] then\
2506 room.items[ sItem ] = nil\
2507 print( \"The \"..tItem.aliases[1]..\" dies.\" )\
2508\
2509 if tItem.drops then\
2510 for n, sDrop in pairs( tItem.drops ) do\
2511 if not room.items[sDrop] then\
2512 print( \"The \"..tItem.aliases[1]..\" dropped \"..sDrop..\".\" )\
2513 room.items[sDrop] = items[sDrop]\
2514 end\
2515 end\
2516 end\
2517\
2518 if tItem.monster then\
2519 room.nMonsters = room.nMonsters - 1\
2520 end\
2521 else\
2522 print( \"The \"..tItem.aliases[1]..\" is injured by your blow.\" )\
2523 end\
2524\
2525 if tItem.hitDrops then\
2526 for n, sDrop in pairs( tItem.hitDrops ) do\
2527 if not room.items[sDrop] then\
2528 print( \"The \"..tItem.aliases[1]..\" dropped \"..sDrop..\".\" )\
2529 room.items[sDrop] = items[sDrop]\
2530 end\
2531 end\
2532 end\
2533\
2534 else\
2535 print( \"You can't break \"..sItem..\".\" )\
2536 end\
2537 else\
2538 print( \"You don't see a \".._sItem..\" here.\" )\
2539 end\
2540end\
2541\
2542function commands.craft( _sItem )\
2543 if _sItem == nil then\
2544 print( \"Craft what?\" )\
2545 return\
2546 end\
2547\
2548 if _sItem == \"computer\" or _sItem == \"a computer\" then\
2549 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.\" )\
2550 if term.isColour() then\
2551 term.setTextColour( colours.red )\
2552 end\
2553 print( \"You have died.\" )\
2554 print( \"Score: &e0\" )\
2555 term.setTextColour( colours.white )\
2556 bRunning = false\
2557 return\
2558 end\
2559\
2560 local room = getRoom( x,y,z )\
2561 local sItem = findItem( items, _sItem )\
2562 local tRecipe = (sItem and tRecipes[ sItem ]) or nil\
2563 if tRecipe then\
2564 for n,sReq in ipairs( tRecipe ) do\
2565 if inventory[sReq] == nil then\
2566 print( \"You don't have the items you need to craft \"..sItem..\".\" )\
2567 return\
2568 end\
2569 end\
2570\
2571 for n,sReq in ipairs( tRecipe ) do\
2572 inventory[sReq] = nil\
2573 end\
2574 inventory[ sItem ] = items[ sItem ]\
2575 if inventory[\"some torches\"] and inventory[\"a torch\"] then\
2576 inventory[\"a torch\"] = nil\
2577 end\
2578 print( \"Crafted.\" )\
2579 else\
2580 print( \"You don't know how to make \"..(sItem or _sItem)..\".\" )\
2581 end\
2582end\
2583\
2584function commands.build( _sThing, _sMaterial )\
2585 if _sThing == nil then\
2586 print( \"Build what?\" )\
2587 return\
2588 end\
2589\
2590 local sMaterial = nil\
2591 if _sMaterial == nil then\
2592 for sItem, tItem in pairs( inventory ) do\
2593 if tItem.material then\
2594 sMaterial = sItem\
2595 break\
2596 end\
2597 end\
2598 if sMaterial == nil then\
2599 print( \"You don't have any building materials.\" )\
2600 return\
2601 end\
2602 else\
2603 sMaterial = findItem( inventory, _sMaterial )\
2604 if not sMaterial then\
2605 print( \"You don't have any \".._sMaterial )\
2606 return\
2607 end\
2608\
2609 if inventory[sMaterial].material ~= true then\
2610 print( sMaterial..\" is not a good building material.\" )\
2611 return\
2612 end\
2613 end\
2614\
2615 local alias = nil\
2616 if string.sub(_sThing, 1, 1) == \"a\" then\
2617 alias = string.match( _sThing, \"a ([%a ]+)\" )\
2618 end\
2619\
2620 local room = getRoom( x,y,z )\
2621 inventory[sMaterial] = nil\
2622 room.items[ _sThing ] = {\
2623 heavy = true,\
2624 aliases = { alias },\
2625 desc = \"As you look at your creation (made from \"..sMaterial..\"), you feel a swelling sense of pride.\",\
2626 }\
2627\
2628 print( \"Your construction is complete.\" )\
2629end\
2630\
2631function commands.help()\
2632 local sText =\
2633 \"Welcome to adventure, the greatest text adventure game on CraftOS. \" ..\
2634 \"To get around the world, type actions, and the adventure will \" ..\
2635 \"be read back to you. The actions availiable to you are go, look, inspect, inventory, \" ..\
2636 \"take, drop, place, punch, attack, mine, dig, craft, build, eat and exit.\"\
2637 print( sText )\
2638end\
2639\
2640function commands.eat( _sItem )\
2641 if _sItem == nil then\
2642 print( \"Eat what?\" )\
2643 return\
2644 end\
2645\
2646 local sItem = findItem( inventory, _sItem )\
2647 if not sItem then\
2648 print( \"You don't have any \".._sItem..\".\" )\
2649 return\
2650 end\
2651\
2652 local tItem = inventory[sItem]\
2653 if tItem.food then\
2654 print( \"That was delicious!\" )\
2655 inventory[sItem] = nil\
2656\
2657 if bInjured then\
2658 print( \"You are no longer injured.\" )\
2659 bInjured = false\
2660 end\
2661 else\
2662 print( \"You can't eat \"..sItem..\".\" )\
2663 end\
2664end\
2665\
2666function commands.exit()\
2667 bRunning = false\
2668end\
2669\
2670function commands.badinput()\
2671 local tResponses = {\
2672 \"I don't understand.\",\
2673 \"I don't understand you.\",\
2674 \"You can't do that.\",\
2675 \"Nope.\",\
2676 \"Huh?\",\
2677 \"Say again?\",\
2678 \"That's crazy talk.\",\
2679 \"Speak clearly.\",\
2680 \"I'll think about it.\",\
2681 \"Let me get back to you on that one.\",\
2682 \"That doesn't make any sense.\",\
2683 \"What?\",\
2684 }\
2685 print( tResponses[ math.random(1,#tResponses) ] )\
2686end\
2687\
2688function commands.noinput()\
2689 local tResponses = {\
2690 \"Speak up.\",\
2691 \"Enunciate.\",\
2692 \"Project your voice.\",\
2693 \"Don't be shy.\",\
2694 \"Use your words.\",\
2695 }\
2696 print( tResponses[ math.random(1,#tResponses) ] )\
2697end\
2698\
2699local function simulate()\
2700 local bNewMonstersThisRoom = false\
2701\
2702 -- Spawn monsters in nearby rooms\
2703 for sx = -2,2 do\
2704 for sy = -1,1 do\
2705 for sz = -2,2 do\
2706 local h = y + sy\
2707 if h >= -3 and h <= 0 then\
2708 local room = getRoom( x + sx, h, z + sz )\
2709\
2710 -- Spawn monsters\
2711 if room.nMonsters < 2 and\
2712 ((h == 0 and not isSunny() and not room.items[\"a torch\"]) or room.dark) and\
2713 math.random(1,6) == 1 then\
2714\
2715 local sMonster = tMonsters[ math.random(1,#tMonsters) ]\
2716 if room.items[ sMonster ] == nil then\
2717 room.items[ sMonster ] = items[ sMonster ]\
2718 room.nMonsters = room.nMonsters + 1\
2719\
2720 if sx == 0 and sy == 0 and sz == 0 and not room.dark then\
2721 print( \"From the shadows, \"..sMonster..\" appears.\" )\
2722 bNewMonstersThisRoom = true\
2723 end\
2724 end\
2725 end\
2726\
2727 -- Burn monsters\
2728 if h == 0 and isSunny() then\
2729 for n,sMonster in ipairs( tMonsters ) do\
2730 if room.items[sMonster] and items[sMonster].nocturnal then\
2731 room.items[sMonster] = nil\
2732 if sx == 0 and sy == 0 and sz == 0 and not room.dark then\
2733 print( \"With the sun high in the sky, the \"..items[sMonster].aliases[1]..\" bursts into flame and dies.\" )\
2734 end\
2735 room.nMonsters = room.nMonsters - 1\
2736 end\
2737 end\
2738 end\
2739 end\
2740 end\
2741 end\
2742 end\
2743\
2744 -- Make monsters attack\
2745 local room = getRoom( x, y, z )\
2746 if nTimeInRoom >= 2 and not bNewMonstersThisRoom then\
2747 for n,sMonster in ipairs( tMonsters ) do\
2748 if room.items[sMonster] then\
2749 if math.random(1,4) == 1 and\
2750 not (y == 0 and isSunny() and (sMonster == \"a spider\")) then\
2751 if sMonster == \"a creeper\" then\
2752 if room.dark then\
2753 print( \"A creeper explodes.\" )\
2754 else\
2755 print( \"The creeper explodes.\" )\
2756 end\
2757 room.items[sMonster] = nil\
2758 room.nMonsters = room.nMonsters - 1\
2759 else\
2760 if room.dark then\
2761 print( \"A \"..items[sMonster].aliases[1]..\" attacks you.\" )\
2762 else\
2763 print( \"The \"..items[sMonster].aliases[1]..\" attacks you.\" )\
2764 end\
2765 end\
2766\
2767 if bInjured then\
2768 if term.isColour() then\
2769 term.setTextColour( colours.red )\
2770 end\
2771 print( \"You have died.\" )\
2772 print( \"Score: &e0\" )\
2773 term.setTextColour( colours.white )\
2774 bRunning = false\
2775 return\
2776 else\
2777 bInjured = true\
2778 end\
2779\
2780 break\
2781 end\
2782 end\
2783 end\
2784 end\
2785\
2786 -- Always print this\
2787 if bInjured then\
2788 if term.isColour() then\
2789 term.setTextColour( colours.red )\
2790 end\
2791 print( \"You are injured.\" )\
2792 term.setTextColour( colours.white )\
2793 end\
2794\
2795 -- Advance time\
2796 nTurn = nTurn + 1\
2797 nTimeInRoom = nTimeInRoom + 1\
2798end\
2799\
2800doCommand( \"look\" )\
2801simulate()\
2802\
2803local tCommandHistory = {}\
2804while bRunning do\
2805 if term.isColour() then\
2806 term.setTextColour( colours.yellow )\
2807 end\
2808 write( \"? \" )\
2809 term.setTextColour( colours.white )\
2810\
2811 local sRawLine = read( nil, tCommandHistory )\
2812 table.insert( tCommandHistory, sRawLine )\
2813\
2814 local sLine = nil\
2815 for match in string.gmatch(sRawLine, \"%a+\") do\
2816 if sLine then\
2817 sLine = sLine .. \" \" .. string.lower(match)\
2818 else\
2819 sLine = string.lower(match)\
2820 end\
2821 end\
2822\
2823 doCommand( sLine or \"\" )\
2824 if bRunning then\
2825 simulate()\
2826 end\
2827end",
2828 [ "programs/pocket/equip.lua" ] = "local ok, err = pcall( pocket.equipBack )\
2829if not ok then\
2830 printError( \"Nothing to equip\" )\
2831else\
2832 print( \"Item equipped\" )\
2833end",
2834 [ "help/eject.txt" ] = "eject ejects the contents of an attached disk drive.\
2835\
2836ex:\
2837\"eject left\" ejects the contents of the disk drive to the left of the computer.",
2838 [ "programs/copy.lua" ] = "\
2839local tArgs = { ... }\
2840if #tArgs < 2 then\
2841 print( \"Usage: cp <source> <destination>\" )\
2842 return\
2843end\
2844\
2845local sSource = shell.resolve( tArgs[1] )\
2846local sDest = shell.resolve( tArgs[2] )\
2847local tFiles = fs.find( sSource )\
2848if #tFiles > 0 then\
2849 for n,sFile in ipairs( tFiles ) do\
2850 if fs.isDir( sDest ) then\
2851 fs.copy( sFile, fs.combine( sDest, fs.getName(sFile) ) )\
2852 elseif #tFiles == 1 then\
2853 if fs.exists( sDest ) then\
2854 printError( \"Destination exists\" )\
2855 else\
2856 fs.copy( sFile, sDest )\
2857 end\
2858 else\
2859 printError( \"Cannot overwrite file multiple times\" )\
2860 return\
2861 end\
2862 end\
2863else\
2864 printError( \"No matching files\" )\
2865end",
2866 [ "programs/fun/advanced/paint.lua" ] = "-- Paint created by nitrogenfingers (edited by dan200)\
2867-- http://www.youtube.com/user/NitrogenFingers\
2868\
2869------------\
2870-- Fields --\
2871------------\
2872\
2873-- The width and height of the terminal\
2874local w,h = term.getSize()\
2875\
2876-- The selected colours on the left and right mouse button, and the colour of the canvas\
2877local leftColour, rightColour = colours.white, nil\
2878local canvasColour = colours.black\
2879\
2880-- The values stored in the canvas\
2881local canvas = {}\
2882\
2883-- The menu options\
2884local mChoices = { \"Save\",\"Exit\" }\
2885\
2886-- The message displayed in the footer bar\
2887local fMessage = \"Press Ctrl to access menu\"\
2888\
2889-------------------------\
2890-- Initialisation --\
2891-------------------------\
2892\
2893-- Determine if we can even run this\
2894if not term.isColour() then\
2895 print(\"Requires an Advanced Computer\")\
2896 return\
2897end\
2898\
2899-- Determines if the file exists, and can be edited on this computer\
2900local tArgs = {...}\
2901if #tArgs == 0 then\
2902 print(\"Usage: paint <path>\")\
2903 return\
2904end\
2905local sPath = shell.resolve(tArgs[1])\
2906local bReadOnly = fs.isReadOnly(sPath)\
2907if fs.exists(sPath) and fs.isDir(sPath) then\
2908 print(\"Cannot edit a directory.\")\
2909 return\
2910end\
2911\
2912-- Create .nfp files by default\
2913if not fs.exists( sPath ) and not string.find( sPath, \"%.\" ) then\
2914 local sExtension = settings.get(\"paint.default_extension\", \"\" )\
2915 if sExtension ~= \"\" and type( sExtension ) == \"string\" then\
2916 sPath = sPath .. \".\" .. sExtension\
2917 end\
2918end\
2919\
2920\
2921---------------\
2922-- Functions --\
2923---------------\
2924\
2925local function getCanvasPixel( x, y )\
2926 if canvas[y] then\
2927 return canvas[y][x]\
2928 end\
2929 return nil\
2930end\
2931\
2932--[[\
2933 Converts a colour value to a text character\
2934 params: colour = the number to convert to a hex value\
2935 returns: a string representing the chosen colour\
2936]]\
2937local function getCharOf( colour )\
2938 -- Incorrect values always convert to nil\
2939 if type(colour) == \"number\" then\
2940 local value = math.floor( math.log(colour) / math.log(2) ) + 1\
2941 if value >= 1 and value <= 16 then\
2942 return string.sub( \"0123456789abcdef\", value, value )\
2943 end\
2944 end\
2945 return \" \"\
2946end\
2947\
2948--[[\
2949 Converts a text character to colour value\
2950 params: char = the char (from string.byte) to convert to number\
2951 returns: the colour number of the hex value\
2952]]\
2953local tColourLookup = {}\
2954for n=1,16 do\
2955 tColourLookup[ string.byte( \"0123456789abcdef\",n,n ) ] = 2^(n-1)\
2956end\
2957local function getColourOf( char )\
2958 -- Values not in the hex table are transparent (canvas coloured)\
2959 return tColourLookup[char]\
2960end\
2961\
2962--[[\
2963 Loads the file into the canvas\
2964 params: path = the path of the file to open\
2965 returns: nil\
2966]]\
2967local function load(path)\
2968 -- Load the file\
2969 if fs.exists(path) then\
2970 local file = fs.open(sPath, \"r\")\
2971 local sLine = file.readLine()\
2972 while sLine do\
2973 local line = {}\
2974 for x=1,w-2 do\
2975 line[x] = getColourOf( string.byte(sLine,x,x) )\
2976 end\
2977 table.insert( canvas, line )\
2978 sLine = file.readLine()\
2979 end\
2980 file.close()\
2981 end\
2982end\
2983\
2984--[[\
2985 Saves the current canvas to file\
2986 params: path = the path of the file to save\
2987 returns: true if save was successful, false otherwise\
2988]]\
2989local function save(path)\
2990 -- Open file\
2991 local sDir = string.sub(sPath, 1, #sPath - #fs.getName(sPath))\
2992 if not fs.exists(sDir) then\
2993 fs.makeDir(sDir)\
2994 end\
2995\
2996 local file, err = fs.open( path, \"w\" )\
2997 if not file then\
2998 return false, err\
2999 end\
3000\
3001 -- Encode (and trim)\
3002 local tLines = {}\
3003 local nLastLine = 0\
3004 for y=1,h-1 do\
3005 local sLine = \"\"\
3006 local nLastChar = 0\
3007 for x=1,w-2 do\
3008 local c = getCharOf( getCanvasPixel( x, y ) )\
3009 sLine = sLine .. c\
3010 if c ~= \" \" then\
3011 nLastChar = x\
3012 end\
3013 end\
3014 sLine = string.sub( sLine, 1, nLastChar )\
3015 tLines[y] = sLine\
3016 if string.len( sLine ) > 0 then\
3017 nLastLine = y\
3018 end\
3019 end\
3020\
3021 -- Save out\
3022 for n=1,nLastLine do\
3023 file.writeLine( tLines[ n ] )\
3024 end\
3025 file.close()\
3026 return true\
3027end\
3028\
3029--[[\
3030 Draws colour picker sidebar, the pallette and the footer\
3031 returns: nil\
3032]]\
3033local function drawInterface()\
3034 -- Footer\
3035 term.setCursorPos(1, h)\
3036 term.setBackgroundColour(colours.black)\
3037 term.setTextColour(colours.yellow)\
3038 term.clearLine()\
3039 term.write(fMessage)\
3040\
3041 -- Colour Picker\
3042 for i=1,16 do\
3043 term.setCursorPos(w-1, i)\
3044 term.setBackgroundColour( 2^(i-1) )\
3045 term.write(\" \")\
3046 end\
3047\
3048 term.setCursorPos(w-1, 17)\
3049 term.setBackgroundColour( canvasColour )\
3050 term.setTextColour( colours.grey )\
3051 term.write(\"\\127\\127\")\
3052\
3053 -- Left and Right Selected Colours\
3054 for i=18,18 do\
3055 term.setCursorPos(w-1, i)\
3056 if leftColour ~= nil then\
3057 term.setBackgroundColour( leftColour )\
3058 term.write(\" \")\
3059 else\
3060 term.setBackgroundColour( canvasColour )\
3061 term.setTextColour( colours.grey )\
3062 term.write(\"\\127\")\
3063 end\
3064 if rightColour ~= nil then\
3065 term.setBackgroundColour( rightColour )\
3066 term.write(\" \")\
3067 else\
3068 term.setBackgroundColour( canvasColour )\
3069 term.setTextColour( colours.grey )\
3070 term.write(\"\\127\")\
3071 end\
3072 end\
3073\
3074 -- Padding\
3075 term.setBackgroundColour( canvasColour )\
3076 for i=20,h-1 do\
3077 term.setCursorPos(w-1, i)\
3078 term.write(\" \")\
3079 end\
3080end\
3081\
3082--[[\
3083 Converts a single pixel of a single line of the canvas and draws it\
3084 returns: nil\
3085]]\
3086local function drawCanvasPixel( x, y )\
3087 local pixel = getCanvasPixel( x, y )\
3088 if pixel then\
3089 term.setBackgroundColour( pixel or canvasColour )\
3090 term.setCursorPos(x, y)\
3091 term.write(\" \")\
3092 else\
3093 term.setBackgroundColour( canvasColour )\
3094 term.setTextColour( colours.grey )\
3095 term.setCursorPos(x, y)\
3096 term.write(\"\\127\")\
3097 end\
3098end\
3099\
3100--[[\
3101 Converts each colour in a single line of the canvas and draws it\
3102 returns: nil\
3103]]\
3104local function drawCanvasLine( y )\
3105 for x = 1, w-2 do\
3106 drawCanvasPixel( x, y )\
3107 end\
3108end\
3109\
3110--[[\
3111 Converts each colour in the canvas and draws it\
3112 returns: nil\
3113]]\
3114local function drawCanvas()\
3115 for y = 1, h-1 do\
3116 drawCanvasLine( y )\
3117 end\
3118end\
3119\
3120--[[\
3121 Draws menu options and handles input from within the menu.\
3122 returns: true if the program is to be exited; false otherwise\
3123]]\
3124local function accessMenu()\
3125 -- Selected menu option\
3126 local selection = 1\
3127\
3128 term.setBackgroundColour(colours.black)\
3129 while true do\
3130 -- Draw the menu\
3131 term.setCursorPos(1,h)\
3132 term.clearLine()\
3133 term.setTextColour(colours.white)\
3134 for k,v in pairs(mChoices) do\
3135 if selection==k then\
3136 term.setTextColour(colours.yellow)\
3137 local ox,_ = term.getCursorPos()\
3138 term.write(\"[\"..string.rep(\" \",#v)..\"]\")\
3139 term.setCursorPos(ox+1,h)\
3140 term.setTextColour(colours.white)\
3141 term.write(v)\
3142 term.setCursorPos(term.getCursorPos()+1,h)\
3143 else\
3144 term.write(\" \"..v..\" \")\
3145 end\
3146 end\
3147\
3148 -- Handle input in the menu\
3149 local id,key = os.pullEvent(\"key\")\
3150 if id == \"key\" then\
3151 -- S and E are shortcuts\
3152 if key == keys.s then\
3153 selection = 1\
3154 key = keys.enter\
3155 elseif key == keys.e then\
3156 selection = 2\
3157 key = keys.enter\
3158 end\
3159\
3160 if key == keys.right then\
3161 -- Move right\
3162 selection = selection + 1\
3163 if selection > #mChoices then\
3164 selection = 1\
3165 end\
3166\
3167 elseif key == keys.left and selection > 1 then\
3168 -- Move left\
3169 selection = selection - 1\
3170 if selection < 1 then\
3171 selection = #mChoices\
3172 end\
3173\
3174 elseif key == keys.enter then\
3175 -- Select an option\
3176 if mChoices[selection]==\"Save\" then\
3177 if bReadOnly then\
3178 fMessage = \"Access denied\"\
3179 return false\
3180 end\
3181 local success, err = save(sPath)\
3182 if success then\
3183 fMessage = \"Saved to \"..sPath\
3184 else\
3185 if err then\
3186 fMessage = \"Error saving to \"..err\
3187 else\
3188 fMessage = \"Error saving to \"..sPath\
3189 end\
3190 end\
3191 return false\
3192 elseif mChoices[selection]==\"Exit\" then\
3193 return true\
3194 end\
3195 elseif key == keys.leftCtrl or keys == keys.rightCtrl then\
3196 -- Cancel the menu\
3197 return false\
3198 end\
3199 end\
3200 end\
3201end\
3202\
3203--[[\
3204 Runs the main thread of execution. Draws the canvas and interface, and handles\
3205 mouse and key events.\
3206 returns: nil\
3207]]\
3208local function handleEvents()\
3209 local programActive = true\
3210 while programActive do\
3211 local id,p1,p2,p3 = os.pullEvent()\
3212 if id==\"mouse_click\" or id==\"mouse_drag\" then\
3213 if p2 >= w-1 and p3 >= 1 and p3 <= 17 then\
3214 if id ~= \"mouse_drag\" then\
3215 -- Selecting an items in the colour picker\
3216 if p3 <= 16 then\
3217 if p1==1 then\
3218 leftColour = 2^(p3-1)\
3219 else\
3220 rightColour = 2^(p3-1)\
3221 end\
3222 else\
3223 if p1==1 then\
3224 leftColour = nil\
3225 else\
3226 rightColour = nil\
3227 end\
3228 end\
3229 --drawCanvas()\
3230 drawInterface()\
3231 end\
3232 elseif p2 < w-1 and p3 <= h-1 then\
3233 -- Clicking on the canvas\
3234 local paintColour = nil\
3235 if p1==1 then\
3236 paintColour = leftColour\
3237 elseif p1==2 then\
3238 paintColour = rightColour\
3239 end\
3240 if not canvas[p3] then\
3241 canvas[p3] = {}\
3242 end\
3243 canvas[p3][p2] = paintColour\
3244\
3245 drawCanvasPixel( p2, p3 )\
3246 end\
3247 elseif id==\"key\" then\
3248 if p1==keys.leftCtrl or p1==keys.rightCtrl then\
3249 programActive = not accessMenu()\
3250 drawInterface()\
3251 end\
3252 elseif id==\"term_resize\" then\
3253 w,h = term.getSize()\
3254 drawCanvas()\
3255 drawInterface()\
3256 end\
3257 end\
3258end\
3259\
3260-- Init\
3261load(sPath)\
3262drawCanvas()\
3263drawInterface()\
3264\
3265-- Main loop\
3266handleEvents()\
3267\
3268-- Shutdown\
3269term.setBackgroundColour(colours.black)\
3270term.setTextColour(colours.white)\
3271term.clear()\
3272term.setCursorPos(1,1)",
3273 [ "help/cd.txt" ] = "cd changes the directory you're in.\
3274\
3275ex:\
3276\"cd rom\" will move to \"rom\" folder.\
3277\"cd ..\" will move up one folder.\
3278\"cd /\" will move to the root.",
3279 [ "programs/fun/advanced/levels/8.dat" ] = "4\
3280777777 7777\
32817287b7 7867\
3282788787 7887\
328377878777877\
3284 7888eb8887\
3285 77877787877\
3286 7887 787887\
3287 7487 7e7807\
3288 7777 777777",
3289 [ "apis/paintutils.lua" ] = "\
3290local function drawPixelInternal( xPos, yPos )\
3291 term.setCursorPos( xPos, yPos )\
3292 term.write(\" \")\
3293end\
3294\
3295local tColourLookup = {}\
3296for n=1,16 do\
3297 tColourLookup[ string.byte( \"0123456789abcdef\",n,n ) ] = 2^(n-1)\
3298end\
3299\
3300local function parseLine( tImageArg, sLine )\
3301 local tLine = {}\
3302 for x=1,sLine:len() do\
3303 tLine[x] = tColourLookup[ string.byte(sLine,x,x) ] or 0\
3304 end\
3305 table.insert( tImageArg, tLine )\
3306end\
3307\
3308function parseImage( sRawData )\
3309 if type( sRawData ) ~= \"string\" then\
3310 error( \"bad argument #1 (expected string, got \" .. type( sRawData ) .. \")\" )\
3311 end\
3312 local tImage = {}\
3313 for sLine in ( sRawData .. \"\\n\" ):gmatch( \"(.-)\\n\" ) do -- read each line like original file handling did\
3314 parseLine( tImage, sLine )\
3315 end\
3316 return tImage\
3317end\
3318\
3319function loadImage( sPath )\
3320 if type( sPath ) ~= \"string\" then\
3321 error( \"bad argument #1 (expected string, got \" .. type( sPath ) .. \")\", 2 )\
3322 end\
3323\
3324 if fs.exists( sPath ) then\
3325 local file = io.open( sPath, \"r\" )\
3326 local sContent = file:read(\"*a\")\
3327 file:close()\
3328 return parseImage( sContent ) -- delegate image parse to parseImage\
3329 end\
3330 return nil\
3331end\
3332\
3333function drawPixel( xPos, yPos, nColour )\
3334 if type( xPos ) ~= \"number\" then error( \"bad argument #1 (expected number, got \" .. type( xPos ) .. \")\", 2 ) end\
3335 if type( yPos ) ~= \"number\" then error( \"bad argument #2 (expected number, got \" .. type( yPos ) .. \")\", 2 ) end\
3336 if nColour ~= nil and type( nColour ) ~= \"number\" then error( \"bad argument #3 (expected number, got \" .. type( nColour ) .. \")\", 2 ) end\
3337 if nColour then\
3338 term.setBackgroundColor( nColour )\
3339 end\
3340 drawPixelInternal( xPos, yPos )\
3341end\
3342\
3343function drawLine( startX, startY, endX, endY, nColour )\
3344 if type( startX ) ~= \"number\" then error( \"bad argument #1 (expected number, got \" .. type( startX ) .. \")\", 2 ) end\
3345 if type( startY ) ~= \"number\" then error( \"bad argument #2 (expected number, got \" .. type( startY ) .. \")\", 2 ) end\
3346 if type( endX ) ~= \"number\" then error( \"bad argument #3 (expected number, got \" .. type( endX ) .. \")\", 2 ) end\
3347 if type( endY ) ~= \"number\" then error( \"bad argument #4 (expected number, got \" .. type( endY ) .. \")\", 2 ) end\
3348 if nColour ~= nil and type( nColour ) ~= \"number\" then error( \"bad argument #5 (expected number, got \" .. type( nColour ) .. \")\", 2 ) end\
3349\
3350 startX = math.floor(startX)\
3351 startY = math.floor(startY)\
3352 endX = math.floor(endX)\
3353 endY = math.floor(endY)\
3354\
3355 if nColour then\
3356 term.setBackgroundColor( nColour )\
3357 end\
3358 if startX == endX and startY == endY then\
3359 drawPixelInternal( startX, startY )\
3360 return\
3361 end\
3362\
3363 local minX = math.min( startX, endX )\
3364 local maxX, minY, maxY\
3365 if minX == startX then\
3366 minY = startY\
3367 maxX = endX\
3368 maxY = endY\
3369 else\
3370 minY = endY\
3371 maxX = startX\
3372 maxY = startY\
3373 end\
3374\
3375 -- TODO: clip to screen rectangle?\
3376\
3377 local xDiff = maxX - minX\
3378 local yDiff = maxY - minY\
3379\
3380 if xDiff > math.abs(yDiff) then\
3381 local y = minY\
3382 local dy = yDiff / xDiff\
3383 for x=minX,maxX do\
3384 drawPixelInternal( x, math.floor( y + 0.5 ) )\
3385 y = y + dy\
3386 end\
3387 else\
3388 local x = minX\
3389 local dx = xDiff / yDiff\
3390 if maxY >= minY then\
3391 for y=minY,maxY do\
3392 drawPixelInternal( math.floor( x + 0.5 ), y )\
3393 x = x + dx\
3394 end\
3395 else\
3396 for y=minY,maxY,-1 do\
3397 drawPixelInternal( math.floor( x + 0.5 ), y )\
3398 x = x - dx\
3399 end\
3400 end\
3401 end\
3402end\
3403\
3404function drawBox( startX, startY, endX, endY, nColour )\
3405 if type( startX ) ~= \"number\" then error( \"bad argument #1 (expected number, got \" .. type( startX ) .. \")\", 2 ) end\
3406 if type( startY ) ~= \"number\" then error( \"bad argument #2 (expected number, got \" .. type( startY ) .. \")\", 2 ) end\
3407 if type( endX ) ~= \"number\" then error( \"bad argument #3 (expected number, got \" .. type( endX ) .. \")\", 2 ) end\
3408 if type( endY ) ~= \"number\" then error( \"bad argument #4 (expected number, got \" .. type( endY ) .. \")\", 2 ) end\
3409 if nColour ~= nil and type( nColour ) ~= \"number\" then error( \"bad argument #5 (expected number, got \" .. type( nColour ) .. \")\", 2 ) end\
3410\
3411 startX = math.floor(startX)\
3412 startY = math.floor(startY)\
3413 endX = math.floor(endX)\
3414 endY = math.floor(endY)\
3415\
3416 if nColour then\
3417 term.setBackgroundColor( nColour )\
3418 end\
3419 if startX == endX and startY == endY then\
3420 drawPixelInternal( startX, startY )\
3421 return\
3422 end\
3423\
3424 local minX = math.min( startX, endX )\
3425 local maxX, minY, maxY\
3426 if minX == startX then\
3427 minY = startY\
3428 maxX = endX\
3429 maxY = endY\
3430 else\
3431 minY = endY\
3432 maxX = startX\
3433 maxY = startY\
3434 end\
3435\
3436 for x=minX,maxX do\
3437 drawPixelInternal( x, minY )\
3438 drawPixelInternal( x, maxY )\
3439 end\
3440\
3441 if (maxY - minY) >= 2 then\
3442 for y=(minY+1),(maxY-1) do\
3443 drawPixelInternal( minX, y )\
3444 drawPixelInternal( maxX, y )\
3445 end\
3446 end\
3447end\
3448\
3449function drawFilledBox( startX, startY, endX, endY, nColour )\
3450 if type( startX ) ~= \"number\" then error( \"bad argument #1 (expected number, got \" .. type( startX ) .. \")\", 2 ) end\
3451 if type( startY ) ~= \"number\" then error( \"bad argument #2 (expected number, got \" .. type( startY ) .. \")\", 2 ) end\
3452 if type( endX ) ~= \"number\" then error( \"bad argument #3 (expected number, got \" .. type( endX ) .. \")\", 2 ) end\
3453 if type( endY ) ~= \"number\" then error( \"bad argument #4 (expected number, got \" .. type( endY ) .. \")\", 2 ) end\
3454 if nColour ~= nil and type( nColour ) ~= \"number\" then error( \"bad argument #5 (expected number, got \" .. type( nColour ) .. \")\", 2 ) end\
3455\
3456 startX = math.floor(startX)\
3457 startY = math.floor(startY)\
3458 endX = math.floor(endX)\
3459 endY = math.floor(endY)\
3460\
3461 if nColour then\
3462 term.setBackgroundColor( nColour )\
3463 end\
3464 if startX == endX and startY == endY then\
3465 drawPixelInternal( startX, startY )\
3466 return\
3467 end\
3468\
3469 local minX = math.min( startX, endX )\
3470 local maxX, minY, maxY\
3471 if minX == startX then\
3472 minY = startY\
3473 maxX = endX\
3474 maxY = endY\
3475 else\
3476 minY = endY\
3477 maxX = startX\
3478 maxY = startY\
3479 end\
3480\
3481 for x=minX,maxX do\
3482 for y=minY,maxY do\
3483 drawPixelInternal( x, y )\
3484 end\
3485 end\
3486end\
3487\
3488function drawImage( tImage, xPos, yPos )\
3489 if type( tImage ) ~= \"table\" then error( \"bad argument #1 (expected table, got \" .. type( tImage ) .. \")\", 2 ) end\
3490 if type( xPos ) ~= \"number\" then error( \"bad argument #2 (expected number, got \" .. type( xPos ) .. \")\", 2 ) end\
3491 if type( yPos ) ~= \"number\" then error( \"bad argument #3 (expected number, got \" .. type( yPos ) .. \")\", 2 ) end\
3492 for y=1,#tImage do\
3493 local tLine = tImage[y]\
3494 for x=1,#tLine do\
3495 if tLine[x] > 0 then\
3496 term.setBackgroundColor( tLine[x] )\
3497 drawPixelInternal( x + xPos - 1, y + yPos - 1 )\
3498 end\
3499 end\
3500 end\
3501end",
3502 [ "help/id.txt" ] = "id prints the unique identifier of this computer, or a Disk in an attached Disk Drive.\
3503\
3504ex:\
3505\"id\" will print this Computers ID and label\
3506\"id left\" will print the ID and label of the disk in the Disk Drive on the left",
3507 [ "programs/http/wget.lua" ] = "\
3508local function printUsage()\
3509 print( \"Usage:\" )\
3510 print( \"wget <url> [filename]\" )\
3511end\
3512\
3513local tArgs = { ... }\
3514if #tArgs < 1 then\
3515 printUsage()\
3516 return\
3517end\
3518\
3519if not http then\
3520 printError( \"wget requires http API\" )\
3521 printError( \"Set http_enable to true in ComputerCraft.cfg\" )\
3522 return\
3523end\
3524\
3525local function getFilename( sUrl )\
3526 sUrl = sUrl:gsub( \"[#?].*\" , \"\" ):gsub( \"/+$\" , \"\" )\
3527 return sUrl:match( \"/([^/]+)$\" )\
3528end\
3529\
3530local function get( sUrl )\
3531 write( \"Connecting to \" .. sUrl .. \"... \" )\
3532\
3533 local response = http.get( sUrl , nil , true )\
3534 if not response then\
3535 print( \"Failed.\" )\
3536 return nil\
3537 end\
3538\
3539 print( \"Success.\" )\
3540\
3541 local sResponse = response.readAll()\
3542 response.close()\
3543 return sResponse\
3544end\
3545\
3546-- Determine file to download\
3547local sUrl = tArgs[1]\
3548\
3549--Check if the URL is valid\
3550local ok, err = http.checkURL( sUrl )\
3551if not ok then\
3552 printError( err or \"Invalid URL.\" )\
3553 return\
3554end\
3555\
3556local sFile = tArgs[2] or getFilename( sUrl )\
3557local sPath = shell.resolve( sFile )\
3558if fs.exists( sPath ) then\
3559 print( \"File already exists\" )\
3560 return\
3561end\
3562\
3563-- Do the get\
3564local res = get( sUrl )\
3565if res then\
3566 local file = fs.open( sPath, \"wb\" )\
3567 file.write( res )\
3568 file.close()\
3569\
3570 print( \"Downloaded as \"..sFile )\
3571end",
3572 [ "programs/command/commands.lua" ] = "\
3573if not commands then\
3574 printError( \"Requires a Command Computer.\" )\
3575 return\
3576end\
3577\
3578local tCommands = commands.list()\
3579table.sort( tCommands )\
3580\
3581if term.isColor() then\
3582 term.setTextColor( colors.green )\
3583end\
3584print( \"Available commands:\" )\
3585term.setTextColor( colors.white )\
3586\
3587textutils.pagedTabulate( tCommands )",
3588 [ "autorun/emu.lua" ] = "-- Setup completion functions\
3589local function completeMultipleChoice(text, options, addSpaces)\
3590 local tResults = {}\
3591 for n = 1, #options do\
3592 local sOption = options[n]\
3593 if #sOption + (addSpaces and 1 or 0) > #text and sOption:sub(1, #text) == text then\
3594 local sResult = sOption:sub(#text + 1)\
3595 if addSpaces then\
3596 table.insert(tResults, sResult .. \" \")\
3597 else\
3598 table.insert(tResults, sResult)\
3599 end\
3600 end\
3601 end\
3602 return tResults\
3603end\
3604\
3605local commands = { \"close\", \"open\", \"data\", \"config\" }\
3606shell.setCompletionFunction(\"rom/programs/emu.lua\", function(shell, index, text, previous)\
3607 if index == 1 then\
3608 return completeMultipleChoice(text, commands, true)\
3609 end\
3610end)",
3611 [ "help/string.txt" ] = "string is a standard Lua5.1 API.\
3612Refer to http://www.lua.org/manual/5.1/ for more information.",
3613 [ "help/turtle.txt" ] = "turtle is an api availiable on Turtles, which controls their movement.\
3614Functions in the Turtle API:\
3615turtle.forward()\
3616turtle.back()\
3617turtle.up()\
3618turtle.down()\
3619turtle.turnLeft()\
3620turtle.turnRight()\
3621turtle.select( slotNum )\
3622turtle.getSelectedSlot()\
3623turtle.getItemCount( [slotNum] )\
3624turtle.getItemSpace( [slotNum] )\
3625turtle.getItemDetail( [slotNum] )\
3626turtle.equipLeft()\
3627turtle.equipRight()\
3628turtle.dig( [toolSide] )\
3629turtle.digUp( [toolSide] )\
3630turtle.digDown( [toolSide] )\
3631turtle.place()\
3632turtle.placeUp()\
3633turtle.placeDown()\
3634turtle.attack( [toolSide] )\
3635turtle.attackUp( [toolSide] )\
3636turtle.attackDown( [toolSide] )\
3637turtle.detect()\
3638turtle.detectUp()\
3639turtle.detectDown()\
3640turtle.compare()\
3641turtle.compareUp()\
3642turtle.compareDown()\
3643turtle.inspect()\
3644turtle.inspectUp()\
3645turtle.inspectDown()\
3646turtle.compareTo( slotNum )\
3647turtle.transferTo( slotNum, [quantity] )\
3648turtle.drop( [quantity] )\
3649turtle.dropUp( [quantity] )\
3650turtle.dropDown( [quantity] )\
3651turtle.suck( [quantity] )\
3652turtle.suckUp( [quantity] )\
3653turtle.suckDown( [quantity] )\
3654turtle.getFuelLevel()\
3655turtle.getFuelLimit()\
3656turtle.refuel( [quantity] )\
3657turtle.craft( [quantity] ) (requires Crafty Turtle)\
3658\
3659Events fired by the Turtle API:\
3660\"turtle_inventory\" when any of the items in the inventory are changed. Use comparison operations to inspect the changes.",
3661 [ "apis/help.lua" ] = "\
3662local sPath = \"/rom/help\"\
3663\
3664function path()\
3665 return sPath\
3666end\
3667\
3668function setPath( _sPath )\
3669 if type( _sPath ) ~= \"string\" then\
3670 error( \"bad argument #1 (expected string, got \" .. type( _sPath ) .. \")\", 2 )\
3671 end\
3672 sPath = _sPath\
3673end\
3674\
3675function lookup( _sTopic )\
3676 if type( _sTopic ) ~= \"string\" then\
3677 error( \"bad argument #1 (expected string, got \" .. type( _sTopic ) .. \")\", 2 )\
3678 end\
3679 -- Look on the path variable\
3680 for sPath in string.gmatch(sPath, \"[^:]+\") do\
3681 sPath = fs.combine( sPath, _sTopic )\
3682 if fs.exists( sPath ) and not fs.isDir( sPath ) then\
3683 return sPath\
3684 elseif fs.exists( sPath..\".txt\" ) and not fs.isDir( sPath..\".txt\" ) then\
3685 return sPath..\".txt\"\
3686 end\
3687 end\
3688\
3689 -- Not found\
3690 return nil\
3691end\
3692\
3693function topics()\
3694 -- Add index\
3695 local tItems = {\
3696 [ \"index\" ] = true\
3697 }\
3698\
3699 -- Add topics from the path\
3700 for sPath in string.gmatch(sPath, \"[^:]+\") do\
3701 if fs.isDir( sPath ) then\
3702 local tList = fs.list( sPath )\
3703 for n,sFile in pairs( tList ) do\
3704 if string.sub( sFile, 1, 1 ) ~= \".\" then\
3705 if not fs.isDir( fs.combine( sPath, sFile ) ) then\
3706 if #sFile > 4 and sFile:sub(-4) == \".txt\" then\
3707 sFile = sFile:sub(1,-5)\
3708 end\
3709 tItems[ sFile ] = true\
3710 end\
3711 end\
3712 end\
3713 end\
3714 end\
3715\
3716 -- Sort and return\
3717 local tItemList = {}\
3718 for sItem, b in pairs( tItems ) do\
3719 table.insert( tItemList, sItem )\
3720 end\
3721 table.sort( tItemList )\
3722 return tItemList\
3723end\
3724\
3725function completeTopic( sText )\
3726 if type( sText ) ~= \"string\" then\
3727 error( \"bad argument #1 (expected string, got \" .. type( sText ) .. \")\", 2 )\
3728 end\
3729 local tTopics = topics()\
3730 local tResults = {}\
3731 for n=1,#tTopics do\
3732 local sTopic = tTopics[n]\
3733 if #sTopic > #sText and string.sub( sTopic, 1, #sText ) == sText then\
3734 table.insert( tResults, string.sub( sTopic, #sText + 1 ) )\
3735 end\
3736 end\
3737 return tResults\
3738end",
3739 [ "help/settings.txt" ] = "Functions in the Settings API:\
3740settings.get( name, [default] )\
3741settings.set( name, value )\
3742settings.unset( name )\
3743settings.load( path )\
3744settings.save( path )\
3745settings.clear()\
3746settings.getNames()\
3747\
3748Default Settings:\
3749shell.autocomplete - enables auto-completion in the Shell.\
3750lua.autocomplete - enables auto-completion in the Lua program.\
3751edit.autocomplete - enables auto-completion in the Edit program.\
3752edit.default_extension - sets the default file extension for files created with the Edit program\
3753paint.default_extension - sets the default file extension for files created with the Paint program\
3754bios.use_multishell - enables Multishell on Advanced Computers, Turtles, Pocket Computers and Command Computers.\
3755shell.allow_disk_startup - if a Disk Drive with a Disk inside that has a 'startup' script is attached to a computer, this setting allows to automatically run that script when the computer starts.\
3756shell.allow_startup - if there is a 'startup' script in a computer's root, this setting allow to automatically run that script when the computer runs.\
3757list.show_hidden - determines, whether the List program will list hidden files or not.",
3758 [ "help/colours.txt" ] = "Functions in the colours api\
3759(used for redstone.setBundledOutput):\
3760colours.combine( colour1, colour2, colour3, ...)\
3761colours.subtract( colours, colour1, colour2, ...)\
3762colours.test( colours, colour )\
3763colours.rgb8( r, g, b )\
3764\
3765Colour constants in the colours api, in ascending bit order:\
3766colours.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.",
3767 [ "help/os.txt" ] = "Functions in the os (Operating System) API:\
3768os.version()\
3769os.getComputerID()\
3770os.getComputerLabel()\
3771os.setComputerLabel()\
3772os.run( environment, programpath, arguments )\
3773os.loadAPI( path )\
3774os.unloadAPI( name )\
3775os.pullEvent( [filter] )\
3776os.queueEvent( event, arguments )\
3777os.clock()\
3778os.startTimer( timeout )\
3779os.cancelTimer( token )\
3780os.sleep( timeout )\
3781os.time( [source] )\
3782os.day( [source] )\
3783os.epoch( [source] )\
3784os.setAlarm( time )\
3785os.cancelAlarm( token )\
3786os.shutdown()\
3787os.reboot()\
3788\
3789Events emitted by the os API:\
3790\"timer\" when a timeout started by os.startTimer() completes. Argument is the token returned by os.startTimer().\
3791\"alarm\" when a time passed to os.setAlarm() is reached. Argument is the token returned by os.setAlarm().\
3792Type \"help events\" to learn about the event system.",
3793 [ "help/unequip.txt" ] = "unequip is a program for Turtles and Pocket Computers. unequip will remove tools of peripherals from the specified side of the turtle. On a Pocket Computer you don't need to write a side.\
3794\
3795ex:\
3796\"unequip left\" will remove the item on the left side of the turtle\
3797\"unequip\" on a Pocket Computer will remove the item from the Pocket Computer",
3798 [ "modules/main/.ignoreme" ] = "--[[\
3799Alright then, don't ignore me. This file is to ensure the existence of the \"modules/main\" folder.\
3800You can use this folder to add modules who can be loaded with require() to your Resourcepack.\
3801]]",
3802 [ "apis/command/commands.lua" ] = "\
3803if not commands then\
3804 error( \"Cannot load command API on normal computer\", 2 )\
3805end\
3806native = commands.native or commands\
3807\
3808local function collapseArgs( errorDepth, bJSONIsNBT, arg1, ... )\
3809 if arg1 ~= nil then\
3810 if type(arg1) == \"boolean\" or type(arg1) == \"number\" or type(arg1) == \"string\" then\
3811 return tostring(arg1) .. \" \" .. collapseArgs( errorDepth + 1, bJSONIsNBT, ... )\
3812 elseif type(arg1) == \"table\" then\
3813 return textutils.serialiseJSON( arg1, bJSONIsNBT ) .. \" \" .. collapseArgs( errorDepth + 1, bJSONIsNBT, ... )\
3814 else\
3815 error( \"Expected string, number, boolean or table\", errorDepth )\
3816 end\
3817 end\
3818 return \"\"\
3819end\
3820\
3821-- Put native functions into the environment\
3822local env = _ENV\
3823for k,v in pairs( native ) do\
3824 env[k] = v\
3825end\
3826\
3827-- Create wrapper functions for all the commands\
3828local tAsync = {}\
3829local tNonNBTJSONCommands = {\
3830 [ \"tellraw\" ] = true,\
3831 [ \"title\" ] = true\
3832}\
3833local tCommands = native.list()\
3834for n,sCommandName in ipairs(tCommands) do\
3835 if env[ sCommandName ] == nil then\
3836 local bJSONIsNBT = (tNonNBTJSONCommands[ sCommandName ] == nil)\
3837 env[ sCommandName ] = function( ... )\
3838 local sCommand = sCommandName .. \" \" .. collapseArgs( 3, bJSONIsNBT, ... )\
3839 return native.exec( sCommand )\
3840 end\
3841 tAsync[ sCommandName ] = function( ... )\
3842 local sCommand = sCommandName .. \" \" .. collapseArgs( 3, bJSONIsNBT, ... )\
3843 return native.execAsync( sCommand )\
3844 end\
3845 end\
3846end\
3847env.async = tAsync",
3848 [ "help/reboot.txt" ] = "reboot will turn the computer off and on again.\
3849You can also hold Ctrl+R at any time to quickly reboot.",
3850 [ "apis/textutils.lua" ] = "\
3851function slowWrite( sText, nRate )\
3852 if nRate ~= nil and type( nRate ) ~= \"number\" then\
3853 error( \"bad argument #2 (expected number, got \" .. type( nRate ) .. \")\", 2 )\
3854 end\
3855 nRate = nRate or 20\
3856 if nRate < 0 then\
3857 error( \"Rate must be positive\", 2 )\
3858 end\
3859 local nSleep = 1 / nRate\
3860\
3861 sText = tostring( sText )\
3862 local x,y = term.getCursorPos()\
3863 local len = string.len( sText )\
3864\
3865 for n=1,len do\
3866 term.setCursorPos( x, y )\
3867 sleep( nSleep )\
3868 local nLines = write( string.sub( sText, 1, n ) )\
3869 local newX, newY = term.getCursorPos()\
3870 y = newY - nLines\
3871 end\
3872end\
3873\
3874function slowPrint( sText, nRate )\
3875 slowWrite( sText, nRate )\
3876 print()\
3877end\
3878\
3879function formatTime( nTime, bTwentyFourHour )\
3880 if type( nTime ) ~= \"number\" then\
3881 error( \"bad argument #1 (expected number, got \" .. type( nTime ) .. \")\", 2 )\
3882 end\
3883 if bTwentyFourHour ~= nil and type( bTwentyFourHour ) ~= \"boolean\" then\
3884 error( \"bad argument #2 (expected boolean, got \" .. type( bTwentyFourHour ) .. \")\", 2 )\
3885 end\
3886 local sTOD = nil\
3887 if not bTwentyFourHour then\
3888 if nTime >= 12 then\
3889 sTOD = \"PM\"\
3890 else\
3891 sTOD = \"AM\"\
3892 end\
3893 if nTime >= 13 then\
3894 nTime = nTime - 12\
3895 end\
3896 end\
3897\
3898 local nHour = math.floor(nTime)\
3899 local nMinute = math.floor((nTime - nHour)*60)\
3900 if sTOD then\
3901 return string.format( \"%d:%02d %s\", nHour, nMinute, sTOD )\
3902 else\
3903 return string.format( \"%d:%02d\", nHour, nMinute )\
3904 end\
3905end\
3906\
3907local function makePagedScroll( _term, _nFreeLines )\
3908 local nativeScroll = _term.scroll\
3909 local nFreeLines = _nFreeLines or 0\
3910 return function( _n )\
3911 for n=1,_n do\
3912 nativeScroll( 1 )\
3913\
3914 if nFreeLines <= 0 then\
3915 local w,h = _term.getSize()\
3916 _term.setCursorPos( 1, h )\
3917 _term.write( \"Press any key to continue\" )\
3918 os.pullEvent( \"key\" )\
3919 _term.clearLine()\
3920 _term.setCursorPos( 1, h )\
3921 else\
3922 nFreeLines = nFreeLines - 1\
3923 end\
3924 end\
3925 end\
3926end\
3927\
3928function pagedPrint( _sText, _nFreeLines )\
3929 if _nFreeLines ~= nil and type( _nFreeLines ) ~= \"number\" then\
3930 error( \"bad argument #2 (expected number, got \" .. type( _nFreeLines ) .. \")\", 2 )\
3931 end\
3932 -- Setup a redirector\
3933 local oldTerm = term.current()\
3934 local newTerm = {}\
3935 for k,v in pairs( oldTerm ) do\
3936 newTerm[k] = v\
3937 end\
3938 newTerm.scroll = makePagedScroll( oldTerm, _nFreeLines )\
3939 term.redirect( newTerm )\
3940\
3941 -- Print the text\
3942 local result\
3943 local ok, err = pcall( function()\
3944 if _sText ~= nil then\
3945 result = print( _sText )\
3946 else\
3947 result = print()\
3948 end\
3949 end )\
3950\
3951 -- Removed the redirector\
3952 term.redirect( oldTerm )\
3953\
3954 -- Propogate errors\
3955 if not ok then\
3956 error( err, 0 )\
3957 end\
3958 return result\
3959end\
3960\
3961local function tabulateCommon( bPaged, ... )\
3962 local tAll = { ... }\
3963 for k,v in ipairs( tAll ) do\
3964 if type( v ) ~= \"number\" and type( v ) ~= \"table\" then\
3965 error( \"bad argument #\"..k..\" (expected number or table, got \" .. type( v ) .. \")\", 3 )\
3966 end\
3967 end\
3968\
3969 local w,h = term.getSize()\
3970 local nMaxLen = w / 8\
3971 for n, t in ipairs( tAll ) do\
3972 if type(t) == \"table\" then\
3973 for nu, sItem in pairs(t) do\
3974 if type( sItem ) ~= \"string\" then\
3975 error( \"bad argument #\"..n..\".\"..nu..\" (expected string, got \" .. type( sItem ) .. \")\", 3 )\
3976 end\
3977 nMaxLen = math.max( string.len( sItem ) + 1, nMaxLen )\
3978 end\
3979 end\
3980 end\
3981 local nCols = math.floor( w / nMaxLen )\
3982 local nLines = 0\
3983 local function newLine()\
3984 if bPaged and nLines >= (h-3) then\
3985 pagedPrint()\
3986 else\
3987 print()\
3988 end\
3989 nLines = nLines + 1\
3990 end\
3991\
3992 local function drawCols( _t )\
3993 local nCol = 1\
3994 for n, s in ipairs( _t ) do\
3995 if nCol > nCols then\
3996 nCol = 1\
3997 newLine()\
3998 end\
3999\
4000 local cx, cy = term.getCursorPos()\
4001 cx = 1 + ((nCol - 1) * nMaxLen)\
4002 term.setCursorPos( cx, cy )\
4003 term.write( s )\
4004\
4005 nCol = nCol + 1\
4006 end\
4007 print()\
4008 end\
4009 for n, t in ipairs( tAll ) do\
4010 if type(t) == \"table\" then\
4011 if #t > 0 then\
4012 drawCols( t )\
4013 end\
4014 elseif type(t) == \"number\" then\
4015 term.setTextColor( t )\
4016 end\
4017 end\
4018end\
4019\
4020function tabulate( ... )\
4021 tabulateCommon( false, ... )\
4022end\
4023\
4024function pagedTabulate( ... )\
4025 tabulateCommon( true, ... )\
4026end\
4027\
4028local g_tLuaKeywords = {\
4029 [ \"and\" ] = true,\
4030 [ \"break\" ] = true,\
4031 [ \"do\" ] = true,\
4032 [ \"else\" ] = true,\
4033 [ \"elseif\" ] = true,\
4034 [ \"end\" ] = true,\
4035 [ \"false\" ] = true,\
4036 [ \"for\" ] = true,\
4037 [ \"function\" ] = true,\
4038 [ \"if\" ] = true,\
4039 [ \"in\" ] = true,\
4040 [ \"local\" ] = true,\
4041 [ \"nil\" ] = true,\
4042 [ \"not\" ] = true,\
4043 [ \"or\" ] = true,\
4044 [ \"repeat\" ] = true,\
4045 [ \"return\" ] = true,\
4046 [ \"then\" ] = true,\
4047 [ \"true\" ] = true,\
4048 [ \"until\" ] = true,\
4049 [ \"while\" ] = true,\
4050}\
4051\
4052local function serializeImpl( t, tTracking, sIndent )\
4053 local sType = type(t)\
4054 if sType == \"table\" then\
4055 if tTracking[t] ~= nil then\
4056 error( \"Cannot serialize table with recursive entries\", 0 )\
4057 end\
4058 tTracking[t] = true\
4059\
4060 if next(t) == nil then\
4061 -- Empty tables are simple\
4062 return \"{}\"\
4063 else\
4064 -- Other tables take more work\
4065 local sResult = \"{\\n\"\
4066 local sSubIndent = sIndent .. \" \"\
4067 local tSeen = {}\
4068 for k,v in ipairs(t) do\
4069 tSeen[k] = true\
4070 sResult = sResult .. sSubIndent .. serializeImpl( v, tTracking, sSubIndent ) .. \",\\n\"\
4071 end\
4072 for k,v in pairs(t) do\
4073 if not tSeen[k] then\
4074 local sEntry\
4075 if type(k) == \"string\" and not g_tLuaKeywords[k] and string.match( k, \"^[%a_][%a%d_]*$\" ) then\
4076 sEntry = k .. \" = \" .. serializeImpl( v, tTracking, sSubIndent ) .. \",\\n\"\
4077 else\
4078 sEntry = \"[ \" .. serializeImpl( k, tTracking, sSubIndent ) .. \" ] = \" .. serializeImpl( v, tTracking, sSubIndent ) .. \",\\n\"\
4079 end\
4080 sResult = sResult .. sSubIndent .. sEntry\
4081 end\
4082 end\
4083 sResult = sResult .. sIndent .. \"}\"\
4084 return sResult\
4085 end\
4086\
4087 elseif sType == \"string\" then\
4088 return string.format( \"%q\", t )\
4089\
4090 elseif sType == \"number\" or sType == \"boolean\" or sType == \"nil\" then\
4091 return tostring(t)\
4092\
4093 else\
4094 error( \"Cannot serialize type \"..sType, 0 )\
4095\
4096 end\
4097end\
4098\
4099empty_json_array = {}\
4100\
4101local function serializeJSONImpl( t, tTracking, bNBTStyle )\
4102 local sType = type(t)\
4103 if t == empty_json_array then\
4104 return \"[]\"\
4105\
4106 elseif sType == \"table\" then\
4107 if tTracking[t] ~= nil then\
4108 error( \"Cannot serialize table with recursive entries\", 0 )\
4109 end\
4110 tTracking[t] = true\
4111\
4112 if next(t) == nil then\
4113 -- Empty tables are simple\
4114 return \"{}\"\
4115 else\
4116 -- Other tables take more work\
4117 local sObjectResult = \"{\"\
4118 local sArrayResult = \"[\"\
4119 local nObjectSize = 0\
4120 local nArraySize = 0\
4121 for k,v in pairs(t) do\
4122 if type(k) == \"string\" then\
4123 local sEntry\
4124 if bNBTStyle then\
4125 sEntry = tostring(k) .. \":\" .. serializeJSONImpl( v, tTracking, bNBTStyle )\
4126 else\
4127 sEntry = string.format( \"%q\", k ) .. \":\" .. serializeJSONImpl( v, tTracking, bNBTStyle )\
4128 end\
4129 if nObjectSize == 0 then\
4130 sObjectResult = sObjectResult .. sEntry\
4131 else\
4132 sObjectResult = sObjectResult .. \",\" .. sEntry\
4133 end\
4134 nObjectSize = nObjectSize + 1\
4135 end\
4136 end\
4137 for n,v in ipairs(t) do\
4138 local sEntry = serializeJSONImpl( v, tTracking, bNBTStyle )\
4139 if nArraySize == 0 then\
4140 sArrayResult = sArrayResult .. sEntry\
4141 else\
4142 sArrayResult = sArrayResult .. \",\" .. sEntry\
4143 end\
4144 nArraySize = nArraySize + 1\
4145 end\
4146 sObjectResult = sObjectResult .. \"}\"\
4147 sArrayResult = sArrayResult .. \"]\"\
4148 if nObjectSize > 0 or nArraySize == 0 then\
4149 return sObjectResult\
4150 else\
4151 return sArrayResult\
4152 end\
4153 end\
4154\
4155 elseif sType == \"string\" then\
4156 return string.format( \"%q\", t )\
4157\
4158 elseif sType == \"number\" or sType == \"boolean\" then\
4159 return tostring(t)\
4160\
4161 else\
4162 error( \"Cannot serialize type \"..sType, 0 )\
4163\
4164 end\
4165end\
4166\
4167function serialize( t )\
4168 local tTracking = {}\
4169 return serializeImpl( t, tTracking, \"\" )\
4170end\
4171\
4172function unserialize( s )\
4173 if type( s ) ~= \"string\" then\
4174 error( \"bad argument #1 (expected string, got \" .. type( s ) .. \")\", 2 )\
4175 end\
4176 local func = load( \"return \"..s, \"unserialize\", \"t\", {} )\
4177 if func then\
4178 local ok, result = pcall( func )\
4179 if ok then\
4180 return result\
4181 end\
4182 end\
4183 return nil\
4184end\
4185\
4186function serializeJSON( t, bNBTStyle )\
4187 if type( t ) ~= \"table\" and type( t ) ~= \"string\" and type( t ) ~= \"number\" and type( t ) ~= \"boolean\" then\
4188 error( \"bad argument #1 (expected table/string/number/boolean, got \" .. type( t ) .. \")\", 2 )\
4189 end\
4190 if bNBTStyle ~= nil and type( bNBTStyle ) ~= \"boolean\" then\
4191 error( \"bad argument #2 (expected boolean, got \" .. type( bNBTStyle ) .. \")\", 2 )\
4192 end\
4193 local tTracking = {}\
4194 return serializeJSONImpl( t, tTracking, bNBTStyle or false )\
4195end\
4196\
4197function urlEncode( str )\
4198 if type( str ) ~= \"string\" then\
4199 error( \"bad argument #1 (expected string, got \" .. type( str ) .. \")\", 2 )\
4200 end\
4201 if str then\
4202 str = string.gsub(str, \"\\n\", \"\\r\\n\")\
4203 str = string.gsub(str, \"([^A-Za-z0-9 %-%_%.])\", function(c)\
4204 local n = string.byte(c)\
4205 if n < 128 then\
4206 -- ASCII\
4207 return string.format(\"%%%02X\", n)\
4208 else\
4209 -- Non-ASCII (encode as UTF-8)\
4210 return\
4211 string.format(\"%%%02X\", 192 + bit32.band( bit32.arshift(n,6), 31 ) ) ..\
4212 string.format(\"%%%02X\", 128 + bit32.band( n, 63 ) )\
4213 end\
4214 end )\
4215 str = string.gsub(str, \" \", \"+\")\
4216 end\
4217 return str\
4218end\
4219\
4220local tEmpty = {}\
4221function complete( sSearchText, tSearchTable )\
4222 if type( sSearchText ) ~= \"string\" then\
4223 error( \"bad argument #1 (expected string, got \" .. type( sSearchText ) .. \")\", 2 )\
4224 end\
4225 if tSearchTable ~= nil and type( tSearchTable ) ~= \"table\" then\
4226 error( \"bad argument #2 (expected table, got \" .. type( tSearchTable ) .. \")\", 2 )\
4227 end\
4228\
4229 if g_tLuaKeywords[sSearchText] then return tEmpty end\
4230 local nStart = 1\
4231 local nDot = string.find( sSearchText, \".\", nStart, true )\
4232 local tTable = tSearchTable or _ENV\
4233 while nDot do\
4234 local sPart = string.sub( sSearchText, nStart, nDot - 1 )\
4235 local value = tTable[ sPart ]\
4236 if type( value ) == \"table\" then\
4237 tTable = value\
4238 nStart = nDot + 1\
4239 nDot = string.find( sSearchText, \".\", nStart, true )\
4240 else\
4241 return tEmpty\
4242 end\
4243 end\
4244 local nColon = string.find( sSearchText, \":\", nStart, true )\
4245 if nColon then\
4246 local sPart = string.sub( sSearchText, nStart, nColon - 1 )\
4247 local value = tTable[ sPart ]\
4248 if type( value ) == \"table\" then\
4249 tTable = value\
4250 nStart = nColon + 1\
4251 else\
4252 return tEmpty\
4253 end\
4254 end\
4255\
4256 local sPart = string.sub( sSearchText, nStart )\
4257 local nPartLength = string.len( sPart )\
4258\
4259 local tResults = {}\
4260 local tSeen = {}\
4261 while tTable do\
4262 for k,v in pairs( tTable ) do\
4263 if not tSeen[k] and type(k) == \"string\" then\
4264 if string.find( k, sPart, 1, true ) == 1 then\
4265 if not g_tLuaKeywords[k] and string.match( k, \"^[%a_][%a%d_]*$\" ) then\
4266 local sResult = string.sub( k, nPartLength + 1 )\
4267 if nColon then\
4268 if type(v) == \"function\" then\
4269 table.insert( tResults, sResult .. \"(\" )\
4270 elseif type(v) == \"table\" then\
4271 local tMetatable = getmetatable( v )\
4272 if tMetatable and ( type( tMetatable.__call ) == \"function\" or type( tMetatable.__call ) == \"table\" ) then\
4273 table.insert( tResults, sResult .. \"(\" )\
4274 end\
4275 end\
4276 else\
4277 if type(v) == \"function\" then\
4278 sResult = sResult .. \"(\"\
4279 elseif type(v) == \"table\" and next(v) ~= nil then\
4280 sResult = sResult .. \".\"\
4281 end\
4282 table.insert( tResults, sResult )\
4283 end\
4284 end\
4285 end\
4286 end\
4287 tSeen[k] = true\
4288 end\
4289 local tMetatable = getmetatable( tTable )\
4290 if tMetatable and type( tMetatable.__index ) == \"table\" then\
4291 tTable = tMetatable.__index\
4292 else\
4293 tTable = nil\
4294 end\
4295 end\
4296\
4297 table.sort( tResults )\
4298 return tResults\
4299end\
4300\
4301-- GB versions\
4302serialise = serialize\
4303unserialise = unserialize\
4304serialiseJSON = serializeJSON",
4305 [ "help/bundled.txt" ] = "To set bundled outputs:\
4306c = colors.combine( colors.red, colors.blue )\
4307rs.setBundledOutput( \"left\", c )\
4308\
4309c = colors.combine( c, colors.green )\
4310rs.setBundledOutput( \"left\", c )\
4311\
4312c = colors.subtract( c, colors.blue )\
4313rs.setBundledOutput( \"left\", c )\
4314\
4315To get bundled inputs:\
4316c = rs.getBundledInput( \"right\" )\
4317red = colors.test( c, colors.red )\
4318\
4319Type \"help colors\" for the list of wire colors.",
4320 [ "help/go.txt" ] = "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.\
4321\
4322ex:\
4323\"go forward\" moves the turtle 1 space forward.\
4324\"go forward 3\" moves the turtle 3 spaces forward.\
4325\"go forward 3 up left 2\" moves the turtle 3 spaces forward, 1 spaces up, then left 180 degrees.",
4326 [ "help/monitor.txt" ] = "monitor will connect to an attached Monitor peripheral, and run a program on its display.\
4327Type \"help monitors\" for help using monitors as peripherals in lua programs.\
4328\
4329ex:\
4330\"monitor left hello\" will run the \"hello\" program on the monitor to the left of the computer.\
4331\"monitor top edit foo\" will run the edit program on the top monitor, editing the file \"foo\".",
4332 [ "help/list.txt" ] = "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.",
4333 [ "help/falling.txt" ] = "\"From Russia with Fun\" comes a fun, new, suspiciously-familiar falling block game for CraftOS. Only on Pocket Computers!",
4334 [ "programs/drive.lua" ] = "local tArgs = { ... }\
4335\
4336-- Get where a directory is mounted\
4337local sPath = shell.dir()\
4338if tArgs[1] ~= nil then\
4339 sPath = shell.resolve( tArgs[1] )\
4340end\
4341\
4342if fs.exists( sPath ) then\
4343 write( fs.getDrive( sPath ) .. \" (\" )\
4344 local nSpace = fs.getFreeSpace( sPath )\
4345 if nSpace >= 1000 * 1000 then\
4346 print( (math.floor( nSpace / (100 * 1000) ) / 10) .. \"MB remaining)\" )\
4347 elseif nSpace >= 1000 then\
4348 print( (math.floor( nSpace / 100 ) / 10) .. \"KB remaining)\" )\
4349 else\
4350 print( nSpace .. \"B remaining)\" )\
4351 end\
4352else\
4353 print( \"No such path\" )\
4354end",
4355 [ "programs/mkdir.lua" ] = "local tArgs = { ... }\
4356if #tArgs < 1 then\
4357 print( \"Usage: mkdir <path>\" )\
4358 return\
4359end\
4360\
4361local sNewDir = shell.resolve( tArgs[1] )\
4362\
4363if fs.exists( sNewDir ) and not fs.isDir(sNewDir) then\
4364 printError( \"Destination exists\" )\
4365 return\
4366end\
4367\
4368fs.makeDir( sNewDir )",
4369 [ "programs/eject.lua" ] = "\
4370-- Get arguments\
4371local tArgs = { ... }\
4372if #tArgs == 0 then\
4373 print( \"Usage: eject <drive>\" )\
4374 return\
4375end\
4376\
4377local sDrive = tArgs[1]\
4378\
4379-- Check the disk exists\
4380local bPresent = disk.isPresent( sDrive )\
4381if not bPresent then\
4382 print( \"Nothing in \"..sDrive..\" drive\" )\
4383 return\
4384end\
4385\
4386disk.eject( sDrive )",
4387 [ "programs/turtle/turn.lua" ] = "local tArgs = { ... }\
4388if #tArgs < 1 then\
4389 print( \"Usage: turn <direction> <turns>\" )\
4390 return\
4391end\
4392\
4393local tHandlers = {\
4394 [\"lt\"] = turtle.turnLeft,\
4395 [\"left\"] = turtle.turnLeft,\
4396 [\"rt\"] = turtle.turnRight,\
4397 [\"right\"] = turtle.turnRight,\
4398}\
4399\
4400local nArg = 1\
4401while nArg <= #tArgs do\
4402 local sDirection = tArgs[nArg]\
4403 local nDistance = 1\
4404 if nArg < #tArgs then\
4405 local num = tonumber( tArgs[nArg + 1] )\
4406 if num then\
4407 nDistance = num\
4408 nArg = nArg + 1\
4409 end\
4410 end\
4411 nArg = nArg + 1\
4412\
4413 local fnHandler = tHandlers[string.lower(sDirection)]\
4414 if fnHandler then\
4415 for n=1,nDistance do\
4416 fnHandler( nArg )\
4417 end\
4418 else\
4419 print( \"No such direction: \"..sDirection )\
4420 print( \"Try: left, right\" )\
4421 return\
4422 end\
4423end",
4424 [ "help/rename.txt" ] = "rename renames a file or directory.\
4425\
4426ex:\
4427\"rename foo bar\" renames the file \"foo\" to \"bar\".",
4428 [ "apis/colors.lua" ] = "-- Colors\
4429white = 1\
4430orange = 2\
4431magenta = 4\
4432lightBlue = 8\
4433yellow = 16\
4434lime = 32\
4435pink = 64\
4436gray = 128\
4437lightGray = 256\
4438cyan = 512\
4439purple = 1024\
4440blue = 2048\
4441brown = 4096\
4442green = 8192\
4443red = 16384\
4444black = 32768\
4445\
4446function combine( ... )\
4447 local r = 0\
4448 for n,c in ipairs( { ... } ) do\
4449 if type( c ) ~= \"number\" then\
4450 error( \"bad argument #\"..n..\" (expected number, got \" .. type( c ) .. \")\", 2 )\
4451 end\
4452 r = bit32.bor(r,c)\
4453 end\
4454 return r\
4455end\
4456\
4457function subtract( colors, ... )\
4458 if type( colors ) ~= \"number\" then\
4459 error( \"bad argument #1 (expected number, got \" .. type( colors ) .. \")\", 2 )\
4460 end\
4461 local r = colors\
4462 for n,c in ipairs( { ... } ) do\
4463 if type( c ) ~= \"number\" then\
4464 error( \"bad argument #\"..tostring( n+1 )..\" (expected number, got \" .. type( c ) .. \")\", 2 )\
4465 end\
4466 r = bit32.band(r, bit32.bnot(c))\
4467 end\
4468 return r\
4469end\
4470\
4471function test( colors, color )\
4472 if type( colors ) ~= \"number\" then\
4473 error( \"bad argument #1 (expected number, got \" .. type( colors ) .. \")\", 2 )\
4474 end\
4475 if type( color ) ~= \"number\" then\
4476 error( \"bad argument #2 (expected number, got \" .. type( color ) .. \")\", 2 )\
4477 end\
4478 return ((bit32.band(colors, color)) == color)\
4479end\
4480\
4481function rgb8( r, g, b )\
4482 if type( r ) ~= \"number\" then\
4483 error( \"bad argument #1 (expected number, got \" .. type( r ) .. \")\", 2 )\
4484 elseif type(r) == \"number\" and g == nil and b == nil then\
4485 return bit32.band( bit32.rshift( r, 16 ), 0xFF ) / 255, bit32.band( bit32.rshift( r, 8 ), 0xFF ) / 255, bit32.band( r, 0xFF ) / 255\
4486 elseif type(r) == \"number\" and type(g) == \"number\" and type(b) == \"number\" then\
4487 return\
4488 bit32.lshift( bit32.band(r * 255, 0xFF), 16 ) +\
4489 bit32.lshift( bit32.band(g * 255, 0xFF), 8 ) +\
4490 bit32.band(b * 255, 0xFF)\
4491 elseif type( g ) ~= \"number\" then\
4492 error( \"bad argument #2 (expected number, got \" .. type( g ) .. \")\", 2 )\
4493 elseif type( b ) ~= \"number\" then\
4494 error( \"bad argument #3 (expected number, got \" .. type( b ) .. \")\", 2 )\
4495 end\
4496end",
4497 [ "help/coroutine.txt" ] = "coroutine is a standard Lua5.1 API.\
4498Refer to http://www.lua.org/manual/5.1/ for more information.",
4499 [ "apis/gps.lua" ] = "CHANNEL_GPS = 65534\
4500\
4501local function trilaterate( A, B, C )\
4502 local a2b = B.vPosition - A.vPosition\
4503 local a2c = C.vPosition - A.vPosition\
4504\
4505 if math.abs( a2b:normalize():dot( a2c:normalize() ) ) > 0.999 then\
4506 return nil\
4507 end\
4508\
4509 local d = a2b:length()\
4510 local ex = a2b:normalize( )\
4511 local i = ex:dot( a2c )\
4512 local ey = (a2c - (ex * i)):normalize()\
4513 local j = ey:dot( a2c )\
4514 local ez = ex:cross( ey )\
4515\
4516 local r1 = A.nDistance\
4517 local r2 = B.nDistance\
4518 local r3 = C.nDistance\
4519\
4520 local x = (r1*r1 - r2*r2 + d*d) / (2*d)\
4521 local y = (r1*r1 - r3*r3 - x*x + (x-i)*(x-i) + j*j) / (2*j)\
4522\
4523 local result = A.vPosition + (ex * x) + (ey * y)\
4524\
4525 local zSquared = r1*r1 - x*x - y*y\
4526 if zSquared > 0 then\
4527 local z = math.sqrt( zSquared )\
4528 local result1 = result + (ez * z)\
4529 local result2 = result - (ez * z)\
4530\
4531 local rounded1, rounded2 = result1:round( 0.01 ), result2:round( 0.01 )\
4532 if rounded1.x ~= rounded2.x or rounded1.y ~= rounded2.y or rounded1.z ~= rounded2.z then\
4533 return rounded1, rounded2\
4534 else\
4535 return rounded1\
4536 end\
4537 end\
4538 return result:round( 0.01 )\
4539\
4540end\
4541\
4542local function narrow( p1, p2, fix )\
4543 local dist1 = math.abs( (p1 - fix.vPosition):length() - fix.nDistance )\
4544 local dist2 = math.abs( (p2 - fix.vPosition):length() - fix.nDistance )\
4545\
4546 if math.abs(dist1 - dist2) < 0.01 then\
4547 return p1, p2\
4548 elseif dist1 < dist2 then\
4549 return p1:round( 0.01 )\
4550 else\
4551 return p2:round( 0.01 )\
4552 end\
4553end\
4554\
4555function locate( _nTimeout, _bDebug )\
4556 if _nTimeout ~= nil and type( _nTimeout ) ~= \"number\" then\
4557 error( \"bad argument #1 (expected number, got \" .. type( _nTimeout ) .. \")\", 2 )\
4558 end\
4559 if _bDebug ~= nil and type( _bDebug ) ~= \"boolean\" then\
4560 error( \"bad argument #2 (expected boolean, got \" .. type( _bDebug) .. \")\", 2 )\
4561 end\
4562 -- Let command computers use their magic fourth-wall-breaking special abilities\
4563 if commands then\
4564 return commands.getBlockPosition()\
4565 end\
4566\
4567 -- Find a modem\
4568 local sModemSide = nil\
4569 for n,sSide in ipairs( rs.getSides() ) do\
4570 if peripheral.getType( sSide ) == \"modem\" and peripheral.call( sSide, \"isWireless\" ) then\
4571 sModemSide = sSide\
4572 break\
4573 end\
4574 end\
4575\
4576 if sModemSide == nil then\
4577 if _bDebug then\
4578 print( \"No wireless modem attached\" )\
4579 end\
4580 return nil\
4581 end\
4582\
4583 if _bDebug then\
4584 print( \"Finding position...\" )\
4585 end\
4586\
4587 -- Open a channel\
4588 local modem = peripheral.wrap( sModemSide )\
4589 local bCloseChannel = false\
4590 if not modem.isOpen( os.getComputerID() ) then\
4591 modem.open( os.getComputerID() )\
4592 bCloseChannel = true\
4593 end\
4594\
4595 -- Send a ping to listening GPS hosts\
4596 modem.transmit( CHANNEL_GPS, os.getComputerID(), \"PING\" )\
4597\
4598 -- Wait for the responses\
4599 local tFixes = {}\
4600 local pos1, pos2 = nil, nil\
4601 local timeout = os.startTimer( _nTimeout or 2 )\
4602 while true do\
4603 local e, p1, p2, p3, p4, p5 = os.pullEvent()\
4604 if e == \"modem_message\" then\
4605 -- We received a reply from a modem\
4606 local sSide, sChannel, sReplyChannel, tMessage, nDistance = p1, p2, p3, p4, p5\
4607 if sSide == sModemSide and sChannel == os.getComputerID() and sReplyChannel == CHANNEL_GPS and nDistance then\
4608 -- Received the correct message from the correct modem: use it to determine position\
4609 if type(tMessage) == \"table\" and #tMessage == 3 and tonumber(tMessage[1]) and tonumber(tMessage[2]) and tonumber(tMessage[3]) then\
4610 local tFix = { vPosition = vector.new( tMessage[1], tMessage[2], tMessage[3] ), nDistance = nDistance }\
4611 if _bDebug then\
4612 print( tFix.nDistance..\" metres from \"..tostring( tFix.vPosition ) )\
4613 end\
4614 if tFix.nDistance == 0 then\
4615 pos1, pos2 = tFix.vPosition, nil\
4616 else\
4617 table.insert( tFixes, tFix )\
4618 if #tFixes >= 3 then\
4619 if not pos1 then\
4620 pos1, pos2 = trilaterate( tFixes[1], tFixes[2], tFixes[#tFixes] )\
4621 else\
4622 pos1, pos2 = narrow( pos1, pos2, tFixes[#tFixes] )\
4623 end\
4624 end\
4625 end\
4626 if pos1 and not pos2 then\
4627 break\
4628 end\
4629 end\
4630 end\
4631\
4632 elseif e == \"timer\" then\
4633 -- We received a timeout\
4634 local timer = p1\
4635 if timer == timeout then\
4636 break\
4637 end\
4638\
4639 end\
4640 end\
4641\
4642 -- Close the channel, if we opened one\
4643 if bCloseChannel then\
4644 modem.close( os.getComputerID() )\
4645 end\
4646\
4647 -- Return the response\
4648 if pos1 and pos2 then\
4649 if _bDebug then\
4650 print( \"Ambiguous position\" )\
4651 print( \"Could be \"..pos1.x..\",\"..pos1.y..\",\"..pos1.z..\" or \"..pos2.x..\",\"..pos2.y..\",\"..pos2.z )\
4652 end\
4653 return nil\
4654 elseif pos1 then\
4655 if _bDebug then\
4656 print( \"Position is \"..pos1.x..\",\"..pos1.y..\",\"..pos1.z )\
4657 end\
4658 return pos1.x, pos1.y, pos1.z\
4659 else\
4660 if _bDebug then\
4661 print( \"Could not determine position\" )\
4662 end\
4663 return nil\
4664 end\
4665end",
4666 [ "help/exit.txt" ] = "exit will exit the current shell.",
4667 [ "programs/edit.lua" ] = "-- Get file to edit\
4668local tArgs = { ... }\
4669if #tArgs == 0 then\
4670 print( \"Usage: edit <path>\" )\
4671 return\
4672end\
4673\
4674-- Error checking\
4675local sPath = shell.resolve( tArgs[1] )\
4676local bReadOnly = fs.isReadOnly( sPath )\
4677if fs.exists( sPath ) and fs.isDir( sPath ) then\
4678 print( \"Cannot edit a directory.\" )\
4679 return\
4680end\
4681\
4682-- Create .lua files by default\
4683if not fs.exists( sPath ) and not string.find( sPath, \"%.\" ) then\
4684 local sExtension = settings.get(\"edit.default_extension\", \"\" )\
4685 if sExtension ~= \"\" and type( sExtension ) == \"string\" then\
4686 sPath = sPath .. \".\" .. sExtension\
4687 end\
4688end\
4689\
4690local x,y = 1,1\
4691local w,h = term.getSize()\
4692local scrollX, scrollY = 0,0\
4693\
4694local tLines = {}\
4695local bRunning = true\
4696\
4697-- Colours\
4698local highlightColour, keywordColour, commentColour, textColour, bgColour, stringColour\
4699if term.isColour() then\
4700 bgColour = colours.black\
4701 textColour = colours.white\
4702 highlightColour = colours.yellow\
4703 keywordColour = colours.yellow\
4704 commentColour = colours.green\
4705 stringColour = colours.red\
4706else\
4707 bgColour = colours.black\
4708 textColour = colours.white\
4709 highlightColour = colours.white\
4710 keywordColour = colours.white\
4711 commentColour = colours.white\
4712 stringColour = colours.white\
4713end\
4714\
4715-- Menus\
4716local bMenu = false\
4717local nMenuItem = 1\
4718local tMenuItems = {}\
4719if not bReadOnly then\
4720 table.insert( tMenuItems, \"Save\" )\
4721end\
4722if shell.openTab then\
4723 table.insert( tMenuItems, \"Run\" )\
4724end\
4725if peripheral.find( \"printer\" ) then\
4726 table.insert( tMenuItems, \"Print\" )\
4727end\
4728table.insert( tMenuItems, \"Exit\" )\
4729\
4730local sStatus = \"Press Ctrl to access menu\"\
4731if string.len( sStatus ) > w - 5 then\
4732 sStatus = \"Press Ctrl for menu\"\
4733end\
4734\
4735local function load( _sPath )\
4736 tLines = {}\
4737 if fs.exists( _sPath ) then\
4738 local file = io.open( _sPath, \"r\" )\
4739 local sLine = file:read()\
4740 while sLine do\
4741 table.insert( tLines, sLine )\
4742 sLine = file:read()\
4743 end\
4744 file:close()\
4745 end\
4746\
4747 if #tLines == 0 then\
4748 table.insert( tLines, \"\" )\
4749 end\
4750end\
4751\
4752local function save( _sPath )\
4753 -- Create intervening folder\
4754 local sDir = _sPath:sub(1, _sPath:len() - fs.getName(_sPath):len() )\
4755 if not fs.exists( sDir ) then\
4756 fs.makeDir( sDir )\
4757 end\
4758\
4759 -- Save\
4760 local file, fileerr\
4761 local function innerSave()\
4762 file, fileerr = fs.open( _sPath, \"w\" )\
4763 if file then\
4764 for n, sLine in ipairs( tLines ) do\
4765 file.write( sLine .. \"\\n\" )\
4766 end\
4767 else\
4768 error( \"Failed to open \".._sPath )\
4769 end\
4770 end\
4771\
4772 local ok, err = pcall( innerSave )\
4773 if file then\
4774 file.close()\
4775 end\
4776 return ok, err, fileerr\
4777end\
4778\
4779local tKeywords = {\
4780 [\"and\"] = true,\
4781 [\"break\"] = true,\
4782 [\"do\"] = true,\
4783 [\"else\"] = true,\
4784 [\"elseif\"] = true,\
4785 [\"end\"] = true,\
4786 [\"false\"] = true,\
4787 [\"for\"] = true,\
4788 [\"function\"] = true,\
4789 [\"if\"] = true,\
4790 [\"in\"] = true,\
4791 [\"local\"] = true,\
4792 [\"nil\"] = true,\
4793 [\"not\"] = true,\
4794 [\"or\"] = true,\
4795 [\"repeat\"] = true,\
4796 [\"return\"] = true,\
4797 [\"then\"] = true,\
4798 [\"true\"] = true,\
4799 [\"until\"]= true,\
4800 [\"while\"] = true,\
4801}\
4802\
4803local function tryWrite( sLine, regex, colour )\
4804 local match = string.match( sLine, regex )\
4805 if match then\
4806 if type(colour) == \"number\" then\
4807 term.setTextColour( colour )\
4808 else\
4809 term.setTextColour( colour(match) )\
4810 end\
4811 term.write( match )\
4812 term.setTextColour( textColour )\
4813 return string.sub( sLine, string.len(match) + 1 )\
4814 end\
4815 return nil\
4816end\
4817\
4818local function writeHighlighted( sLine )\
4819 while string.len(sLine) > 0 do\
4820 sLine =\
4821 tryWrite( sLine, \"^%-%-%[%[.-%]%]\", commentColour ) or\
4822 tryWrite( sLine, \"^%-%-.*\", commentColour ) or\
4823 tryWrite( sLine, \"^\\\"\\\"\", stringColour ) or\
4824 tryWrite( sLine, \"^\\\".-[^\\\\]\\\"\", stringColour ) or\
4825 tryWrite( sLine, \"^\\'\\'\", stringColour ) or\
4826 tryWrite( sLine, \"^\\'.-[^\\\\]\\'\", stringColour ) or\
4827 tryWrite( sLine, \"^%[%[.-%]%]\", stringColour ) or\
4828 tryWrite( sLine, \"^[%w_]+\", function( match )\
4829 if tKeywords[ match ] then\
4830 return keywordColour\
4831 end\
4832 return textColour\
4833 end ) or\
4834 tryWrite( sLine, \"^[^%w_]\", textColour )\
4835 end\
4836end\
4837\
4838local tCompletions\
4839local nCompletion\
4840\
4841local tCompleteEnv = _ENV\
4842local function complete( sLine )\
4843 if settings.get( \"edit.autocomplete\" ) then\
4844 local nStartPos = string.find( sLine, \"[a-zA-Z0-9_%.:]+$\" )\
4845 if nStartPos then\
4846 sLine = string.sub( sLine, nStartPos )\
4847 end\
4848 if #sLine > 0 then\
4849 return textutils.complete( sLine, tCompleteEnv )\
4850 end\
4851 end\
4852 return nil\
4853end\
4854\
4855local function recomplete()\
4856 local sLine = tLines[y]\
4857 if not bMenu and not bReadOnly and x == string.len(sLine) + 1 then\
4858 tCompletions = complete( sLine )\
4859 if tCompletions and #tCompletions > 0 then\
4860 nCompletion = 1\
4861 else\
4862 nCompletion = nil\
4863 end\
4864 else\
4865 tCompletions = nil\
4866 nCompletion = nil\
4867 end\
4868end\
4869\
4870local function writeCompletion( sLine )\
4871 if nCompletion then\
4872 local sCompletion = tCompletions[ nCompletion ]\
4873 term.setTextColor( colours.white )\
4874 term.setBackgroundColor( colours.grey )\
4875 term.write( sCompletion )\
4876 term.setTextColor( textColour )\
4877 term.setBackgroundColor( bgColour )\
4878 end\
4879end\
4880\
4881local function redrawText()\
4882 local cursorX, cursorY = x, y\
4883 for y=1,h-1 do\
4884 term.setCursorPos( 1 - scrollX, y )\
4885 term.clearLine()\
4886\
4887 local sLine = tLines[ y + scrollY ]\
4888 if sLine ~= nil then\
4889 writeHighlighted( sLine )\
4890 if cursorY == y and cursorX == #sLine + 1 then\
4891 writeCompletion()\
4892 end\
4893 end\
4894 end\
4895 term.setCursorPos( x - scrollX, y - scrollY )\
4896end\
4897\
4898local function redrawLine(_nY)\
4899 local sLine = tLines[_nY]\
4900 if sLine then\
4901 term.setCursorPos( 1 - scrollX, _nY - scrollY )\
4902 term.clearLine()\
4903 writeHighlighted( sLine )\
4904 if _nY == y and x == #sLine + 1 then\
4905 writeCompletion()\
4906 end\
4907 term.setCursorPos( x - scrollX, _nY - scrollY )\
4908 end\
4909end\
4910\
4911local function redrawMenu()\
4912 -- Clear line\
4913 term.setCursorPos( 1, h )\
4914 term.clearLine()\
4915\
4916 -- Draw line numbers\
4917 term.setCursorPos( w - string.len( \"Ln \"..y ) + 1, h )\
4918 term.setTextColour( highlightColour )\
4919 term.write( \"Ln \" )\
4920 term.setTextColour( textColour )\
4921 term.write( y )\
4922\
4923 term.setCursorPos( 1, h )\
4924 if bMenu then\
4925 -- Draw menu\
4926 term.setTextColour( textColour )\
4927 for nItem,sItem in pairs( tMenuItems ) do\
4928 if nItem == nMenuItem then\
4929 term.setTextColour( highlightColour )\
4930 term.write( \"[\" )\
4931 term.setTextColour( textColour )\
4932 term.write( sItem )\
4933 term.setTextColour( highlightColour )\
4934 term.write( \"]\" )\
4935 term.setTextColour( textColour )\
4936 else\
4937 term.write( \" \"..sItem..\" \" )\
4938 end\
4939 end\
4940 else\
4941 -- Draw status\
4942 term.setTextColour( highlightColour )\
4943 term.write( sStatus )\
4944 term.setTextColour( textColour )\
4945 end\
4946\
4947 -- Reset cursor\
4948 term.setCursorPos( x - scrollX, y - scrollY )\
4949end\
4950\
4951local tMenuFuncs = {\
4952 Save = function()\
4953 if bReadOnly then\
4954 sStatus = \"Access denied\"\
4955 else\
4956 local ok, err, fileerr = save( sPath )\
4957 if ok then\
4958 sStatus=\"Saved to \"..sPath\
4959 else\
4960 if fileerr then\
4961 sStatus=\"Error saving to \"..fileerr\
4962 else\
4963 sStatus=\"Error saving to \"..sPath\
4964 end\
4965 end\
4966 end\
4967 redrawMenu()\
4968 end,\
4969 Print = function()\
4970 local printer = peripheral.find( \"printer\" )\
4971 if not printer then\
4972 sStatus = \"No printer attached\"\
4973 return\
4974 end\
4975\
4976 local nPage = 0\
4977 local sName = fs.getName( sPath )\
4978 if printer.getInkLevel() < 1 then\
4979 sStatus = \"Printer out of ink\"\
4980 return\
4981 elseif printer.getPaperLevel() < 1 then\
4982 sStatus = \"Printer out of paper\"\
4983 return\
4984 end\
4985\
4986 local screenTerminal = term.current()\
4987 local printerTerminal = {\
4988 getCursorPos = printer.getCursorPos,\
4989 setCursorPos = printer.setCursorPos,\
4990 getSize = printer.getPageSize,\
4991 write = printer.write,\
4992 }\
4993 printerTerminal.scroll = function()\
4994 if nPage == 1 then\
4995 printer.setPageTitle( sName..\" (page \"..nPage..\")\" )\
4996 end\
4997\
4998 while not printer.newPage() do\
4999 if printer.getInkLevel() < 1 then\
5000 sStatus = \"Printer out of ink, please refill\"\
5001 elseif printer.getPaperLevel() < 1 then\
5002 sStatus = \"Printer out of paper, please refill\"\
5003 else\
5004 sStatus = \"Printer output tray full, please empty\"\
5005 end\
5006\
5007 term.redirect( screenTerminal )\
5008 redrawMenu()\
5009 term.redirect( printerTerminal )\
5010\
5011 local timer = os.startTimer(0.5)\
5012 sleep(0.5)\
5013 end\
5014\
5015 nPage = nPage + 1\
5016 if nPage == 1 then\
5017 printer.setPageTitle( sName )\
5018 else\
5019 printer.setPageTitle( sName..\" (page \"..nPage..\")\" )\
5020 end\
5021 end\
5022\
5023 bMenu = false\
5024 term.redirect( printerTerminal )\
5025 local ok, error = pcall( function()\
5026 term.scroll()\
5027 for n, sLine in ipairs( tLines ) do\
5028 print( sLine )\
5029 end\
5030 end )\
5031 term.redirect( screenTerminal )\
5032 if not ok then\
5033 print( error )\
5034 end\
5035\
5036 while not printer.endPage() do\
5037 sStatus = \"Printer output tray full, please empty\"\
5038 redrawMenu()\
5039 sleep( 0.5 )\
5040 end\
5041 bMenu = true\
5042\
5043 if nPage > 1 then\
5044 sStatus = \"Printed \"..nPage..\" Pages\"\
5045 else\
5046 sStatus = \"Printed 1 Page\"\
5047 end\
5048 redrawMenu()\
5049 end,\
5050 Exit = function()\
5051 bRunning = false\
5052 end,\
5053 Run = function()\
5054 local sTempPath = \"/.temp\"\
5055 local ok, err = save( sTempPath )\
5056 if ok then\
5057 local nTask = shell.openTab( sTempPath )\
5058 if nTask then\
5059 shell.switchTab( nTask )\
5060 else\
5061 sStatus=\"Error starting Task\"\
5062 end\
5063 fs.delete( sTempPath )\
5064 else\
5065 sStatus=\"Error saving to \"..sTempPath\
5066 end\
5067 redrawMenu()\
5068 end\
5069}\
5070\
5071local function doMenuItem( _n )\
5072 tMenuFuncs[tMenuItems[_n]]()\
5073 if bMenu then\
5074 bMenu = false\
5075 term.setCursorBlink( true )\
5076 end\
5077 redrawMenu()\
5078end\
5079\
5080local function setCursor( newX, newY )\
5081 local oldX, oldY = x, y\
5082 x, y = newX, newY\
5083 local screenX = x - scrollX\
5084 local screenY = y - scrollY\
5085\
5086 local bRedraw = false\
5087 if screenX < 1 then\
5088 scrollX = x - 1\
5089 screenX = 1\
5090 bRedraw = true\
5091 elseif screenX > w then\
5092 scrollX = x - w\
5093 screenX = w\
5094 bRedraw = true\
5095 end\
5096\
5097 if screenY < 1 then\
5098 scrollY = y - 1\
5099 screenY = 1\
5100 bRedraw = true\
5101 elseif screenY > h-1 then\
5102 scrollY = y - (h-1)\
5103 screenY = h-1\
5104 bRedraw = true\
5105 end\
5106\
5107 recomplete()\
5108 if bRedraw then\
5109 redrawText()\
5110 elseif y ~= oldY then\
5111 redrawLine( oldY )\
5112 redrawLine( y )\
5113 else\
5114 redrawLine( y )\
5115 end\
5116 term.setCursorPos( screenX, screenY )\
5117\
5118 redrawMenu()\
5119end\
5120\
5121-- Actual program functionality begins\
5122load(sPath)\
5123\
5124term.setBackgroundColour( bgColour )\
5125term.clear()\
5126term.setCursorPos(x,y)\
5127term.setCursorBlink( true )\
5128\
5129recomplete()\
5130redrawText()\
5131redrawMenu()\
5132\
5133local function acceptCompletion()\
5134 if nCompletion then\
5135 -- Append the completion\
5136 local sCompletion = tCompletions[ nCompletion ]\
5137 tLines[y] = tLines[y] .. sCompletion\
5138 setCursor( x + string.len( sCompletion ), y )\
5139 end\
5140end\
5141\
5142-- Handle input\
5143while bRunning do\
5144 local sEvent, param, param2, param3 = os.pullEvent()\
5145 if sEvent == \"key\" then\
5146 local oldX, oldY = x, y\
5147 if param == keys.up then\
5148 -- Up\
5149 if not bMenu then\
5150 if nCompletion then\
5151 -- Cycle completions\
5152 nCompletion = nCompletion - 1\
5153 if nCompletion < 1 then\
5154 nCompletion = #tCompletions\
5155 end\
5156 redrawLine(y)\
5157\
5158 elseif y > 1 then\
5159 -- Move cursor up\
5160 setCursor(\
5161 math.min( x, string.len( tLines[y - 1] ) + 1 ),\
5162 y - 1\
5163 )\
5164 end\
5165 end\
5166\
5167 elseif param == keys.down then\
5168 -- Down\
5169 if not bMenu then\
5170 -- Move cursor down\
5171 if nCompletion then\
5172 -- Cycle completions\
5173 nCompletion = nCompletion + 1\
5174 if nCompletion > #tCompletions then\
5175 nCompletion = 1\
5176 end\
5177 redrawLine(y)\
5178\
5179 elseif y < #tLines then\
5180 -- Move cursor down\
5181 setCursor(\
5182 math.min( x, string.len( tLines[y + 1] ) + 1 ),\
5183 y + 1\
5184 )\
5185 end\
5186 end\
5187\
5188 elseif param == keys.tab then\
5189 -- Tab\
5190 if not bMenu and not bReadOnly then\
5191 if nCompletion and x == string.len(tLines[y]) + 1 then\
5192 -- Accept autocomplete\
5193 acceptCompletion()\
5194 else\
5195 -- Indent line\
5196 local sLine = tLines[y]\
5197 tLines[y] = string.sub(sLine,1,x-1) .. \" \" .. string.sub(sLine,x)\
5198 setCursor( x + 4, y )\
5199 end\
5200 end\
5201\
5202 elseif param == keys.pageUp then\
5203 -- Page Up\
5204 if not bMenu then\
5205 -- Move up a page\
5206 local newY\
5207 if y - (h - 1) >= 1 then\
5208 newY = y - (h - 1)\
5209 else\
5210 newY = 1\
5211 end\
5212 setCursor(\
5213 math.min( x, string.len( tLines[newY] ) + 1 ),\
5214 newY\
5215 )\
5216 end\
5217\
5218 elseif param == keys.pageDown then\
5219 -- Page Down\
5220 if not bMenu then\
5221 -- Move down a page\
5222 local newY\
5223 if y + (h - 1) <= #tLines then\
5224 newY = y + (h - 1)\
5225 else\
5226 newY = #tLines\
5227 end\
5228 local newX = math.min( x, string.len( tLines[newY] ) + 1 )\
5229 setCursor( newX, newY )\
5230 end\
5231\
5232 elseif param == keys.home then\
5233 -- Home\
5234 if not bMenu then\
5235 -- Move cursor to the beginning\
5236 if x > 1 then\
5237 setCursor(1,y)\
5238 end\
5239 end\
5240\
5241 elseif param == keys[\"end\"] then\
5242 -- End\
5243 if not bMenu then\
5244 -- Move cursor to the end\
5245 local nLimit = string.len( tLines[y] ) + 1\
5246 if x < nLimit then\
5247 setCursor( nLimit, y )\
5248 end\
5249 end\
5250\
5251 elseif param == keys.left then\
5252 -- Left\
5253 if not bMenu then\
5254 if x > 1 then\
5255 -- Move cursor left\
5256 setCursor( x - 1, y )\
5257 elseif x==1 and y>1 then\
5258 setCursor( string.len( tLines[y-1] ) + 1, y - 1 )\
5259 end\
5260 else\
5261 -- Move menu left\
5262 nMenuItem = nMenuItem - 1\
5263 if nMenuItem < 1 then\
5264 nMenuItem = #tMenuItems\
5265 end\
5266 redrawMenu()\
5267 end\
5268\
5269 elseif param == keys.right then\
5270 -- Right\
5271 if not bMenu then\
5272 local nLimit = string.len( tLines[y] ) + 1\
5273 if x < nLimit then\
5274 -- Move cursor right\
5275 setCursor( x + 1, y )\
5276 elseif nCompletion and x == string.len(tLines[y]) + 1 then\
5277 -- Accept autocomplete\
5278 acceptCompletion()\
5279 elseif x==nLimit and y<#tLines then\
5280 -- Go to next line\
5281 setCursor( 1, y + 1 )\
5282 end\
5283 else\
5284 -- Move menu right\
5285 nMenuItem = nMenuItem + 1\
5286 if nMenuItem > #tMenuItems then\
5287 nMenuItem = 1\
5288 end\
5289 redrawMenu()\
5290 end\
5291\
5292 elseif param == keys.delete then\
5293 -- Delete\
5294 if not bMenu and not bReadOnly then\
5295 local nLimit = string.len( tLines[y] ) + 1\
5296 if x < nLimit then\
5297 local sLine = tLines[y]\
5298 tLines[y] = string.sub(sLine,1,x-1) .. string.sub(sLine,x+1)\
5299 recomplete()\
5300 redrawLine(y)\
5301 elseif y<#tLines then\
5302 tLines[y] = tLines[y] .. tLines[y+1]\
5303 table.remove( tLines, y+1 )\
5304 recomplete()\
5305 redrawText()\
5306 end\
5307 end\
5308\
5309 elseif param == keys.backspace then\
5310 -- Backspace\
5311 if not bMenu and not bReadOnly then\
5312 if x > 1 then\
5313 -- Remove character\
5314 local sLine = tLines[y]\
5315 if x > 4 and string.sub(sLine,x-4,x-1) == \" \" and not string.sub(sLine, 1, x - 1):find(\"%S\") then\
5316 tLines[y] = string.sub(sLine,1,x-5) .. string.sub(sLine,x)\
5317 setCursor( x - 4, y )\
5318 else\
5319 tLines[y] = string.sub(sLine,1,x-2) .. string.sub(sLine,x)\
5320 setCursor( x - 1, y )\
5321 end\
5322 elseif y > 1 then\
5323 -- Remove newline\
5324 local sPrevLen = string.len( tLines[y-1] )\
5325 tLines[y-1] = tLines[y-1] .. tLines[y]\
5326 table.remove( tLines, y )\
5327 setCursor( sPrevLen + 1, y - 1 )\
5328 redrawText()\
5329 end\
5330 end\
5331\
5332 elseif param == keys.enter then\
5333 -- Enter\
5334 if not bMenu and not bReadOnly then\
5335 -- Newline\
5336 local sLine = tLines[y]\
5337 local _,spaces=string.find(sLine,\"^[ ]+\")\
5338 if not spaces then\
5339 spaces=0\
5340 end\
5341 tLines[y] = string.sub(sLine,1,x-1)\
5342 table.insert( tLines, y+1, string.rep(' ',spaces)..string.sub(sLine,x) )\
5343 setCursor( spaces + 1, y + 1 )\
5344 redrawText()\
5345\
5346 elseif bMenu then\
5347 -- Menu selection\
5348 doMenuItem( nMenuItem )\
5349\
5350 end\
5351\
5352 elseif param == keys.leftCtrl or param == keys.rightCtrl or param == keys.rightAlt then\
5353 -- Menu toggle\
5354 bMenu = not bMenu\
5355 if bMenu then\
5356 term.setCursorBlink( false )\
5357 else\
5358 term.setCursorBlink( true )\
5359 end\
5360 redrawMenu()\
5361\
5362 end\
5363\
5364 elseif sEvent == \"char\" then\
5365 if not bMenu and not bReadOnly then\
5366 -- Input text\
5367 local sLine = tLines[y]\
5368 tLines[y] = string.sub(sLine,1,x-1) .. param .. string.sub(sLine,x)\
5369 setCursor( x + 1, y )\
5370\
5371 elseif bMenu then\
5372 -- Select menu items\
5373 for n,sMenuItem in ipairs( tMenuItems ) do\
5374 if string.lower(string.sub(sMenuItem,1,1)) == string.lower(param) then\
5375 doMenuItem( n )\
5376 break\
5377 end\
5378 end\
5379 end\
5380\
5381 elseif sEvent == \"paste\" then\
5382 if not bReadOnly then\
5383 -- Close menu if open\
5384 if bMenu then\
5385 bMenu = false\
5386 term.setCursorBlink( true )\
5387 redrawMenu()\
5388 end\
5389 -- Input text\
5390 local sLine = tLines[y]\
5391 tLines[y] = string.sub(sLine,1,x-1) .. param .. string.sub(sLine,x)\
5392 setCursor( x + string.len( param ), y )\
5393 end\
5394\
5395 elseif sEvent == \"mouse_click\" then\
5396 if not bMenu then\
5397 if param == 1 then\
5398 -- Left click\
5399 local cx,cy = param2, param3\
5400 if cy < h then\
5401 local newY = math.min( math.max( scrollY + cy, 1 ), #tLines )\
5402 local newX = math.min( math.max( scrollX + cx, 1 ), string.len( tLines[newY] ) + 1 )\
5403 setCursor( newX, newY )\
5404 end\
5405 end\
5406 end\
5407\
5408 elseif sEvent == \"mouse_scroll\" then\
5409 if not bMenu then\
5410 if param == -1 then\
5411 -- Scroll up\
5412 if scrollY > 0 then\
5413 -- Move cursor up\
5414 scrollY = scrollY - 1\
5415 redrawText()\
5416 end\
5417\
5418 elseif param == 1 then\
5419 -- Scroll down\
5420 local nMaxScroll = #tLines - (h-1)\
5421 if scrollY < nMaxScroll then\
5422 -- Move cursor down\
5423 scrollY = scrollY + 1\
5424 redrawText()\
5425 end\
5426\
5427 end\
5428 end\
5429\
5430 elseif sEvent == \"term_resize\" then\
5431 w,h = term.getSize()\
5432 setCursor( x, y )\
5433 redrawMenu()\
5434 redrawText()\
5435\
5436 end\
5437end\
5438\
5439-- Cleanup\
5440term.clear()\
5441term.setCursorBlink( false )\
5442term.setCursorPos( 1, 1 )",
5443 [ "help/mkdir.txt" ] = "mkdir creates a directory in the current location.\
5444\
5445ex:\
5446\"mkdir foo\" creates a directory named \"foo\".\
5447\"mkdir ../foo\" creates a directory named \"foo\" in the directory above the current directory.",
5448 [ "apis/peripheral.lua" ] = "local native = peripheral\
5449\
5450function getNames()\
5451 local tResults = {}\
5452 for n,sSide in ipairs( rs.getSides() ) do\
5453 if native.isPresent( sSide ) then\
5454 table.insert( tResults, sSide )\
5455 if native.getType( sSide ) == \"modem\" and not native.call( sSide, \"isWireless\" ) then\
5456 local tRemote = native.call( sSide, \"getNamesRemote\" )\
5457 for n,sName in ipairs( tRemote ) do\
5458 table.insert( tResults, sName )\
5459 end\
5460 end\
5461 end\
5462 end\
5463 return tResults\
5464end\
5465\
5466function isPresent( _sSide )\
5467 if type( _sSide ) ~= \"string\" then\
5468 error( \"bad argument #1 (expected string, got \" .. type( _sSide ) .. \")\", 2 )\
5469 end\
5470 if native.isPresent( _sSide ) then\
5471 return true\
5472 end\
5473 for n,sSide in ipairs( rs.getSides() ) do\
5474 if native.getType( sSide ) == \"modem\" and not native.call( sSide, \"isWireless\" ) then\
5475 if native.call( sSide, \"isPresentRemote\", _sSide ) then\
5476 return true\
5477 end\
5478 end\
5479 end\
5480 return false\
5481end\
5482\
5483function getType( _sSide )\
5484 if type( _sSide ) ~= \"string\" then\
5485 error( \"bad argument #1 (expected string, got \" .. type( _sSide ) .. \")\", 2 )\
5486 end\
5487 if native.isPresent( _sSide ) then\
5488 return native.getType( _sSide )\
5489 end\
5490 for n,sSide in ipairs( rs.getSides() ) do\
5491 if native.getType( sSide ) == \"modem\" and not native.call( sSide, \"isWireless\" ) then\
5492 if native.call( sSide, \"isPresentRemote\", _sSide ) then\
5493 return native.call( sSide, \"getTypeRemote\", _sSide )\
5494 end\
5495 end\
5496 end\
5497 return nil\
5498end\
5499\
5500function getMethods( _sSide )\
5501 if type( _sSide ) ~= \"string\" then\
5502 error( \"bad argument #1 (expected string, got \" .. type( _sSide ) .. \")\", 2 )\
5503 end\
5504 if native.isPresent( _sSide ) then\
5505 return native.getMethods( _sSide )\
5506 end\
5507 for n,sSide in ipairs( rs.getSides() ) do\
5508 if native.getType( sSide ) == \"modem\" and not native.call( sSide, \"isWireless\" ) then\
5509 if native.call( sSide, \"isPresentRemote\", _sSide ) then\
5510 return native.call( sSide, \"getMethodsRemote\", _sSide )\
5511 end\
5512 end\
5513 end\
5514 return nil\
5515end\
5516\
5517function call( _sSide, _sMethod, ... )\
5518 if type( _sSide ) ~= \"string\" then\
5519 error( \"bad argument #1 (expected string, got \" .. type( _sSide ) .. \")\", 2 )\
5520 end\
5521 if type( _sSide ) ~= \"string\" then\
5522 error( \"bad argument #2 (expected string, got \" .. type( _sMethod ) .. \")\", 2 )\
5523 end\
5524 if native.isPresent( _sSide ) then\
5525 return native.call( _sSide, _sMethod, ... )\
5526 end\
5527 for n,sSide in ipairs( rs.getSides() ) do\
5528 if native.getType( sSide ) == \"modem\" and not native.call( sSide, \"isWireless\" ) then\
5529 if native.call( sSide, \"isPresentRemote\", _sSide ) then\
5530 return native.call( sSide, \"callRemote\", _sSide, _sMethod, ... )\
5531 end\
5532 end\
5533 end\
5534 return nil\
5535end\
5536\
5537function wrap( _sSide )\
5538 if type( _sSide ) ~= \"string\" then\
5539 error( \"bad argument #1 (expected string, got \" .. type( _sSide ) .. \")\", 2 )\
5540 end\
5541 if peripheral.isPresent( _sSide ) then\
5542 local tMethods = peripheral.getMethods( _sSide )\
5543 local tResult = {}\
5544 for n,sMethod in ipairs( tMethods ) do\
5545 tResult[sMethod] = function( ... )\
5546 return peripheral.call( _sSide, sMethod, ... )\
5547 end\
5548 end\
5549 return tResult\
5550 end\
5551 return nil\
5552end\
5553\
5554function find( sType, fnFilter )\
5555 if type( sType ) ~= \"string\" then\
5556 error( \"bad argument #1 (expected string, got \" .. type( sType ) .. \")\", 2 )\
5557 end\
5558 if fnFilter ~= nil and type( fnFilter ) ~= \"function\" then\
5559 error( \"bad argument #2 (expected function, got \" .. type( fnFilter ) .. \")\", 2 )\
5560 end\
5561 local tResults = {}\
5562 for n,sName in ipairs( peripheral.getNames() ) do\
5563 if peripheral.getType( sName ) == sType then\
5564 local wrapped = peripheral.wrap( sName )\
5565 if fnFilter == nil or fnFilter( sName, wrapped ) then\
5566 table.insert( tResults, wrapped )\
5567 end\
5568 end\
5569 end\
5570 return table.unpack( tResults )\
5571end",
5572 [ "help/programming.txt" ] = "To learn the lua programming language, visit http://lua-users.org/wiki/TutorialDirectory.\
5573\
5574To experiment with lua in CraftOS, run the \"lua\" program and start typing code.\
5575To 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.\
5576\
5577To terminate a program stuck in a loop, hold Ctrl+T for 1 second.\
5578To quickly shutdown a computer, hold Ctrl+S for 1 second.\
5579To quickly reboot a computer, hold Ctrl+R for 1 second.\
5580\
5581To learn about the programming APIs availiable, type \"apis\" or \"help apis\".\
5582If you get stuck, visit the forums at http://www.computercraft.info/ for advice and tutorials.",
5583 [ "help/fg.txt" ] = "fg is a program for Advanced Computers which opens a new tab in the foreground.\
5584\
5585ex:\
5586\"fg\" will open a foreground tab running the shell\
5587\"fg worm\" will open a foreground tab running the \"worm\" program",
5588 [ "apis/colours.lua" ] = "-- Colours (for lovers of british spelling)\
5589local colours = _ENV\
5590for k,v in pairs(colors) do\
5591 colours[k] = v\
5592end\
5593\
5594colours.grey = colors.gray\
5595colours.gray = nil\
5596\
5597colours.lightGrey = colors.lightGray\
5598colours.lightGray = nil",
5599 [ "apis/turtle/turtle.lua" ] = "\
5600if not turtle then\
5601 error( \"Cannot load turtle API on computer\", 2 )\
5602end\
5603native = turtle.native or turtle\
5604\
5605local function addCraftMethod( object )\
5606 if peripheral.getType( \"left\" ) == \"workbench\" then\
5607 object.craft = function( ... )\
5608 return peripheral.call( \"left\", \"craft\", ... )\
5609 end\
5610 elseif peripheral.getType( \"right\" ) == \"workbench\" then\
5611 object.craft = function( ... )\
5612 return peripheral.call( \"right\", \"craft\", ... )\
5613 end\
5614 else\
5615 object.craft = nil\
5616 end\
5617end\
5618\
5619-- Put commands into environment table\
5620local env = _ENV\
5621for k,v in pairs( native ) do\
5622 if k == \"equipLeft\" or k == \"equipRight\" then\
5623 env[k] = function( ... )\
5624 local result, err = v( ... )\
5625 addCraftMethod( turtle )\
5626 return result, err\
5627 end\
5628 else\
5629 env[k] = v\
5630 end\
5631end\
5632addCraftMethod( env )",
5633 [ "programs/set.lua" ] = "\
5634local tArgs = { ... }\
5635if #tArgs == 0 then\
5636 -- \"set\"\
5637 local x,y = term.getCursorPos()\
5638 local tSettings = {}\
5639 for n,sName in ipairs( settings.getNames() ) do\
5640 tSettings[n] = textutils.serialize(sName) .. \" is \" .. textutils.serialize(settings.get(sName))\
5641 end\
5642 textutils.pagedPrint(table.concat(tSettings,\"\\n\"),y-3)\
5643\
5644elseif #tArgs == 1 then\
5645 -- \"set foo\"\
5646 local sName = tArgs[1]\
5647 print( textutils.serialize(sName) .. \" is \" .. textutils.serialize(settings.get(sName)) )\
5648\
5649else\
5650 -- \"set foo bar\"\
5651 local sName = tArgs[1]\
5652 local sValue = tArgs[2]\
5653 local value\
5654 if sValue == \"true\" then\
5655 value = true\
5656 elseif sValue == \"false\" then\
5657 value = false\
5658 elseif sValue == \"nil\" then\
5659 value = nil\
5660 elseif tonumber(sValue) then\
5661 value = tonumber(sValue)\
5662 else\
5663 value = sValue\
5664 end\
5665\
5666 local oldValue = settings.get( sValue )\
5667 if value ~= nil then\
5668 settings.set( sName, value )\
5669 print( textutils.serialize(sName) .. \" set to \" .. textutils.serialize(value) )\
5670 else\
5671 settings.unset( sName )\
5672 print( textutils.serialize(sName) .. \" unset\" )\
5673 end\
5674 if value ~= oldValue then\
5675 settings.save( \".settings\" )\
5676 end\
5677end",
5678 [ "help/parallel.txt" ] = "Functions in the Parallel API:\
5679parallel.waitForAny( function1, function2, ... )\
5680parallel.waitForAll( function1, function2, ... )\
5681These methods provide an easy way to run multiple lua functions simultaneously.",
5682 [ "help/wget.txt" ] = "wget is a program for downloading files from the internet. This is useful for downloading programs created by other players.\
5683If no filename is specified wget will try to determine the filename from the URL by stripping any anchors, parameters and trailing slashes and then taking everything remaining after the last slash.\
5684The HTTP API must be enabled in ComputerCraft.cfg to use this program.\
5685ex:\
5686\"wget http://pastebin.com/raw/CxaWmPrX test\" will download the file from the URL http://pastebin.com/raw/CxaWmPrX, and save it as \"test\".\
5687\"wget http://example.org/test.lua/?foo=bar#qzu\" will download the file from the URL http://example.org/test.lua/?foo=bar#qzu and save it as \"test.lua\"\
5688\"wget http://example.org/\" will download the file from the URL http://example.org and save it as \"example.org\"",
5689 [ "help/edit.txt" ] = "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.\
5690\
5691ex:\
5692\"edit hello\" opens a file called \"hello\" for editing.",
5693 [ "programs/exit.lua" ] = "shell.exit()",
5694 [ "help/rednet.txt" ] = "The rednet API provides a simple computer networking model using modems.\
5695\
5696Functions in the rednet API:\
5697rednet.open( side )\
5698rednet.close( [side] )\
5699rednet.isOpen( [side] )\
5700rednet.send( receiverID, message, [protocol] ) -- Send to a specific computer\
5701rednet.broadcast( message, [protocol] ) -- Send to all computers\
5702rednet.receive( [protocol], [timeout] ) -- Returns: senderID, message, protocol\
5703rednet.host( protocol, hostname )\
5704rednet.unhost( protocol )\
5705rednet.lookup( protocol, [hostname] ) -- Returns: ID\
5706\
5707Events fired by the rednet API:\
5708\"rednet_message\" when a message is received. Arguments are senderID, message, protocol\
5709Type \"help events\" to learn about the event system.\
5710\
5711Rednet 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.",
5712 [ "help/turn.txt" ] = "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.\
5713\
5714ex:\
5715\"turn left\" turns the turtle 90 degrees left.\
5716\"turn right 2\" turns the turtle 180 degrees right.\
5717\"turn left 2 right\" turns left 180 degrees, then right 90 degrees.",
5718 [ "programs/fun/advanced/levels/4.dat" ] = "2\
5719 77777777\
5720777778888887\
5721788888777787\
57227b77787 787\
5723787 787 787\
57247b77787 787\
57257888887 787\
57267777707 707\
5727 777 777",
5728 [ "programs/fun/advanced/levels/0.dat" ] = "0\
572977 77\
5730718888887\
5731 8 8\
5732 8 8\
5733 8 8\
5734788888897\
573577 77",
5736 [ "help/workbench.txt" ] = "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\".\
5737\
5738Methods exposed by Workbenches:\
5739craft( channel )",
5740 [ "programs/fun/advanced/levels/9.dat" ] = "2\
5741 777 777\
5742 777877778777\
5743 788838888887\
57447778bbbbbbbb8777\
57457888b888888b8897\
57467878be8888eb8787\
57477588b888888b8887\
57487778bbbbbbbb8777\
5749 788888818887\
5750 777877778777\
5751 777 777",
5752 [ "startup.lua" ] = "\
5753-- Setup paths\
5754local sPath = \".:/rom/programs\"\
5755if term.isColor() then\
5756 sPath = sPath..\":/rom/programs/advanced\"\
5757end\
5758if turtle then\
5759 sPath = sPath..\":/rom/programs/turtle\"\
5760else\
5761 sPath = sPath..\":/rom/programs/rednet:/rom/programs/fun\"\
5762 if term.isColor() then\
5763 sPath = sPath..\":/rom/programs/fun/advanced\"\
5764 end\
5765end\
5766if pocket then\
5767 sPath = sPath..\":/rom/programs/pocket\"\
5768end\
5769if commands then\
5770 sPath = sPath..\":/rom/programs/command\"\
5771end\
5772if http then\
5773 sPath = sPath..\":/rom/programs/http\"\
5774end\
5775shell.setPath( sPath )\
5776help.setPath( \"/rom/help\" )\
5777\
5778-- Setup aliases\
5779shell.setAlias( \"ls\", \"list\" )\
5780shell.setAlias( \"dir\", \"list\" )\
5781shell.setAlias( \"cp\", \"copy\" )\
5782shell.setAlias( \"mv\", \"move\" )\
5783shell.setAlias( \"rm\", \"delete\" )\
5784shell.setAlias( \"clr\", \"clear\" )\
5785shell.setAlias( \"rs\", \"redstone\" )\
5786shell.setAlias( \"sh\", \"shell\" )\
5787if term.isColor() then\
5788 shell.setAlias( \"background\", \"bg\" )\
5789 shell.setAlias( \"foreground\", \"fg\" )\
5790end\
5791\
5792-- Setup completion functions\
5793local function completeMultipleChoice( sText, tOptions, bAddSpaces )\
5794 local tResults = {}\
5795 for n=1,#tOptions do\
5796 local sOption = tOptions[n]\
5797 if #sOption + (bAddSpaces and 1 or 0) > #sText and string.sub( sOption, 1, #sText ) == sText then\
5798 local sResult = string.sub( sOption, #sText + 1 )\
5799 if bAddSpaces then\
5800 table.insert( tResults, sResult .. \" \" )\
5801 else\
5802 table.insert( tResults, sResult )\
5803 end\
5804 end\
5805 end\
5806 return tResults\
5807end\
5808local function completePeripheralName( sText, bAddSpaces )\
5809 return completeMultipleChoice( sText, peripheral.getNames(), bAddSpaces )\
5810end\
5811local tRedstoneSides = redstone.getSides()\
5812local function completeSide( sText, bAddSpaces )\
5813 return completeMultipleChoice( sText, tRedstoneSides, bAddSpaces )\
5814end\
5815local function completeFile( shell, nIndex, sText, tPreviousText )\
5816 if nIndex == 1 then\
5817 return fs.complete( sText, shell.dir(), true, false )\
5818 end\
5819end\
5820local function completeDir( shell, nIndex, sText, tPreviousText )\
5821 if nIndex == 1 then\
5822 return fs.complete( sText, shell.dir(), false, true )\
5823 end\
5824end\
5825local function completeEither( shell, nIndex, sText, tPreviousText )\
5826 if nIndex == 1 then\
5827 return fs.complete( sText, shell.dir(), true, true )\
5828 end\
5829end\
5830local function completeEitherEither( shell, nIndex, sText, tPreviousText )\
5831 if nIndex == 1 then\
5832 local tResults = fs.complete( sText, shell.dir(), true, true )\
5833 for n=1,#tResults do\
5834 local sResult = tResults[n]\
5835 if string.sub( sResult, #sResult, #sResult ) ~= \"/\" then\
5836 tResults[n] = sResult .. \" \"\
5837 end\
5838 end\
5839 return tResults\
5840 elseif nIndex == 2 then\
5841 return fs.complete( sText, shell.dir(), true, true )\
5842 end\
5843end\
5844local function completeProgram( shell, nIndex, sText, tPreviousText )\
5845 if nIndex == 1 then\
5846 return shell.completeProgram( sText )\
5847 end\
5848end\
5849local function completeHelp( shell, nIndex, sText, tPreviousText )\
5850 if nIndex == 1 then\
5851 return help.completeTopic( sText )\
5852 end\
5853end\
5854local function completeAlias( shell, nIndex, sText, tPreviousText )\
5855 if nIndex == 2 then\
5856 return shell.completeProgram( sText )\
5857 end\
5858end\
5859local function completePeripheral( shell, nIndex, sText, tPreviousText )\
5860 if nIndex == 1 then\
5861 return completePeripheralName( sText )\
5862 end\
5863end\
5864local tGPSOptions = { \"host\", \"host \", \"locate\" }\
5865local function completeGPS( shell, nIndex, sText, tPreviousText )\
5866 if nIndex == 1 then\
5867 return completeMultipleChoice( sText, tGPSOptions )\
5868 end\
5869end\
5870local tLabelOptions = { \"get\", \"get \", \"set \", \"clear\", \"clear \" }\
5871local function completeLabel( shell, nIndex, sText, tPreviousText )\
5872 if nIndex == 1 then\
5873 return completeMultipleChoice( sText, tLabelOptions )\
5874 elseif nIndex == 2 then\
5875 return completePeripheralName( sText )\
5876 end\
5877end\
5878local function completeMonitor( shell, nIndex, sText, tPreviousText )\
5879 if nIndex == 1 then\
5880 return completePeripheralName( sText, true )\
5881 elseif nIndex == 2 then\
5882 return shell.completeProgram( sText )\
5883 end\
5884end\
5885local tRedstoneOptions = { \"probe\", \"set \", \"pulse \" }\
5886local function completeRedstone( shell, nIndex, sText, tPreviousText )\
5887 if nIndex == 1 then\
5888 return completeMultipleChoice( sText, tRedstoneOptions )\
5889 elseif nIndex == 2 then\
5890 return completeSide( sText )\
5891 end\
5892end\
5893local tDJOptions = { \"play\", \"play \", \"stop \" }\
5894local function completeDJ( shell, nIndex, sText, tPreviousText )\
5895 if nIndex == 1 then\
5896 return completeMultipleChoice( sText, tDJOptions )\
5897 elseif nIndex == 2 then\
5898 return completePeripheralName( sText )\
5899 end\
5900end\
5901local tPastebinOptions = { \"put \", \"get \", \"run \" }\
5902local function completePastebin( shell, nIndex, sText, tPreviousText )\
5903 if nIndex == 1 then\
5904 return completeMultipleChoice( sText, tPastebinOptions )\
5905 elseif nIndex == 2 then\
5906 if tPreviousText[2] == \"put\" then\
5907 return fs.complete( sText, shell.dir(), true, false )\
5908 end\
5909 end\
5910end\
5911local tChatOptions = { \"host \", \"join \" }\
5912local function completeChat( shell, nIndex, sText, tPreviousText )\
5913 if nIndex == 1 then\
5914 return completeMultipleChoice( sText, tChatOptions )\
5915 end\
5916end\
5917local function completeSet( shell, nIndex, sText, tPreviousText )\
5918 if nIndex == 1 then\
5919 return completeMultipleChoice( sText, settings.getNames(), true )\
5920 end\
5921end\
5922local tCommands\
5923if commands then\
5924 tCommands = commands.list()\
5925end\
5926local function completeExec( shell, nIndex, sText, tPreviousText )\
5927 if nIndex == 1 and commands then\
5928 return completeMultipleChoice( sText, tCommands, true )\
5929 end\
5930end\
5931shell.setCompletionFunction( \"rom/programs/alias.lua\", completeAlias )\
5932shell.setCompletionFunction( \"rom/programs/cd.lua\", completeDir )\
5933shell.setCompletionFunction( \"rom/programs/copy.lua\", completeEitherEither )\
5934shell.setCompletionFunction( \"rom/programs/delete.lua\", completeEither )\
5935shell.setCompletionFunction( \"rom/programs/drive.lua\", completeDir )\
5936shell.setCompletionFunction( \"rom/programs/edit.lua\", completeFile )\
5937shell.setCompletionFunction( \"rom/programs/eject.lua\", completePeripheral )\
5938shell.setCompletionFunction( \"rom/programs/gps.lua\", completeGPS )\
5939shell.setCompletionFunction( \"rom/programs/help.lua\", completeHelp )\
5940shell.setCompletionFunction( \"rom/programs/id.lua\", completePeripheral )\
5941shell.setCompletionFunction( \"rom/programs/label.lua\", completeLabel )\
5942shell.setCompletionFunction( \"rom/programs/list.lua\", completeDir )\
5943shell.setCompletionFunction( \"rom/programs/mkdir.lua\", completeFile )\
5944shell.setCompletionFunction( \"rom/programs/monitor.lua\", completeMonitor )\
5945shell.setCompletionFunction( \"rom/programs/move.lua\", completeEitherEither )\
5946shell.setCompletionFunction( \"rom/programs/redstone.lua\", completeRedstone )\
5947shell.setCompletionFunction( \"rom/programs/rename.lua\", completeEitherEither )\
5948shell.setCompletionFunction( \"rom/programs/shell.lua\", completeProgram )\
5949shell.setCompletionFunction( \"rom/programs/type.lua\", completeEither )\
5950shell.setCompletionFunction( \"rom/programs/set.lua\", completeSet )\
5951shell.setCompletionFunction( \"rom/programs/advanced/bg.lua\", completeProgram )\
5952shell.setCompletionFunction( \"rom/programs/advanced/fg.lua\", completeProgram )\
5953shell.setCompletionFunction( \"rom/programs/fun/dj.lua\", completeDJ )\
5954shell.setCompletionFunction( \"rom/programs/fun/advanced/paint.lua\", completeFile )\
5955shell.setCompletionFunction( \"rom/programs/http/pastebin.lua\", completePastebin )\
5956shell.setCompletionFunction( \"rom/programs/rednet/chat.lua\", completeChat )\
5957shell.setCompletionFunction( \"rom/programs/command/exec.lua\", completeExec )\
5958\
5959if turtle then\
5960 local tGoOptions = { \"left\", \"right\", \"forward\", \"back\", \"down\", \"up\" }\
5961 local function completeGo( shell, nIndex, sText )\
5962 return completeMultipleChoice( sText, tGoOptions, true)\
5963 end\
5964 local tTurnOptions = { \"left\", \"right\" }\
5965 local function completeTurn( shell, nIndex, sText )\
5966 return completeMultipleChoice( sText, tTurnOptions, true )\
5967 end\
5968 local tEquipOptions = { \"left\", \"right\" }\
5969 local function completeEquip( shell, nIndex, sText )\
5970 if nIndex == 2 then\
5971 return completeMultipleChoice( sText, tEquipOptions )\
5972 end\
5973 end\
5974 local function completeUnequip( shell, nIndex, sText )\
5975 if nIndex == 1 then\
5976 return completeMultipleChoice( sText, tEquipOptions )\
5977 end\
5978 end\
5979 shell.setCompletionFunction( \"rom/programs/turtle/go.lua\", completeGo )\
5980 shell.setCompletionFunction( \"rom/programs/turtle/turn.lua\", completeTurn )\
5981 shell.setCompletionFunction( \"rom/programs/turtle/equip.lua\", completeEquip )\
5982 shell.setCompletionFunction( \"rom/programs/turtle/unequip.lua\", completeUnequip )\
5983end\
5984\
5985\
5986-- Run autorun files\
5987if fs.exists( \"/rom/autorun\" ) and fs.isDir( \"/rom/autorun\" ) then\
5988 local tFiles = fs.list( \"/rom/autorun\" )\
5989 table.sort( tFiles )\
5990 for n, sFile in ipairs( tFiles ) do\
5991 if string.sub( sFile, 1, 1 ) ~= \".\" then\
5992 local sPath = \"/rom/autorun/\"..sFile\
5993 if not fs.isDir( sPath ) then\
5994 shell.run( sPath )\
5995 end\
5996 end\
5997 end\
5998end\
5999\
6000local function findStartups( sBaseDir )\
6001 local tStartups = nil\
6002 local sBasePath = \"/\" .. fs.combine( sBaseDir, \"startup\" )\
6003 local sStartupNode = shell.resolveProgram( sBasePath )\
6004 if sStartupNode then\
6005 tStartups = { sStartupNode }\
6006 end\
6007 -- It's possible that there is a startup directory and a startup.lua file, so this has to be\
6008 -- executed even if a file has already been found.\
6009 if fs.isDir( sBasePath ) then\
6010 if tStartups == nil then\
6011 tStartups = {}\
6012 end\
6013 for _,v in pairs( fs.list( sBasePath ) ) do\
6014 local sPath = \"/\" .. fs.combine( sBasePath, v )\
6015 if not fs.isDir( sPath ) then\
6016 tStartups[ #tStartups + 1 ] = sPath\
6017 end\
6018 end\
6019 end\
6020 return tStartups\
6021end\
6022\
6023-- Run the user created startup, either from disk drives or the root\
6024local tUserStartups = nil\
6025if settings.get( \"shell.allow_startup\" ) then\
6026 tUserStartups = findStartups( \"/\" )\
6027end\
6028if settings.get( \"shell.allow_disk_startup\" ) then\
6029 for n,sName in pairs( peripheral.getNames() ) do\
6030 if disk.isPresent( sName ) and disk.hasData( sName ) then\
6031 local startups = findStartups( disk.getMountPath( sName ) )\
6032 if startups then\
6033 tUserStartups = startups\
6034 break\
6035 end\
6036 end\
6037 end\
6038end\
6039if tUserStartups then\
6040 for _,v in pairs( tUserStartups ) do\
6041 shell.run( v )\
6042 end\
6043end",
6044 [ "programs/type.lua" ] = "\
6045local tArgs = { ... }\
6046if #tArgs < 1 then\
6047 print( \"Usage: type <path>\" )\
6048 return\
6049end\
6050\
6051local sPath = shell.resolve( tArgs[1] )\
6052if fs.exists( sPath ) then\
6053 if fs.isDir( sPath ) then\
6054 print( \"directory\" )\
6055 else\
6056 print( \"file\" )\
6057 end\
6058else\
6059 print( \"No such path\" )\
6060end",
6061 [ "help/set.txt" ] = "The set program can be used to inspect and change system settings.\
6062\
6063Usage:\
6064\"set\" will print all the system settings and their values\
6065\"set foo\" will print the value of the system setting \"foo\"\
6066\"set foo bar\" will set the value of the system setting \"foo\" to \"bar\"",
6067 [ "programs/turtle/unequip.lua" ] = "\
6068local tArgs = { ... }\
6069local function printUsage()\
6070 print( \"Usage: unequip <side>\" )\
6071end\
6072\
6073if #tArgs ~= 1 then\
6074 printUsage()\
6075 return\
6076end\
6077\
6078local function unequip( fnEquipFunction )\
6079 for nSlot=1,16 do\
6080 local nOldCount = turtle.getItemCount( nSlot )\
6081 if nOldCount == 0 then\
6082 turtle.select( nSlot )\
6083 if fnEquipFunction() then\
6084 local nNewCount = turtle.getItemCount( nSlot )\
6085 if nNewCount > 0 then\
6086 print( \"Item unequipped\" )\
6087 return\
6088 else\
6089 print( \"Nothing to unequip\" )\
6090 return\
6091 end\
6092 end\
6093 end\
6094 end\
6095 print( \"No space to unequip item\" )\
6096end\
6097\
6098local sSide = tArgs[1]\
6099if sSide == \"left\" then\
6100 unequip( turtle.equipLeft )\
6101elseif sSide == \"right\" then\
6102 unequip( turtle.equipRight )\
6103else\
6104 printUsage()\
6105 return\
6106end",
6107 [ "help/intro.txt" ] = "Welcome to CraftOS!\
6108Type \"programs\" to see the programs you can run.\
6109Type \"help <program>\" to see help for a specific program.\
6110Type \"help programming\" to learn about programming.\
6111Type \"help whatsnew\" to find out about new features.\
6112Type \"help credits\" to learn who made all this.\
6113Type \"help index\" to see all help topics.",
6114 [ "help/gps.txt" ] = "gps can be used to host a GPS server, or to determine a position using trilateration.\
6115Type \"help gpsapi\" for help using GPS functions in lua programs.\
6116\
6117ex:\
6118\"gps locate\" will connect to nearby GPS servers, and try to determine the position of the computer or turtle.\
6119\"gps host\" will try to determine the position, and host a GPS server if successful.\
6120\"gps host 10 20 30\" will host a GPS server, using the manually entered position 10,20,30. \
6121\
6122Take care when manually entering host positions. If the positions entered into multiple GPS hosts\
6123are not consistent, the results of locate calls will be incorrect.",
6124 [ "help/peripheral.txt" ] = "The peripheral API is for interacting with external peripheral devices. Type \"help peripherals\" to learn about the peripherals available.\
6125\
6126Functions in the peripheral API:\
6127peripheral.getNames()\
6128peripheral.isPresent( name )\
6129peripheral.getType( name )\
6130peripheral.getMethods( name )\
6131peripheral.call( name, methodName, param1, param2, etc )\
6132peripheral.wrap( name )\
6133peripheral.find( type, [fnFilter] )\
6134\
6135Events fired by the peripheral API:\
6136\"peripheral\" when a new peripheral is attached. Argument is the name.\
6137\"peripheral_detach\" when a peripheral is removed. Argument is the name.\
6138Type \"help events\" to learn about the event system.",
6139 [ "help/paintutils.txt" ] = "Functions in the Paint Utilities API:\
6140paintutils.drawPixel( x, y, colour )\
6141paintutils.drawLine( startX, startY, endX, endY, colour )\
6142paintutils.drawBox( startX, startY, endX, endY, colour )\
6143paintutils.drawFilledBox( startX, startY, endX, endY, colour )\
6144paintutils.loadImage( path )\
6145paintutils.drawImage( image, x, y )",
6146 [ "programs/turtle/go.lua" ] = "local tArgs = { ... }\
6147if #tArgs < 1 then\
6148 print( \"Usage: go <direction> <distance>\" )\
6149 return\
6150end\
6151\
6152local tHandlers = {\
6153 [\"fd\"] = turtle.forward,\
6154 [\"forward\"] = turtle.forward,\
6155 [\"forwards\"] = turtle.forward,\
6156 [\"bk\"] = turtle.back,\
6157 [\"back\"] = turtle.back,\
6158 [\"up\"] = turtle.up,\
6159 [\"dn\"] = turtle.down,\
6160 [\"down\"] = turtle.down,\
6161 [\"lt\"] = turtle.turnLeft,\
6162 [\"left\"] = turtle.turnLeft,\
6163 [\"rt\"] = turtle.turnRight,\
6164 [\"right\"] = turtle.turnRight,\
6165}\
6166\
6167local nArg = 1\
6168while nArg <= #tArgs do\
6169 local sDirection = tArgs[nArg]\
6170 local nDistance = 1\
6171 if nArg < #tArgs then\
6172 local num = tonumber( tArgs[nArg + 1] )\
6173 if num then\
6174 nDistance = num\
6175 nArg = nArg + 1\
6176 end\
6177 end\
6178 nArg = nArg + 1\
6179\
6180 local fnHandler = tHandlers[string.lower(sDirection)]\
6181 if fnHandler then\
6182 while nDistance > 0 do\
6183 if fnHandler() then\
6184 nDistance = nDistance - 1\
6185 elseif turtle.getFuelLevel() == 0 then\
6186 print( \"Out of fuel\" )\
6187 return\
6188 else\
6189 sleep(0.5)\
6190 end\
6191 end\
6192 else\
6193 print( \"No such direction: \"..sDirection )\
6194 print( \"Try: forward, back, up, down\" )\
6195 return\
6196 end\
6197\
6198end",
6199 [ "programs/turtle/excavate.lua" ] = "\
6200local tArgs = { ... }\
6201if #tArgs ~= 1 then\
6202 print( \"Usage: excavate <diameter>\" )\
6203 return\
6204end\
6205\
6206-- Mine in a quarry pattern until we hit something we can't dig\
6207local size = tonumber( tArgs[1] )\
6208if size < 1 then\
6209 print( \"Excavate diameter must be positive\" )\
6210 return\
6211end\
6212\
6213local depth = 0\
6214local unloaded = 0\
6215local collected = 0\
6216\
6217local xPos,zPos = 0,0\
6218local xDir,zDir = 0,1\
6219\
6220local goTo -- Filled in further down\
6221local refuel -- Filled in further down\
6222\
6223local function unload( _bKeepOneFuelStack )\
6224 print( \"Unloading items...\" )\
6225 for n=1,16 do\
6226 local nCount = turtle.getItemCount(n)\
6227 if nCount > 0 then\
6228 turtle.select(n)\
6229 local bDrop = true\
6230 if _bKeepOneFuelStack and turtle.refuel(0) then\
6231 bDrop = false\
6232 _bKeepOneFuelStack = false\
6233 end\
6234 if bDrop then\
6235 turtle.drop()\
6236 unloaded = unloaded + nCount\
6237 end\
6238 end\
6239 end\
6240 collected = 0\
6241 turtle.select(1)\
6242end\
6243\
6244local function returnSupplies()\
6245 local x,y,z,xd,zd = xPos,depth,zPos,xDir,zDir\
6246 print( \"Returning to surface...\" )\
6247 goTo( 0,0,0,0,-1 )\
6248\
6249 local fuelNeeded = 2*(x+y+z) + 1\
6250 if not refuel( fuelNeeded ) then\
6251 unload( true )\
6252 print( \"Waiting for fuel\" )\
6253 while not refuel( fuelNeeded ) do\
6254 os.pullEvent( \"turtle_inventory\" )\
6255 end\
6256 else\
6257 unload( true )\
6258 end\
6259\
6260 print( \"Resuming mining...\" )\
6261 goTo( x,y,z,xd,zd )\
6262end\
6263\
6264local function collect()\
6265 local bFull = true\
6266 local nTotalItems = 0\
6267 for n=1,16 do\
6268 local nCount = turtle.getItemCount(n)\
6269 if nCount == 0 then\
6270 bFull = false\
6271 end\
6272 nTotalItems = nTotalItems + nCount\
6273 end\
6274\
6275 if nTotalItems > collected then\
6276 collected = nTotalItems\
6277 if math.fmod(collected + unloaded, 50) == 0 then\
6278 print( \"Mined \"..(collected + unloaded)..\" items.\" )\
6279 end\
6280 end\
6281\
6282 if bFull then\
6283 print( \"No empty slots left.\" )\
6284 return false\
6285 end\
6286 return true\
6287end\
6288\
6289function refuel( ammount )\
6290 local fuelLevel = turtle.getFuelLevel()\
6291 if fuelLevel == \"unlimited\" then\
6292 return true\
6293 end\
6294\
6295 local needed = ammount or (xPos + zPos + depth + 2)\
6296 if turtle.getFuelLevel() < needed then\
6297 local fueled = false\
6298 for n=1,16 do\
6299 if turtle.getItemCount(n) > 0 then\
6300 turtle.select(n)\
6301 if turtle.refuel(1) then\
6302 while turtle.getItemCount(n) > 0 and turtle.getFuelLevel() < needed do\
6303 turtle.refuel(1)\
6304 end\
6305 if turtle.getFuelLevel() >= needed then\
6306 turtle.select(1)\
6307 return true\
6308 end\
6309 end\
6310 end\
6311 end\
6312 turtle.select(1)\
6313 return false\
6314 end\
6315\
6316 return true\
6317end\
6318\
6319local function tryForwards()\
6320 if not refuel() then\
6321 print( \"Not enough Fuel\" )\
6322 returnSupplies()\
6323 end\
6324\
6325 while not turtle.forward() do\
6326 if turtle.detect() then\
6327 if turtle.dig() then\
6328 if not collect() then\
6329 returnSupplies()\
6330 end\
6331 else\
6332 return false\
6333 end\
6334 elseif turtle.attack() then\
6335 if not collect() then\
6336 returnSupplies()\
6337 end\
6338 else\
6339 sleep( 0.5 )\
6340 end\
6341 end\
6342\
6343 xPos = xPos + xDir\
6344 zPos = zPos + zDir\
6345 return true\
6346end\
6347\
6348local function tryDown()\
6349 if not refuel() then\
6350 print( \"Not enough Fuel\" )\
6351 returnSupplies()\
6352 end\
6353\
6354 while not turtle.down() do\
6355 if turtle.detectDown() then\
6356 if turtle.digDown() then\
6357 if not collect() then\
6358 returnSupplies()\
6359 end\
6360 else\
6361 return false\
6362 end\
6363 elseif turtle.attackDown() then\
6364 if not collect() then\
6365 returnSupplies()\
6366 end\
6367 else\
6368 sleep( 0.5 )\
6369 end\
6370 end\
6371\
6372 depth = depth + 1\
6373 if math.fmod( depth, 10 ) == 0 then\
6374 print( \"Descended \"..depth..\" metres.\" )\
6375 end\
6376\
6377 return true\
6378end\
6379\
6380local function turnLeft()\
6381 turtle.turnLeft()\
6382 xDir, zDir = -zDir, xDir\
6383end\
6384\
6385local function turnRight()\
6386 turtle.turnRight()\
6387 xDir, zDir = zDir, -xDir\
6388end\
6389\
6390function goTo( x, y, z, xd, zd )\
6391 while depth > y do\
6392 if turtle.up() then\
6393 depth = depth - 1\
6394 elseif turtle.digUp() or turtle.attackUp() then\
6395 collect()\
6396 else\
6397 sleep( 0.5 )\
6398 end\
6399 end\
6400\
6401 if xPos > x then\
6402 while xDir ~= -1 do\
6403 turnLeft()\
6404 end\
6405 while xPos > x do\
6406 if turtle.forward() then\
6407 xPos = xPos - 1\
6408 elseif turtle.dig() or turtle.attack() then\
6409 collect()\
6410 else\
6411 sleep( 0.5 )\
6412 end\
6413 end\
6414 elseif xPos < x then\
6415 while xDir ~= 1 do\
6416 turnLeft()\
6417 end\
6418 while xPos < x do\
6419 if turtle.forward() then\
6420 xPos = xPos + 1\
6421 elseif turtle.dig() or turtle.attack() then\
6422 collect()\
6423 else\
6424 sleep( 0.5 )\
6425 end\
6426 end\
6427 end\
6428\
6429 if zPos > z then\
6430 while zDir ~= -1 do\
6431 turnLeft()\
6432 end\
6433 while zPos > z do\
6434 if turtle.forward() then\
6435 zPos = zPos - 1\
6436 elseif turtle.dig() or turtle.attack() then\
6437 collect()\
6438 else\
6439 sleep( 0.5 )\
6440 end\
6441 end\
6442 elseif zPos < z then\
6443 while zDir ~= 1 do\
6444 turnLeft()\
6445 end\
6446 while zPos < z do\
6447 if turtle.forward() then\
6448 zPos = zPos + 1\
6449 elseif turtle.dig() or turtle.attack() then\
6450 collect()\
6451 else\
6452 sleep( 0.5 )\
6453 end\
6454 end\
6455 end\
6456\
6457 while depth < y do\
6458 if turtle.down() then\
6459 depth = depth + 1\
6460 elseif turtle.digDown() or turtle.attackDown() then\
6461 collect()\
6462 else\
6463 sleep( 0.5 )\
6464 end\
6465 end\
6466\
6467 while zDir ~= zd or xDir ~= xd do\
6468 turnLeft()\
6469 end\
6470end\
6471\
6472if not refuel() then\
6473 print( \"Out of Fuel\" )\
6474 return\
6475end\
6476\
6477print( \"Excavating...\" )\
6478\
6479local reseal = false\
6480turtle.select(1)\
6481if turtle.digDown() then\
6482 reseal = true\
6483end\
6484\
6485local alternate = 0\
6486local done = false\
6487while not done do\
6488 for n=1,size do\
6489 for m=1,size-1 do\
6490 if not tryForwards() then\
6491 done = true\
6492 break\
6493 end\
6494 end\
6495 if done then\
6496 break\
6497 end\
6498 if n<size then\
6499 if math.fmod(n + alternate,2) == 0 then\
6500 turnLeft()\
6501 if not tryForwards() then\
6502 done = true\
6503 break\
6504 end\
6505 turnLeft()\
6506 else\
6507 turnRight()\
6508 if not tryForwards() then\
6509 done = true\
6510 break\
6511 end\
6512 turnRight()\
6513 end\
6514 end\
6515 end\
6516 if done then\
6517 break\
6518 end\
6519\
6520 if size > 1 then\
6521 if math.fmod(size,2) == 0 then\
6522 turnRight()\
6523 else\
6524 if alternate == 0 then\
6525 turnLeft()\
6526 else\
6527 turnRight()\
6528 end\
6529 alternate = 1 - alternate\
6530 end\
6531 end\
6532\
6533 if not tryDown() then\
6534 done = true\
6535 break\
6536 end\
6537end\
6538\
6539print( \"Returning to surface...\" )\
6540\
6541-- Return to where we started\
6542goTo( 0,0,0,0,-1 )\
6543unload( false )\
6544goTo( 0,0,0,0,1 )\
6545\
6546-- Seal the hole\
6547if reseal then\
6548 turtle.placeDown()\
6549end\
6550\
6551print( \"Mined \"..(collected + unloaded)..\" items total.\" )",
6552 [ "programs/turtle/equip.lua" ] = "\
6553local tArgs = { ... }\
6554local function printUsage()\
6555 print( \"Usage: equip <slot> <side>\" )\
6556end\
6557\
6558if #tArgs ~= 2 then\
6559 printUsage()\
6560 return\
6561end\
6562\
6563local function equip( nSlot, fnEquipFunction )\
6564 turtle.select( nSlot )\
6565 local nOldCount = turtle.getItemCount( nSlot )\
6566 if nOldCount == 0 then\
6567 print( \"Nothing to equip\" )\
6568 elseif fnEquipFunction() then\
6569 local nNewCount = turtle.getItemCount( nSlot )\
6570 if nNewCount > 0 then\
6571 print( \"Items swapped\" )\
6572 else\
6573 print( \"Item equipped\" )\
6574 end\
6575 else\
6576 print( \"Item not equippable\" )\
6577 end\
6578end\
6579\
6580local nSlot = tonumber( tArgs[1] )\
6581local sSide = tArgs[2]\
6582if sSide == \"left\" then\
6583 equip( nSlot, turtle.equipLeft )\
6584elseif sSide == \"right\" then\
6585 equip( nSlot, turtle.equipRight )\
6586else\
6587 printUsage()\
6588 return\
6589end",
6590 [ "help/whatsnew.txt" ] = "New Features in ComputerCraft 1.80:\
6591\
6592* Added .getResponseHeaders() to HTTP responses.\
6593* Return a HTTP response when a HTTP error occurs.\
6594* Added a GUI to change ComputerCraft config options.\
6595* os.time() and os.day() now accept parameters to give the real world time.\
6596* Added os.epoch()\
6597* Monitor text now glows in the dark.\
6598* Added a \"Pocket Computer upgrade API\" so mod developers can add their own pocket upgrades.\
6599* Added pocket.equipBack()/pocket.unequipBack() to add/remove pocket upgrades.\
6600* Added term.setPaletteColor()/term.getPaletteColor() to change/check colors\
6601* Added colors.rgb8()/colours.rgb8() \
6602* Performance improvements to fs.find\
6603* Requires the player to be interacting with the computer when typing\
6604* Disk labels are limited to 32 characters\
6605* Labels can now only include characters within the printable range ( to ~)\
6606* Various model improvements\
6607* There is now a configurable file descriptor limit\
6608* Threads are now daemon threads\
6609* Termination signals are now sent unless the computer is off\
6610* Fixed compilation errors\
6611* Now handles tile entity changes\
6612* GPS coordinates now have to be numbers\
6613* Turtle upgrades now act as tools and peripherals\
6614* The Filesystem.list result is now sorted\
6615* The number of values to unpack can now be manually specified\
6616* Small terminal & monitor rendering improvements\
6617* General improvements to the documentation\
6618* Redstone inputs are no longer reset when adding peripherals\
6619* Turtles now use tinting\
6620* shell.resolveProgram now picks up on *.lua files\
6621* Fixed a handful of bugs in ComputerCraft\
6622* Added speaker block, turtle upgrade, pocket upgrade, and peripheral api\
6623* Startup can now be a directory containing multiple startup files\
6624* Added .getLabel to the computer peripheral\
6625\
6626Type \"help changelog\" to see the full version history.",
6627 [ "help/shutdown.txt" ] = "shutdown will turn off the computer.",
6628 [ "apis/settings.lua" ] = "\
6629local tSettings = {}\
6630\
6631function set( sName, value )\
6632 if type( sName ) ~= \"string\" then error( \"bad argument #1 (expected string, got \" .. type( sName ) .. \")\", 2 ) end\
6633\
6634 local sValueTy = type(value)\
6635 if sValueTy ~= \"number\" and sValueTy ~= \"string\" and sValueTy ~= \"boolean\" and sValueTy ~= \"table\" then\
6636 error( \"bad argument #2 (expected value, got \" .. sValueTy .. \")\", 2 )\
6637 end\
6638 if sValueTy == \"table\" then\
6639 -- Ensure value is serializeable\
6640 value = textutils.unserialize( textutils.serialize(value) )\
6641 end\
6642 tSettings[ sName ] = value\
6643end\
6644\
6645local copy\
6646function copy( value )\
6647 if type(value) == \"table\" then\
6648 local result = {}\
6649 for k,v in pairs(value) do\
6650 result[k] = copy(v)\
6651 end\
6652 return result\
6653 else\
6654 return value\
6655 end\
6656end\
6657\
6658function get( sName, default )\
6659 if type(sName) ~= \"string\" then\
6660 error( \"bad argument #1 (expected string, got \" .. type( sName ) .. \")\", 2 )\
6661 end\
6662 local result = tSettings[ sName ]\
6663 if result ~= nil then\
6664 return copy(result)\
6665 else\
6666 return default\
6667 end\
6668end\
6669\
6670function unset( sName )\
6671 if type(sName) ~= \"string\" then\
6672 error( \"bad argument #1 (expected string, got \" .. type( sName ) .. \")\", 2 )\
6673 end\
6674 tSettings[ sName ] = nil\
6675end\
6676\
6677function clear()\
6678 tSettings = {}\
6679end\
6680\
6681function getNames()\
6682 local result = {}\
6683 for k,v in pairs( tSettings ) do\
6684 result[ #result + 1 ] = k\
6685 end\
6686 table.sort(result)\
6687 return result\
6688end\
6689\
6690function load( sPath )\
6691 if type(sPath) ~= \"string\" then\
6692 error( \"bad argument #1 (expected string, got \" .. type( sPath ) .. \")\", 2 )\
6693 end\
6694 local file = fs.open( sPath, \"r\" )\
6695 if not file then\
6696 return false\
6697 end\
6698\
6699 local sText = file.readAll()\
6700 file.close()\
6701\
6702 local tFile = textutils.unserialize( sText )\
6703 if type(tFile) ~= \"table\" then\
6704 return false\
6705 end\
6706\
6707 for k,v in pairs(tFile) do\
6708 if type(k) == \"string\" and\
6709 (type(v) == \"string\" or type(v) == \"number\" or type(v) == \"boolean\" or type(v) == \"table\") then\
6710 set( k, v )\
6711 end\
6712 end\
6713\
6714 return true\
6715end\
6716\
6717function save( sPath )\
6718 if type(sPath) ~= \"string\" then\
6719 error( \"bad argument #1 (expected string, got \" .. type( sPath ) .. \")\", 2 )\
6720 end\
6721 local file = fs.open( sPath, \"w\" )\
6722 if not file then\
6723 return false\
6724 end\
6725\
6726 file.write( textutils.serialize( tSettings ) )\
6727 file.close()\
6728\
6729 return true\
6730end",
6731 [ "help/adventure.txt" ] = "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\"",
6732 [ "help/term.txt" ] = "Functions in the Terminal API:\
6733term.write( text )\
6734term.blit( text, textColor, backgroundColor )\
6735term.clear()\
6736term.clearLine()\
6737term.getCursorPos()\
6738term.setCursorPos( x, y )\
6739term.setCursorBlink( blink )\
6740term.isColor()\
6741term.setTextColor( color )\
6742term.setBackgroundColor( color )\
6743term.getTextColor()\
6744term.getBackgroundColor()\
6745term.getSize()\
6746term.scroll( n )\
6747term.redirect( object )\
6748term.current()\
6749term.setPaletteColor( color, r, g, b )\
6750term.getPaletteColor( color )\
6751\
6752Events emitted by the terminals:\
6753\"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.",
6754 [ "help/exec.txt" ] = "On a Command Computer, \"exec\" will execute a command as if entered on a command block. Use \"commands\" to list all the available commands.\
6755\
6756ex:\
6757\"exec say Hello World\"\
6758\"exec setblock ~0 ~1 ~0 minecraft:dirt\"\
6759\
6760Type \"help commandsapi\" for help using commands in lua programs.",
6761 [ "programs/turtle/dance.lua" ] = "\
6762local tMoves = {\
6763 function()\
6764 turtle.up()\
6765 turtle.down()\
6766 end,\
6767 function()\
6768 turtle.up()\
6769 turtle.turnLeft()\
6770 turtle.turnLeft()\
6771 turtle.turnLeft()\
6772 turtle.turnLeft()\
6773 turtle.down()\
6774 end,\
6775 function()\
6776 turtle.up()\
6777 turtle.turnRight()\
6778 turtle.turnRight()\
6779 turtle.turnRight()\
6780 turtle.turnRight()\
6781 turtle.down()\
6782 end,\
6783 function()\
6784 turtle.turnLeft()\
6785 turtle.turnLeft()\
6786 turtle.turnLeft()\
6787 turtle.turnLeft()\
6788 end,\
6789 function()\
6790 turtle.turnRight()\
6791 turtle.turnRight()\
6792 turtle.turnRight()\
6793 turtle.turnRight()\
6794 end,\
6795 function()\
6796 turtle.turnLeft()\
6797 turtle.back()\
6798 turtle.back()\
6799 turtle.turnRight()\
6800 turtle.turnRight()\
6801 turtle.back()\
6802 turtle.back()\
6803 turtle.turnLeft()\
6804 end,\
6805 function()\
6806 turtle.turnRight()\
6807 turtle.back()\
6808 turtle.back()\
6809 turtle.turnLeft()\
6810 turtle.turnLeft()\
6811 turtle.back()\
6812 turtle.back()\
6813 turtle.turnRight()\
6814 end,\
6815 function()\
6816 turtle.back()\
6817 turtle.turnLeft()\
6818 turtle.back()\
6819 turtle.turnLeft()\
6820 turtle.back()\
6821 turtle.turnLeft()\
6822 turtle.back()\
6823 turtle.turnLeft()\
6824 end,\
6825 function()\
6826 turtle.back()\
6827 turtle.turnRight()\
6828 turtle.back()\
6829 turtle.turnRight()\
6830 turtle.back()\
6831 turtle.turnRight()\
6832 turtle.back()\
6833 turtle.turnRight()\
6834 end,\
6835}\
6836\
6837textutils.slowWrite( \"Preparing to get down.\" )\
6838textutils.slowPrint( \"..\", 0.75 )\
6839\
6840local sAudio = nil\
6841for n,sName in pairs( peripheral.getNames() ) do\
6842 if disk.hasAudio( sName ) then\
6843 disk.playAudio( sName )\
6844 print( \"Jamming to \"..disk.getAudioTitle( sName ) )\
6845 sAudio = sName\
6846 break\
6847 end\
6848end\
6849\
6850print( \"Press any key to stop the groove\" )\
6851\
6852parallel.waitForAny(\
6853 function()\
6854 while not bEnd do\
6855 local event, key = os.pullEvent(\"key\")\
6856 if key ~= keys.escape then\
6857 return\
6858 end\
6859 end\
6860 end,\
6861 function()\
6862 while true do\
6863 local fnMove = tMoves[math.random(1,#tMoves)]\
6864 fnMove()\
6865 end\
6866 end\
6867)\
6868\
6869if sAudio then\
6870 disk.stopAudio( sAudio )\
6871end",
6872 [ "apis/rednet.lua" ] = "\
6873CHANNEL_BROADCAST = 65535\
6874CHANNEL_REPEAT = 65533\
6875\
6876local tReceivedMessages = {}\
6877local tReceivedMessageTimeouts = {}\
6878local tHostnames = {}\
6879\
6880function open( sModem )\
6881 if type( sModem ) ~= \"string\" then\
6882 error( \"bad argument #1 (expected string, got \" .. type( sModem ) .. \")\", 2 )\
6883 end\
6884 if peripheral.getType( sModem ) ~= \"modem\" then\
6885 error( \"No such modem: \"..sModem, 2 )\
6886 end\
6887 peripheral.call( sModem, \"open\", os.getComputerID() )\
6888 peripheral.call( sModem, \"open\", CHANNEL_BROADCAST )\
6889end\
6890\
6891function close( sModem )\
6892 if sModem then\
6893 -- Close a specific modem\
6894 if type( sModem ) ~= \"string\" then\
6895 error( \"bad argument #1 (expected string, got \" .. type( sModem ) .. \")\", 2 )\
6896 end\
6897 if peripheral.getType( sModem ) ~= \"modem\" then\
6898 error( \"No such modem: \"..sModem, 2 )\
6899 end\
6900 peripheral.call( sModem, \"close\", os.getComputerID() )\
6901 peripheral.call( sModem, \"close\", CHANNEL_BROADCAST )\
6902 else\
6903 -- Close all modems\
6904 for n,sModem in ipairs( peripheral.getNames() ) do\
6905 if isOpen( sModem ) then\
6906 close( sModem )\
6907 end\
6908 end\
6909 end\
6910end\
6911\
6912function isOpen( sModem )\
6913 if sModem then\
6914 -- Check if a specific modem is open\
6915 if type( sModem ) ~= \"string\" then\
6916 error( \"bad argument #1 (expected string, got \" .. type( sModem ) .. \")\", 2 )\
6917 end\
6918 if peripheral.getType( sModem ) == \"modem\" then\
6919 return peripheral.call( sModem, \"isOpen\", os.getComputerID() ) and peripheral.call( sModem, \"isOpen\", CHANNEL_BROADCAST )\
6920 end\
6921 else\
6922 -- Check if any modem is open\
6923 for n,sModem in ipairs( peripheral.getNames() ) do\
6924 if isOpen( sModem ) then\
6925 return true\
6926 end\
6927 end\
6928 end\
6929 return false\
6930end\
6931\
6932function send( nRecipient, message, sProtocol )\
6933 if type( nRecipient ) ~= \"number\" then\
6934 error( \"bad argument #1 (expected number, got \" .. type( nRecipient ) .. \")\", 2 )\
6935 end\
6936 if sProtocol ~= nil and type( sProtocol ) ~= \"string\" then\
6937 error( \"bad argument #3 (expected string, got \" .. type( sProtocol ) .. \")\", 2 )\
6938 end\
6939 -- Generate a (probably) unique message ID\
6940 -- We could do other things to guarantee uniqueness, but we really don't need to\
6941 -- Store it to ensure we don't get our own messages back\
6942 local nMessageID = math.random( 1, 2147483647 )\
6943 tReceivedMessages[ nMessageID ] = true\
6944 tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = nMessageID\
6945\
6946 -- Create the message\
6947 local nReplyChannel = os.getComputerID()\
6948 local tMessage = {\
6949 nMessageID = nMessageID,\
6950 nRecipient = nRecipient,\
6951 message = message,\
6952 sProtocol = sProtocol,\
6953 }\
6954\
6955 if nRecipient == os.getComputerID() then\
6956 -- Loopback to ourselves\
6957 os.queueEvent( \"rednet_message\", nReplyChannel, message, sProtocol )\
6958\
6959 else\
6960 -- Send on all open modems, to the target and to repeaters\
6961 local sent = false\
6962 for n,sModem in ipairs( peripheral.getNames() ) do\
6963 if isOpen( sModem ) then\
6964 peripheral.call( sModem, \"transmit\", nRecipient, nReplyChannel, tMessage );\
6965 peripheral.call( sModem, \"transmit\", CHANNEL_REPEAT, nReplyChannel, tMessage );\
6966 sent = true\
6967 end\
6968 end\
6969 end\
6970end\
6971\
6972function broadcast( message, sProtocol )\
6973 if sProtocol ~= nil and type( sProtocol ) ~= \"string\" then\
6974 error( \"bad argument #2 (expected string, got \" .. type( sProtocol ) .. \")\", 2 )\
6975 end\
6976 send( CHANNEL_BROADCAST, message, sProtocol )\
6977end\
6978\
6979function receive( sProtocolFilter, nTimeout )\
6980 -- The parameters used to be ( nTimeout ), detect this case for backwards compatibility\
6981 if type(sProtocolFilter) == \"number\" and nTimeout == nil then\
6982 sProtocolFilter, nTimeout = nil, sProtocolFilter\
6983 end\
6984 if sProtocolFilter ~= nil and type( sProtocolFilter ) ~= \"string\" then\
6985 error( \"bad argument #1 (expected string, got \" .. type( sProtocolFilter ) .. \")\", 2 )\
6986 end\
6987 if nTimeout ~= nil and type( nTimeout ) ~= \"number\" then\
6988 error( \"bad argument #2 (expected number, got \" .. type( nTimeout ) .. \")\", 2 )\
6989 end\
6990\
6991 -- Start the timer\
6992 local timer = nil\
6993 local sFilter = nil\
6994 if nTimeout then\
6995 timer = os.startTimer( nTimeout )\
6996 sFilter = nil\
6997 else\
6998 sFilter = \"rednet_message\"\
6999 end\
7000\
7001 -- Wait for events\
7002 while true do\
7003 local sEvent, p1, p2, p3 = os.pullEvent( sFilter )\
7004 if sEvent == \"rednet_message\" then\
7005 -- Return the first matching rednet_message\
7006 local nSenderID, message, sProtocol = p1, p2, p3\
7007 if sProtocolFilter == nil or sProtocol == sProtocolFilter then\
7008 return nSenderID, message, sProtocol\
7009 end\
7010 elseif sEvent == \"timer\" then\
7011 -- Return nil if we timeout\
7012 if p1 == timer then\
7013 return nil\
7014 end\
7015 end\
7016 end\
7017end\
7018\
7019function host( sProtocol, sHostname )\
7020 if type( sProtocol ) ~= \"string\" then\
7021 error( \"bad argument #1 (expected string, got \" .. type( sProtocol ) .. \")\", 2 )\
7022 end\
7023 if type( sHostname ) ~= \"string\" then\
7024 error( \"bad argument #2 (expected string, got \" .. type( sHostname ) .. \")\", 2 )\
7025 end\
7026 if sHostname == \"localhost\" then\
7027 error( \"Reserved hostname\", 2 )\
7028 end\
7029 if tHostnames[ sProtocol ] ~= sHostname then\
7030 if lookup( sProtocol, sHostname ) ~= nil then\
7031 error( \"Hostname in use\", 2 )\
7032 end\
7033 tHostnames[ sProtocol ] = sHostname\
7034 end\
7035end\
7036\
7037function unhost( sProtocol )\
7038 if type( sProtocol ) ~= \"string\" then\
7039 error( \"bad argument #1 (expected string, got \" .. type( sProtocol ) .. \")\", 2 )\
7040 end\
7041 tHostnames[ sProtocol ] = nil\
7042end\
7043\
7044function lookup( sProtocol, sHostname )\
7045 if type( sProtocol ) ~= \"string\" then\
7046 error( \"bad argument #1 (expected string, got \" .. type( sProtocol ) .. \")\", 2 )\
7047 end\
7048 if sHostname ~= nil and type( sHostname ) ~= \"string\" then\
7049 error( \"bad argument #2 (expected string, got \" .. type( sHostname ) .. \")\", 2 )\
7050 end\
7051\
7052 -- Build list of host IDs\
7053 local tResults = nil\
7054 if sHostname == nil then\
7055 tResults = {}\
7056 end\
7057\
7058 -- Check localhost first\
7059 if tHostnames[ sProtocol ] then\
7060 if sHostname == nil then\
7061 table.insert( tResults, os.getComputerID() )\
7062 elseif sHostname == \"localhost\" or sHostname == tHostnames[ sProtocol ] then\
7063 return os.getComputerID()\
7064 end\
7065 end\
7066\
7067 if not isOpen() then\
7068 if tResults then\
7069 return table.unpack( tResults )\
7070 end\
7071 return nil\
7072 end\
7073\
7074 -- Broadcast a lookup packet\
7075 broadcast( {\
7076 sType = \"lookup\",\
7077 sProtocol = sProtocol,\
7078 sHostname = sHostname,\
7079 }, \"dns\" )\
7080\
7081 -- Start a timer\
7082 local timer = os.startTimer( 2 )\
7083\
7084 -- Wait for events\
7085 while true do\
7086 local event, p1, p2, p3 = os.pullEvent()\
7087 if event == \"rednet_message\" then\
7088 -- Got a rednet message, check if it's the response to our request\
7089 local nSenderID, tMessage, sMessageProtocol = p1, p2, p3\
7090 if sMessageProtocol == \"dns\" and type(tMessage) == \"table\" and tMessage.sType == \"lookup response\" then\
7091 if tMessage.sProtocol == sProtocol then\
7092 if sHostname == nil then\
7093 table.insert( tResults, nSenderID )\
7094 elseif tMessage.sHostname == sHostname then\
7095 return nSenderID\
7096 end\
7097 end\
7098 end\
7099 else\
7100 -- Got a timer event, check it's the end of our timeout\
7101 if p1 == timer then\
7102 break\
7103 end\
7104 end\
7105 end\
7106 if tResults then\
7107 return table.unpack( tResults )\
7108 end\
7109 return nil\
7110end\
7111\
7112local bRunning = false\
7113function run()\
7114 if bRunning then\
7115 error( \"rednet is already running\", 2 )\
7116 end\
7117 bRunning = true\
7118\
7119 while bRunning do\
7120 local sEvent, p1, p2, p3, p4 = os.pullEventRaw()\
7121 if sEvent == \"modem_message\" then\
7122 -- Got a modem message, process it and add it to the rednet event queue\
7123 local sModem, nChannel, nReplyChannel, tMessage = p1, p2, p3, p4\
7124 if isOpen( sModem ) and ( nChannel == os.getComputerID() or nChannel == CHANNEL_BROADCAST ) then\
7125 if type( tMessage ) == \"table\" and tMessage.nMessageID then\
7126 if not tReceivedMessages[ tMessage.nMessageID ] then\
7127 tReceivedMessages[ tMessage.nMessageID ] = true\
7128 tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = tMessage.nMessageID\
7129 os.queueEvent( \"rednet_message\", nReplyChannel, tMessage.message, tMessage.sProtocol )\
7130 end\
7131 end\
7132 end\
7133\
7134 elseif sEvent == \"rednet_message\" then\
7135 -- Got a rednet message (queued from above), respond to dns lookup\
7136 local nSenderID, tMessage, sProtocol = p1, p2, p3\
7137 if sProtocol == \"dns\" and type(tMessage) == \"table\" and tMessage.sType == \"lookup\" then\
7138 local sHostname = tHostnames[ tMessage.sProtocol ]\
7139 if sHostname ~= nil and (tMessage.sHostname == nil or tMessage.sHostname == sHostname) then\
7140 rednet.send( nSenderID, {\
7141 sType = \"lookup response\",\
7142 sHostname = sHostname,\
7143 sProtocol = tMessage.sProtocol,\
7144 }, \"dns\" )\
7145 end\
7146 end\
7147\
7148 elseif sEvent == \"timer\" then\
7149 -- Got a timer event, use it to clear the event queue\
7150 local nTimer = p1\
7151 local nMessage = tReceivedMessageTimeouts[ nTimer ]\
7152 if nMessage then\
7153 tReceivedMessageTimeouts[ nTimer ] = nil\
7154 tReceivedMessages[ nMessage ] = nil\
7155 end\
7156 end\
7157 end\
7158end",
7159 [ "programs/time.lua" ] = "local nTime = os.time()\
7160local nDay = os.day()\
7161print( \"The time is \"..textutils.formatTime( nTime, false )..\" on Day \"..nDay )",
7162 [ "help/clear.txt" ] = "clear clears the screen.",
7163 [ "programs/shutdown.lua" ] = "if term.isColour() then\
7164 term.setTextColour( colours.yellow )\
7165end\
7166print( \"Goodbye\" )\
7167term.setTextColour( colours.white )\
7168\
7169sleep( 1 )\
7170os.shutdown()",
7171 [ "apis/parallel.lua" ] = "\
7172local function create( ... )\
7173 local tFns = table.pack(...)\
7174 local tCos = {}\
7175 for i = 1, tFns.n, 1 do\
7176 local fn = tFns[i]\
7177 if type( fn ) ~= \"function\" then\
7178 error( \"bad argument #\" .. i .. \" (expected function, got \" .. type( fn ) .. \")\", 3 )\
7179 end\
7180\
7181 tCos[i] = coroutine.create(fn)\
7182 end\
7183\
7184 return tCos\
7185end\
7186\
7187local function runUntilLimit( _routines, _limit )\
7188 local count = #_routines\
7189 local living = count\
7190\
7191 local tFilters = {}\
7192 local eventData = { n = 0 }\
7193 while true do\
7194 for n=1,count do\
7195 local r = _routines[n]\
7196 if r then\
7197 if tFilters[r] == nil or tFilters[r] == eventData[1] or eventData[1] == \"terminate\" then\
7198 local ok, param = coroutine.resume( r, table.unpack( eventData, 1, eventData.n ) )\
7199 if not ok then\
7200 error( param, 0 )\
7201 else\
7202 tFilters[r] = param\
7203 end\
7204 if coroutine.status( r ) == \"dead\" then\
7205 _routines[n] = nil\
7206 living = living - 1\
7207 if living <= _limit then\
7208 return n\
7209 end\
7210 end\
7211 end\
7212 end\
7213 end\
7214 for n=1,count do\
7215 local r = _routines[n]\
7216 if r and coroutine.status( r ) == \"dead\" then\
7217 _routines[n] = nil\
7218 living = living - 1\
7219 if living <= _limit then\
7220 return n\
7221 end\
7222 end\
7223 end\
7224 eventData = table.pack( os.pullEventRaw() )\
7225 end\
7226end\
7227\
7228function waitForAny( ... )\
7229 local routines = create( ... )\
7230 return runUntilLimit( routines, #routines - 1 )\
7231end\
7232\
7233function waitForAll( ... )\
7234 local routines = create( ... )\
7235 runUntilLimit( routines, 0 )\
7236end",
7237 [ "help/time.txt" ] = "time prints the current time of day.",
7238 [ "help/dance.txt" ] = "dance is a program for Turtles. Turtles love to get funky.",
7239 [ "programs/shell.lua" ] = "\
7240local multishell = multishell\
7241local parentShell = shell\
7242local parentTerm = term.current()\
7243\
7244if multishell then\
7245 multishell.setTitle( multishell.getCurrent(), \"shell\" )\
7246end\
7247\
7248local bExit = false\
7249local sDir = (parentShell and parentShell.dir()) or \"\"\
7250local sPath = (parentShell and parentShell.path()) or \".:/rom/programs\"\
7251local tAliases = (parentShell and parentShell.aliases()) or {}\
7252local tCompletionInfo = (parentShell and parentShell.getCompletionInfo()) or {}\
7253local tProgramStack = {}\
7254\
7255local shell = {}\
7256local function createShellEnv( sDir )\
7257 local tEnv = {}\
7258 tEnv[ \"shell\" ] = shell\
7259 tEnv[ \"multishell\" ] = multishell\
7260\
7261 local package = {}\
7262 package.loaded = {\
7263 _G = _G,\
7264 bit32 = bit32,\
7265 coroutine = coroutine,\
7266 math = math,\
7267 package = package,\
7268 string = string,\
7269 table = table,\
7270 }\
7271 package.path = \"?;?.lua;?/init.lua;/rom/modules/main/?;/rom/modules/main/?.lua;/rom/modules/main/?/init.lua\"\
7272 if turtle then\
7273 package.path = package.path..\";/rom/modules/turtle/?;/rom/modules/turtle/?.lua;/rom/modules/turtle/?/init.lua\"\
7274 elseif command then\
7275 package.path = package.path..\";/rom/modules/command/?;/rom/modules/command/?.lua;/rom/modules/command/?/init.lua\"\
7276 end\
7277 package.config = \"/\\n;\\n?\\n!\\n-\"\
7278 package.preload = {}\
7279 package.loaders = {\
7280 function( name )\
7281 if package.preload[name] then\
7282 return package.preload[name]\
7283 else\
7284 return nil, \"no field package.preload['\" .. name .. \"']\"\
7285 end\
7286 end,\
7287 function( name )\
7288 local fname = string.gsub(name, \"%.\", \"/\")\
7289 local sError = \"\"\
7290 for pattern in string.gmatch(package.path, \"[^;]+\") do\
7291 local sPath = string.gsub(pattern, \"%?\", fname)\
7292 if sPath:sub(1,1) ~= \"/\" then\
7293 sPath = fs.combine(sDir, sPath)\
7294 end\
7295 if fs.exists(sPath) and not fs.isDir(sPath) then\
7296 local fnFile, sError = loadfile( sPath, tEnv )\
7297 if fnFile then\
7298 return fnFile, sPath\
7299 else\
7300 return nil, sError\
7301 end\
7302 else\
7303 if #sError > 0 then\
7304 sError = sError .. \"\\n\"\
7305 end\
7306 sError = sError .. \"no file '\" .. sPath .. \"'\"\
7307 end\
7308 end\
7309 return nil, sError\
7310 end\
7311 }\
7312\
7313 local sentinel = {}\
7314 local function require( name )\
7315 if type( name ) ~= \"string\" then\
7316 error( \"bad argument #1 (expected string, got \" .. type( name ) .. \")\", 2 )\
7317 end\
7318 if package.loaded[name] == sentinel then\
7319 error(\"Loop detected requiring '\" .. name .. \"'\", 0)\
7320 end\
7321 if package.loaded[name] then\
7322 return package.loaded[name]\
7323 end\
7324\
7325 local sError = \"Error loading module '\" .. name .. \"':\"\
7326 for n,searcher in ipairs(package.loaders) do\
7327 local loader, err = searcher(name)\
7328 if loader then\
7329 package.loaded[name] = sentinel\
7330 local result = loader( err )\
7331 if result ~= nil then\
7332 package.loaded[name] = result\
7333 return result\
7334 else\
7335 package.loaded[name] = true\
7336 return true\
7337 end\
7338 else\
7339 sError = sError .. \"\\n\" .. err\
7340 end\
7341 end\
7342 error(sError, 2)\
7343 end\
7344\
7345 tEnv[\"package\"] = package\
7346 tEnv[\"require\"] = require\
7347\
7348 return tEnv\
7349end\
7350\
7351-- Colours\
7352local promptColour, textColour, bgColour\
7353if term.isColour() then\
7354 promptColour = colours.yellow\
7355 textColour = colours.white\
7356 bgColour = colours.black\
7357else\
7358 promptColour = colours.white\
7359 textColour = colours.white\
7360 bgColour = colours.black\
7361end\
7362\
7363local function run( _sCommand, ... )\
7364 local sPath = shell.resolveProgram( _sCommand )\
7365 if sPath ~= nil then\
7366 tProgramStack[#tProgramStack + 1] = sPath\
7367 if multishell then\
7368 local sTitle = fs.getName( sPath )\
7369 if sTitle:sub(-4) == \".lua\" then\
7370 sTitle = sTitle:sub(1,-5)\
7371 end\
7372 multishell.setTitle( multishell.getCurrent(), sTitle )\
7373 end\
7374 local sDir = fs.getDir( sPath )\
7375 local result = os.run( createShellEnv( sDir ), sPath, ... )\
7376 tProgramStack[#tProgramStack] = nil\
7377 if multishell then\
7378 if #tProgramStack > 0 then\
7379 local sTitle = fs.getName( tProgramStack[#tProgramStack] )\
7380 if sTitle:sub(-4) == \".lua\" then\
7381 sTitle = sTitle:sub(1,-5)\
7382 end\
7383 multishell.setTitle( multishell.getCurrent(), sTitle )\
7384 else\
7385 multishell.setTitle( multishell.getCurrent(), \"shell\" )\
7386 end\
7387 end\
7388 return result\
7389 else\
7390 printError( \"No such program\" )\
7391 return false\
7392 end\
7393end\
7394\
7395local function tokenise( ... )\
7396 local sLine = table.concat( { ... }, \" \" )\
7397 local tWords = {}\
7398 local bQuoted = false\
7399 for match in string.gmatch( sLine .. \"\\\"\", \"(.-)\\\"\" ) do\
7400 if bQuoted then\
7401 table.insert( tWords, match )\
7402 else\
7403 for m in string.gmatch( match, \"[^ \\t]+\" ) do\
7404 table.insert( tWords, m )\
7405 end\
7406 end\
7407 bQuoted = not bQuoted\
7408 end\
7409 return tWords\
7410end\
7411\
7412-- Install shell API\
7413function shell.run( ... )\
7414 local tWords = tokenise( ... )\
7415 local sCommand = tWords[1]\
7416 if sCommand then\
7417 return run( sCommand, table.unpack( tWords, 2 ) )\
7418 end\
7419 return false\
7420end\
7421\
7422function shell.exit()\
7423 bExit = true\
7424end\
7425\
7426function shell.dir()\
7427 return sDir\
7428end\
7429\
7430function shell.setDir( _sDir )\
7431 if type( _sDir ) ~= \"string\" then\
7432 error( \"bad argument #1 (expected string, got \" .. type( _sDir ) .. \")\", 2 )\
7433 end\
7434 if not fs.isDir( _sDir ) then\
7435 error( \"Not a directory\", 2 )\
7436 end\
7437 sDir = _sDir\
7438end\
7439\
7440function shell.path()\
7441 return sPath\
7442end\
7443\
7444function shell.setPath( _sPath )\
7445 if type( _sPath ) ~= \"string\" then\
7446 error( \"bad argument #1 (expected string, got \" .. type( _sPath ) .. \")\", 2 )\
7447 end\
7448 sPath = _sPath\
7449end\
7450\
7451function shell.resolve( _sPath )\
7452 if type( _sPath ) ~= \"string\" then\
7453 error( \"bad argument #1 (expected string, got \" .. type( _sPath ) .. \")\", 2 )\
7454 end\
7455 local sStartChar = string.sub( _sPath, 1, 1 )\
7456 if sStartChar == \"/\" or sStartChar == \"\\\\\" then\
7457 return fs.combine( \"\", _sPath )\
7458 else\
7459 return fs.combine( sDir, _sPath )\
7460 end\
7461end\
7462\
7463local function pathWithExtension( _sPath, _sExt )\
7464 local nLen = #sPath\
7465 local sEndChar = string.sub( _sPath, nLen, nLen )\
7466 -- Remove any trailing slashes so we can add an extension to the path safely\
7467 if sEndChar == \"/\" or sEndChar == \"\\\\\" then\
7468 _sPath = string.sub( _sPath, 1, nLen - 1 )\
7469 end\
7470 return _sPath .. \".\" .. _sExt\
7471end\
7472\
7473function shell.resolveProgram( _sCommand )\
7474 if type( _sCommand ) ~= \"string\" then\
7475 error( \"bad argument #1 (expected string, got \" .. type( _sCommand ) .. \")\", 2 )\
7476 end\
7477 -- Substitute aliases firsts\
7478 if tAliases[ _sCommand ] ~= nil then\
7479 _sCommand = tAliases[ _sCommand ]\
7480 end\
7481\
7482 -- If the path is a global path, use it directly\
7483 if _sCommand:find(\"/\") or _sCommand:find(\"\\\\\") then\
7484 local sPath = shell.resolve( _sCommand )\
7485 if fs.exists( sPath ) and not fs.isDir( sPath ) then\
7486 return sPath\
7487 else\
7488 local sPathLua = pathWithExtension( sPath, \"lua\" )\
7489 if fs.exists( sPathLua ) and not fs.isDir( sPathLua ) then\
7490 return sPathLua\
7491 end\
7492 end\
7493 return nil\
7494 end\
7495\
7496 -- Otherwise, look on the path variable\
7497 for sPath in string.gmatch(sPath, \"[^:]+\") do\
7498 sPath = fs.combine( shell.resolve( sPath ), _sCommand )\
7499 if fs.exists( sPath ) and not fs.isDir( sPath ) then\
7500 return sPath\
7501 else\
7502 local sPathLua = pathWithExtension( sPath, \"lua\" )\
7503 if fs.exists( sPathLua ) and not fs.isDir( sPathLua ) then\
7504 return sPathLua\
7505 end\
7506 end\
7507 end\
7508\
7509 -- Not found\
7510 return nil\
7511end\
7512\
7513function shell.programs( _bIncludeHidden )\
7514 local tItems = {}\
7515\
7516 -- Add programs from the path\
7517 for sPath in string.gmatch(sPath, \"[^:]+\") do\
7518 sPath = shell.resolve( sPath )\
7519 if fs.isDir( sPath ) then\
7520 local tList = fs.list( sPath )\
7521 for n=1,#tList do\
7522 local sFile = tList[n]\
7523 if not fs.isDir( fs.combine( sPath, sFile ) ) and\
7524 (_bIncludeHidden or string.sub( sFile, 1, 1 ) ~= \".\") then\
7525 if #sFile > 4 and sFile:sub(-4) == \".lua\" then\
7526 sFile = sFile:sub(1,-5)\
7527 end\
7528 tItems[ sFile ] = true\
7529 end\
7530 end\
7531 end\
7532 end\
7533\
7534 -- Sort and return\
7535 local tItemList = {}\
7536 for sItem, b in pairs( tItems ) do\
7537 table.insert( tItemList, sItem )\
7538 end\
7539 table.sort( tItemList )\
7540 return tItemList\
7541end\
7542\
7543local function completeProgram( sLine )\
7544 if #sLine > 0 and (sLine:find(\"/\") or sLine:find(\"\\\\\")) then\
7545 -- Add programs from the root\
7546 return fs.complete( sLine, sDir, true, false )\
7547\
7548 else\
7549 local tResults = {}\
7550 local tSeen = {}\
7551\
7552 -- Add aliases\
7553 for sAlias, sCommand in pairs( tAliases ) do\
7554 if #sAlias > #sLine and string.sub( sAlias, 1, #sLine ) == sLine then\
7555 local sResult = string.sub( sAlias, #sLine + 1 )\
7556 if not tSeen[ sResult ] then\
7557 table.insert( tResults, sResult )\
7558 tSeen[ sResult ] = true\
7559 end\
7560 end\
7561 end\
7562\
7563 -- Add all subdirectories. We don't include files as they will be added in the block below\
7564 local tDirs = fs.complete( sLine, sDir, false, false )\
7565 for i = 1, #tDirs do\
7566 local sResult = tDirs[i]\
7567 if not tSeen[ sResult ] then\
7568 table.insert ( tResults, sResult )\
7569 tSeen [ sResult ] = true\
7570 end\
7571 end\
7572\
7573 -- Add programs from the path\
7574 local tPrograms = shell.programs()\
7575 for n=1,#tPrograms do\
7576 local sProgram = tPrograms[n]\
7577 if #sProgram > #sLine and string.sub( sProgram, 1, #sLine ) == sLine then\
7578 local sResult = string.sub( sProgram, #sLine + 1 )\
7579 if not tSeen[ sResult ] then\
7580 table.insert( tResults, sResult )\
7581 tSeen[ sResult ] = true\
7582 end\
7583 end\
7584 end\
7585\
7586 -- Sort and return\
7587 table.sort( tResults )\
7588 return tResults\
7589 end\
7590end\
7591\
7592local function completeProgramArgument( sProgram, nArgument, sPart, tPreviousParts )\
7593 local tInfo = tCompletionInfo[ sProgram ]\
7594 if tInfo then\
7595 return tInfo.fnComplete( shell, nArgument, sPart, tPreviousParts )\
7596 end\
7597 return nil\
7598end\
7599\
7600function shell.complete( sLine )\
7601 if type( sLine ) ~= \"string\" then\
7602 error( \"bad argument #1 (expected string, got \" .. type( sLine ) .. \")\", 2 )\
7603 end\
7604 if #sLine > 0 then\
7605 local tWords = tokenise( sLine )\
7606 local nIndex = #tWords\
7607 if string.sub( sLine, #sLine, #sLine ) == \" \" then\
7608 nIndex = nIndex + 1\
7609 end\
7610 if nIndex == 1 then\
7611 local sBit = tWords[1] or \"\"\
7612 local sPath = shell.resolveProgram( sBit )\
7613 if tCompletionInfo[ sPath ] then\
7614 return { \" \" }\
7615 else\
7616 local tResults = completeProgram( sBit )\
7617 for n=1,#tResults do\
7618 local sResult = tResults[n]\
7619 local sPath = shell.resolveProgram( sBit .. sResult )\
7620 if tCompletionInfo[ sPath ] then\
7621 tResults[n] = sResult .. \" \"\
7622 end\
7623 end\
7624 return tResults\
7625 end\
7626\
7627 elseif nIndex > 1 then\
7628 local sPath = shell.resolveProgram( tWords[1] )\
7629 local sPart = tWords[nIndex] or \"\"\
7630 local tPreviousParts = tWords\
7631 tPreviousParts[nIndex] = nil\
7632 return completeProgramArgument( sPath , nIndex - 1, sPart, tPreviousParts )\
7633\
7634 end\
7635 end\
7636 return nil\
7637end\
7638\
7639function shell.completeProgram( sProgram )\
7640 if type( sProgram ) ~= \"string\" then\
7641 error( \"bad argument #1 (expected string, got \" .. type( sProgram ) .. \")\", 2 )\
7642 end\
7643 return completeProgram( sProgram )\
7644end\
7645\
7646function shell.setCompletionFunction( sProgram, fnComplete )\
7647 if type( sProgram ) ~= \"string\" then\
7648 error( \"bad argument #1 (expected string, got \" .. type( sProgram ) .. \")\", 2 )\
7649 end\
7650 if type( fnComplete ) ~= \"function\" then\
7651 error( \"bad argument #2 (expected function, got \" .. type( fnComplete ) .. \")\", 2 )\
7652 end\
7653 tCompletionInfo[ sProgram ] = {\
7654 fnComplete = fnComplete\
7655 }\
7656end\
7657\
7658function shell.getCompletionInfo()\
7659 return tCompletionInfo\
7660end\
7661\
7662function shell.getRunningProgram()\
7663 if #tProgramStack > 0 then\
7664 return tProgramStack[#tProgramStack]\
7665 end\
7666 return nil\
7667end\
7668\
7669function shell.setAlias( _sCommand, _sProgram )\
7670 if type( _sCommand ) ~= \"string\" then\
7671 error( \"bad argument #1 (expected string, got \" .. type( _sCommand ) .. \")\", 2 )\
7672 end\
7673 if type( _sProgram ) ~= \"string\" then\
7674 error( \"bad argument #2 (expected string, got \" .. type( _sProgram ) .. \")\", 2 )\
7675 end\
7676 tAliases[ _sCommand ] = _sProgram\
7677end\
7678\
7679function shell.clearAlias( _sCommand )\
7680 if type( _sCommand ) ~= \"string\" then\
7681 error( \"bad argument #1 (expected string, got \" .. type( _sCommand ) .. \")\", 2 )\
7682 end\
7683 tAliases[ _sCommand ] = nil\
7684end\
7685\
7686function shell.aliases()\
7687 -- Copy aliases\
7688 local tCopy = {}\
7689 for sAlias, sCommand in pairs( tAliases ) do\
7690 tCopy[sAlias] = sCommand\
7691 end\
7692 return tCopy\
7693end\
7694\
7695if multishell then\
7696 function shell.openTab( ... )\
7697 local tWords = tokenise( ... )\
7698 local sCommand = tWords[1]\
7699 if sCommand then\
7700 local sPath = shell.resolveProgram( sCommand )\
7701 if sPath == \"rom/programs/shell.lua\" then\
7702 return multishell.launch( createShellEnv( \"rom/programs\" ), sPath, table.unpack( tWords, 2 ) )\
7703 elseif sPath ~= nil then\
7704 return multishell.launch( createShellEnv( \"rom/programs\" ), \"rom/programs/shell.lua\", sCommand, table.unpack( tWords, 2 ) )\
7705 else\
7706 printError( \"No such program\" )\
7707 end\
7708 end\
7709 end\
7710\
7711 function shell.switchTab( nID )\
7712 if type( nID ) ~= \"number\" then\
7713 error( \"bad argument #1 (expected number, got \" .. type( nID ) .. \")\", 2 )\
7714 end\
7715 multishell.setFocus( nID )\
7716 end\
7717end\
7718\
7719local tArgs = { ... }\
7720if #tArgs > 0 then\
7721 -- \"shell x y z\"\
7722 -- Run the program specified on the commandline\
7723 shell.run( ... )\
7724\
7725else\
7726 -- \"shell\"\
7727 -- Print the header\
7728 term.setBackgroundColor( bgColour )\
7729 term.setTextColour( promptColour )\
7730 print( os.version() )\
7731 term.setTextColour( textColour )\
7732\
7733 -- Run the startup program\
7734 if parentShell == nil then\
7735 shell.run( \"/rom/startup.lua\" )\
7736 end\
7737\
7738 -- Read commands and execute them\
7739 local tCommandHistory = {}\
7740 while not bExit do\
7741 term.redirect( parentTerm )\
7742 term.setBackgroundColor( bgColour )\
7743 term.setTextColour( promptColour )\
7744 write( shell.dir() .. \"> \" )\
7745 term.setTextColour( textColour )\
7746\
7747\
7748 local sLine\
7749 if settings.get( \"shell.autocomplete\" ) then\
7750 sLine = read( nil, tCommandHistory, shell.complete )\
7751 else\
7752 sLine = read( nil, tCommandHistory )\
7753 end\
7754 if sLine:match(\"%S\") and tCommandHistory[#tCommandHistory] ~= sLine then\
7755 table.insert( tCommandHistory, sLine )\
7756 end\
7757 shell.run( sLine )\
7758 end\
7759end",
7760 [ "help/colors.txt" ] = "Functions in the colors api\
7761(used for redstone.setBundledOutput):\
7762colors.combine( color1, color2, color3, ... )\
7763colors.subtract( colors, color1, color2, ... )\
7764colors.test( colors, color )\
7765colors.rgb8( r, g, b )\
7766\
7767Color constants in the colors api, in ascending bit order:\
7768colors.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.",
7769 [ "programs/redstone.lua" ] = "\
7770local tArgs = { ... }\
7771\
7772local function printUsage()\
7773 print( \"Usages:\" )\
7774 print( \"redstone probe\" )\
7775 print( \"redstone set <side> <value>\" )\
7776 print( \"redstone set <side> <color> <value>\" )\
7777 print( \"redstone pulse <side> <count> <period>\" )\
7778end\
7779\
7780local sCommand = tArgs[1]\
7781if sCommand == \"probe\" then\
7782 -- \"redstone probe\"\
7783 -- Regular input\
7784 print( \"Redstone inputs: \" )\
7785\
7786 local count = 0\
7787 local bundledCount = 0\
7788 for n,sSide in ipairs( redstone.getSides() ) do\
7789 if redstone.getBundledInput( sSide ) > 0 then\
7790 bundledCount = bundledCount + 1\
7791 end\
7792 if redstone.getInput( sSide ) then\
7793 if count > 0 then\
7794 io.write( \", \" )\
7795 end\
7796 io.write( sSide )\
7797 count = count + 1\
7798 end\
7799 end\
7800 if count > 0 then\
7801 print( \".\" )\
7802 else\
7803 print( \"None.\" )\
7804 end\
7805\
7806 -- Bundled input\
7807 if bundledCount > 0 then\
7808 print()\
7809 print( \"Bundled inputs:\" )\
7810 for i,sSide in ipairs( redstone.getSides() ) do\
7811 local nInput = redstone.getBundledInput( sSide )\
7812 if nInput ~= 0 then\
7813 write( sSide..\": \" )\
7814 local count = 0\
7815 for sColour,nColour in pairs( colors ) do\
7816 if type( nColour ) == \"number\" and colors.test( nInput, nColour ) then\
7817 if count > 0 then\
7818 write( \", \" )\
7819 end\
7820 if term.isColour() then\
7821 term.setTextColour( nColour )\
7822 end\
7823 write( sColour )\
7824 if term.isColour() then\
7825 term.setTextColour( colours.white )\
7826 end\
7827 count = count + 1\
7828 end\
7829 end\
7830 print( \".\" )\
7831 end\
7832 end\
7833 end\
7834\
7835elseif sCommand == \"pulse\" then\
7836 -- \"redstone pulse\"\
7837 local sSide = tArgs[2]\
7838 local nCount = tonumber( tArgs[3] ) or 1\
7839 local nPeriod = tonumber( tArgs[4] ) or 0.5\
7840 for n=1,nCount do\
7841 redstone.setOutput( sSide, true )\
7842 sleep( nPeriod / 2 )\
7843 redstone.setOutput( sSide, false )\
7844 sleep( nPeriod / 2 )\
7845 end\
7846\
7847elseif sCommand == \"set\" then\
7848 -- \"redstone set\"\
7849 local sSide = tArgs[2]\
7850 if #tArgs > 3 then\
7851 -- Bundled cable output\
7852 local sColour = tArgs[3]\
7853 local nColour = colors[sColour] or colours[sColour]\
7854 if type(nColour) ~= \"number\" then\
7855 printError( \"No such color\" )\
7856 return\
7857 end\
7858\
7859 local sValue = tArgs[4]\
7860 if sValue == \"true\" then\
7861 rs.setBundledOutput( sSide, colors.combine( rs.getBundledOutput( sSide ), nColour ) )\
7862 elseif sValue == \"false\" then\
7863 rs.setBundledOutput( sSide, colors.subtract( rs.getBundledOutput( sSide ), nColour ) )\
7864 else\
7865 print( \"Value must be boolean\" )\
7866 end\
7867 else\
7868 -- Regular output\
7869 local sValue = tArgs[3]\
7870 local nValue = tonumber(sValue)\
7871 if sValue == \"true\" then\
7872 rs.setOutput( sSide, true )\
7873 elseif sValue == \"false\" then\
7874 rs.setOutput( sSide, false )\
7875 elseif nValue and nValue >= 0 and nValue <= 15 then\
7876 rs.setAnalogOutput( sSide, nValue )\
7877 else\
7878 print( \"Value must be boolean or 0-15\" )\
7879 end\
7880 end\
7881\
7882else\
7883 -- Something else\
7884 printUsage()\
7885\
7886end",
7887 [ "programs/rednet/repeat.lua" ] = "\
7888-- Find modems\
7889local tModems = {}\
7890for n,sModem in ipairs( peripheral.getNames() ) do\
7891 if peripheral.getType( sModem ) == \"modem\" then\
7892 table.insert( tModems, sModem )\
7893 end\
7894end\
7895if #tModems == 0 then\
7896 print( \"No modems found.\" )\
7897 return\
7898elseif #tModems == 1 then\
7899 print( \"1 modem found.\" )\
7900else\
7901 print( #tModems .. \" modems found.\" )\
7902end\
7903\
7904local function open( nChannel )\
7905 for n=1,#tModems do\
7906 local sModem = tModems[n]\
7907 peripheral.call( sModem, \"open\", nChannel )\
7908 end\
7909end\
7910\
7911local function close( nChannel )\
7912 for n=1,#tModems do\
7913 local sModem = tModems[n]\
7914 peripheral.call( sModem, \"close\", nChannel )\
7915 end\
7916end\
7917\
7918-- Open channels\
7919print( \"0 messages repeated.\" )\
7920open( rednet.CHANNEL_REPEAT )\
7921\
7922-- Main loop (terminate to break)\
7923local ok, error = pcall( function()\
7924 local tReceivedMessages = {}\
7925 local tReceivedMessageTimeouts = {}\
7926 local nTransmittedMessages = 0\
7927\
7928 while true do\
7929 local sEvent, sModem, nChannel, nReplyChannel, tMessage = os.pullEvent()\
7930 if sEvent == \"modem_message\" then\
7931 -- Got a modem message, rebroadcast it if it's a rednet thing\
7932 if nChannel == rednet.CHANNEL_REPEAT then\
7933 if type( tMessage ) == \"table\" and tMessage.nMessageID and tMessage.nRecipient and type(tMessage.nRecipient) == \"number\" then\
7934 if not tReceivedMessages[ tMessage.nMessageID ] then\
7935 -- Ensure we only repeat a message once\
7936 tReceivedMessages[ tMessage.nMessageID ] = true\
7937 tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = tMessage.nMessageID\
7938\
7939 -- Send on all other open modems, to the target and to other repeaters\
7940 for n=1,#tModems do\
7941 local sOtherModem = tModems[n]\
7942 peripheral.call( sOtherModem, \"transmit\", rednet.CHANNEL_REPEAT, nReplyChannel, tMessage )\
7943 peripheral.call( sOtherModem, \"transmit\", tMessage.nRecipient, nReplyChannel, tMessage )\
7944 end\
7945\
7946 -- Log the event\
7947 nTransmittedMessages = nTransmittedMessages + 1\
7948 local x,y = term.getCursorPos()\
7949 term.setCursorPos( 1, y - 1 )\
7950 term.clearLine()\
7951 if nTransmittedMessages == 1 then\
7952 print( nTransmittedMessages .. \" message repeated.\" )\
7953 else\
7954 print( nTransmittedMessages .. \" messages repeated.\" )\
7955 end\
7956 end\
7957 end\
7958 end\
7959\
7960 elseif sEvent == \"timer\" then\
7961 -- Got a timer event, use it to clear the message history\
7962 local nTimer = sModem\
7963 local nMessageID = tReceivedMessageTimeouts[ nTimer ]\
7964 if nMessageID then\
7965 tReceivedMessageTimeouts[ nTimer ] = nil\
7966 tReceivedMessages[ nMessageID ] = nil\
7967 end\
7968\
7969 end\
7970 end\
7971end )\
7972if not ok then\
7973 printError( error )\
7974end\
7975\
7976-- Close channels\
7977close( rednet.CHANNEL_REPEAT )",
7978 [ "help/excavate.txt" ] = "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.\
7979\
7980ex:\
7981\"excavate 3\" will mine a 3x3 shaft.",
7982 [ "programs/rednet/chat.lua" ] = "\
7983local tArgs = { ... }\
7984\
7985local function printUsage()\
7986 print( \"Usages:\" )\
7987 print( \"chat host <hostname>\" )\
7988 print( \"chat join <hostname> <nickname>\" )\
7989end\
7990\
7991local sOpenedModem = nil\
7992local function openModem()\
7993 for n,sModem in ipairs( peripheral.getNames() ) do\
7994 if peripheral.getType( sModem ) == \"modem\" then\
7995 if not rednet.isOpen( sModem ) then\
7996 rednet.open( sModem )\
7997 sOpenedModem = sModem\
7998 end\
7999 return true\
8000 end\
8001 end\
8002 print( \"No modems found.\" )\
8003 return false\
8004end\
8005\
8006local function closeModem()\
8007 if sOpenedModem ~= nil then\
8008 rednet.close( sOpenedModem )\
8009 sOpenedModem = nil\
8010 end\
8011end\
8012\
8013-- Colours\
8014local highlightColour, textColour\
8015if term.isColour() then\
8016 textColour = colours.white\
8017 highlightColour = colours.yellow\
8018else\
8019 textColour = colours.white\
8020 highlightColour = colours.white\
8021end\
8022\
8023local sCommand = tArgs[1]\
8024if sCommand == \"host\" then\
8025 -- \"chat host\"\
8026 -- Get hostname\
8027 local sHostname = tArgs[2]\
8028 if sHostname == nil then\
8029 printUsage()\
8030 return\
8031 end\
8032\
8033 -- Host server\
8034 if not openModem() then\
8035 return\
8036 end\
8037 rednet.host( \"chat\", sHostname )\
8038 print( \"0 users connected.\" )\
8039\
8040 local tUsers = {}\
8041 local nUsers = 0\
8042 local function send( sText, nUserID )\
8043 if nUserID then\
8044 local tUser = tUsers[ nUserID ]\
8045 if tUser then\
8046 rednet.send( tUser.nID, {\
8047 sType = \"text\",\
8048 nUserID = nUserID,\
8049 sText = sText,\
8050 }, \"chat\" )\
8051 end\
8052 else\
8053 for nUserID, tUser in pairs( tUsers ) do\
8054 rednet.send( tUser.nID, {\
8055 sType = \"text\",\
8056 nUserID = nUserID,\
8057 sText = sText,\
8058 }, \"chat\" )\
8059 end\
8060 end\
8061 end\
8062\
8063 -- Setup ping pong\
8064 local tPingPongTimer = {}\
8065 local function ping( nUserID )\
8066 local tUser = tUsers[ nUserID ]\
8067 rednet.send( tUser.nID, {\
8068 sType = \"ping to client\",\
8069 nUserID = nUserID,\
8070 }, \"chat\" )\
8071\
8072 local timer = os.startTimer( 15 )\
8073 tUser.bPingPonged = false\
8074 tPingPongTimer[ timer ] = nUserID\
8075 end\
8076\
8077 local function printUsers()\
8078 local x,y = term.getCursorPos()\
8079 term.setCursorPos( 1, y - 1 )\
8080 term.clearLine()\
8081 if nUsers == 1 then\
8082 print( nUsers .. \" user connected.\" )\
8083 else\
8084 print( nUsers .. \" users connected.\" )\
8085 end\
8086 end\
8087\
8088 -- Handle messages\
8089 local ok, error = pcall( function()\
8090 parallel.waitForAny( function()\
8091 while true do\
8092 local sEvent, timer = os.pullEvent( \"timer\" )\
8093 local nUserID = tPingPongTimer[ timer ]\
8094 if nUserID and tUsers[ nUserID ] then\
8095 local tUser = tUsers[ nUserID ]\
8096 if tUser then\
8097 if not tUser.bPingPonged then\
8098 send( \"* \"..tUser.sUsername..\" has timed out\" )\
8099 tUsers[ nUserID ] = nil\
8100 nUsers = nUsers - 1\
8101 printUsers()\
8102 else\
8103 ping( nUserID )\
8104 end\
8105 end\
8106 end\
8107 end\
8108 end,\
8109 function()\
8110 while true do\
8111 local tCommands\
8112 tCommands = {\
8113 [\"me\"] = function( tUser, sContent )\
8114 if string.len(sContent) > 0 then\
8115 send( \"* \"..tUser.sUsername..\" \"..sContent )\
8116 else\
8117 send( \"* Usage: /me [words]\", tUser.nUserID )\
8118 end\
8119 end,\
8120 [\"nick\"] = function( tUser, sContent )\
8121 if string.len(sContent) > 0 then\
8122 local sOldName = tUser.sUsername\
8123 tUser.sUsername = sContent\
8124 send( \"* \"..sOldName..\" is now known as \"..tUser.sUsername )\
8125 else\
8126 send( \"* Usage: /nick [nickname]\", tUser.nUserID )\
8127 end\
8128 end,\
8129 [\"users\"] = function( tUser, sContent )\
8130 send( \"* Connected Users:\", tUser.nUserID )\
8131 local sUsers = \"*\"\
8132 for nUserID, tUser in pairs( tUsers ) do\
8133 sUsers = sUsers .. \" \" .. tUser.sUsername\
8134 end\
8135 send( sUsers, tUser.nUserID )\
8136 end,\
8137 [\"help\"] = function( tUser, sContent )\
8138 send( \"* Available commands:\", tUser.nUserID )\
8139 local sCommands = \"*\"\
8140 for sCommand, fnCommand in pairs( tCommands ) do\
8141 sCommands = sCommands .. \" /\" .. sCommand\
8142 end\
8143 send( sCommands..\" /logout\", tUser.nUserID )\
8144 end,\
8145 }\
8146\
8147 local nSenderID, tMessage = rednet.receive( \"chat\" )\
8148 if type( tMessage ) == \"table\" then\
8149 if tMessage.sType == \"login\" then\
8150 -- Login from new client\
8151 local nUserID = tMessage.nUserID\
8152 local sUsername = tMessage.sUsername\
8153 if nUserID and sUsername then\
8154 tUsers[ nUserID ] = {\
8155 nID = nSenderID,\
8156 nUserID = nUserID,\
8157 sUsername = sUsername,\
8158 }\
8159 nUsers = nUsers + 1\
8160 printUsers()\
8161 send( \"* \"..sUsername..\" has joined the chat\" )\
8162 ping( nUserID )\
8163 end\
8164\
8165 else\
8166 -- Something else from existing client\
8167 local nUserID = tMessage.nUserID\
8168 local tUser = tUsers[ nUserID ]\
8169 if tUser and tUser.nID == nSenderID then\
8170 if tMessage.sType == \"logout\" then\
8171 send( \"* \"..tUser.sUsername..\" has left the chat\" )\
8172 tUsers[ nUserID ] = nil\
8173 nUsers = nUsers - 1\
8174 printUsers()\
8175\
8176 elseif tMessage.sType == \"chat\" then\
8177 local sMessage = tMessage.sText\
8178 if sMessage then\
8179 local sCommand = string.match( sMessage, \"^/([a-z]+)\" )\
8180 if sCommand then\
8181 local fnCommand = tCommands[ sCommand ]\
8182 if fnCommand then\
8183 local sContent = string.sub( sMessage, string.len(sCommand)+3 )\
8184 fnCommand( tUser, sContent )\
8185 else\
8186 send( \"* Unrecognised command: /\"..sCommand, tUser.nUserID )\
8187 end\
8188 else\
8189 send( \"<\"..tUser.sUsername..\"> \"..tMessage.sText )\
8190 end\
8191 end\
8192\
8193 elseif tMessage.sType == \"ping to server\" then\
8194 rednet.send( tUser.nID, {\
8195 sType = \"pong to client\",\
8196 nUserID = nUserID,\
8197 }, \"chat\" )\
8198\
8199 elseif tMessage.sType == \"pong to server\" then\
8200 tUser.bPingPonged = true\
8201\
8202 end\
8203 end\
8204 end\
8205 end\
8206 end\
8207 end )\
8208 end )\
8209 if not ok then\
8210 printError( error )\
8211 end\
8212\
8213 -- Unhost server\
8214 for nUserID, tUser in pairs( tUsers ) do\
8215 rednet.send( tUser.nID, {\
8216 sType = \"kick\",\
8217 nUserID = nUserID,\
8218 }, \"chat\" )\
8219 end\
8220 rednet.unhost( \"chat\" )\
8221 closeModem()\
8222\
8223elseif sCommand == \"join\" then\
8224 -- \"chat join\"\
8225 -- Get hostname and username\
8226 local sHostname = tArgs[2]\
8227 local sUsername = tArgs[3]\
8228 if sHostname == nil or sUsername == nil then\
8229 printUsage()\
8230 return\
8231 end\
8232\
8233 -- Connect\
8234 if not openModem() then\
8235 return\
8236 end\
8237 write( \"Looking up \" .. sHostname .. \"... \" )\
8238 local nHostID = rednet.lookup( \"chat\", sHostname )\
8239 if nHostID == nil then\
8240 print( \"Failed.\" )\
8241 return\
8242 else\
8243 print( \"Success.\" )\
8244 end\
8245\
8246 -- Login\
8247 local nUserID = math.random( 1, 2147483647 )\
8248 rednet.send( nHostID, {\
8249 sType = \"login\",\
8250 nUserID = nUserID,\
8251 sUsername = sUsername,\
8252 }, \"chat\" )\
8253\
8254 -- Setup ping pong\
8255 local bPingPonged = true\
8256 local pingPongTimer = os.startTimer( 0 )\
8257\
8258 local function ping()\
8259 rednet.send( nHostID, {\
8260 sType = \"ping to server\",\
8261 nUserID = nUserID,\
8262 }, \"chat\" )\
8263 bPingPonged = false\
8264 pingPongTimer = os.startTimer( 15 )\
8265 end\
8266\
8267 -- Handle messages\
8268 local w,h = term.getSize()\
8269 local parentTerm = term.current()\
8270 local titleWindow = window.create( parentTerm, 1, 1, w, 1, true )\
8271 local historyWindow = window.create( parentTerm, 1, 2, w, h-2, true )\
8272 local promptWindow = window.create( parentTerm, 1, h, w, 1, true )\
8273 historyWindow.setCursorPos( 1, h-2 )\
8274\
8275 term.clear()\
8276 term.setTextColour( textColour )\
8277 term.redirect( promptWindow )\
8278 promptWindow.restoreCursor()\
8279\
8280 local function drawTitle()\
8281 local x,y = titleWindow.getCursorPos()\
8282 local w,h = titleWindow.getSize()\
8283 local sTitle = sUsername..\" on \"..sHostname\
8284 titleWindow.setTextColour( highlightColour )\
8285 titleWindow.setCursorPos( math.floor( w/2 - string.len(sTitle)/2 ), 1 )\
8286 titleWindow.clearLine()\
8287 titleWindow.write( sTitle )\
8288 promptWindow.restoreCursor()\
8289 end\
8290\
8291 local function printMessage( sMessage )\
8292 term.redirect( historyWindow )\
8293 print()\
8294 if string.match( sMessage, \"^%*\" ) then\
8295 -- Information\
8296 term.setTextColour( highlightColour )\
8297 write( sMessage )\
8298 term.setTextColour( textColour )\
8299 else\
8300 -- Chat\
8301 local sUsernameBit = string.match( sMessage, \"^<[^>]*>\" )\
8302 if sUsernameBit then\
8303 term.setTextColour( highlightColour )\
8304 write( sUsernameBit )\
8305 term.setTextColour( textColour )\
8306 write( string.sub( sMessage, string.len( sUsernameBit ) + 1 ) )\
8307 else\
8308 write( sMessage )\
8309 end\
8310 end\
8311 term.redirect( promptWindow )\
8312 promptWindow.restoreCursor()\
8313 end\
8314\
8315 drawTitle()\
8316\
8317 local ok, error = pcall( function()\
8318 parallel.waitForAny( function()\
8319 while true do\
8320 local sEvent, timer = os.pullEvent()\
8321 if sEvent == \"timer\" then\
8322 if timer == pingPongTimer then\
8323 if not bPingPonged then\
8324 printMessage( \"Server timeout.\" )\
8325 return\
8326 else\
8327 ping()\
8328 end\
8329 end\
8330\
8331 elseif sEvent == \"term_resize\" then\
8332 local w,h = parentTerm.getSize()\
8333 titleWindow.reposition( 1, 1, w, 1 )\
8334 historyWindow.reposition( 1, 2, w, h-2 )\
8335 promptWindow.reposition( 1, h, w, 1 )\
8336\
8337 end\
8338 end\
8339 end,\
8340 function()\
8341 while true do\
8342 local nSenderID, tMessage = rednet.receive( \"chat\" )\
8343 if nSenderID == nHostID and type( tMessage ) == \"table\" and tMessage.nUserID == nUserID then\
8344 if tMessage.sType == \"text\" then\
8345 local sText = tMessage.sText\
8346 if sText then\
8347 printMessage( sText )\
8348 end\
8349\
8350 elseif tMessage.sType == \"ping to client\" then\
8351 rednet.send( nSenderID, {\
8352 sType = \"pong to server\",\
8353 nUserID = nUserID,\
8354 }, \"chat\" )\
8355\
8356 elseif tMessage.sType == \"pong to client\" then\
8357 bPingPonged = true\
8358\
8359 elseif tMessage.sType == \"kick\" then\
8360 return\
8361\
8362 end\
8363 end\
8364 end\
8365 end,\
8366 function()\
8367 local tSendHistory = {}\
8368 while true do\
8369 promptWindow.setCursorPos( 1,1 )\
8370 promptWindow.clearLine()\
8371 promptWindow.setTextColor( highlightColour )\
8372 promptWindow.write( \": \")\
8373 promptWindow.setTextColor( textColour )\
8374\
8375 local sChat = read( nil, tSendHistory )\
8376 if string.match( sChat, \"^/logout\" ) then\
8377 break\
8378 else\
8379 rednet.send( nHostID, {\
8380 sType = \"chat\",\
8381 nUserID = nUserID,\
8382 sText = sChat,\
8383 }, \"chat\" )\
8384 table.insert( tSendHistory, sChat )\
8385 end\
8386 end\
8387 end )\
8388 end )\
8389\
8390 -- Close the windows\
8391 term.redirect( parentTerm )\
8392\
8393 -- Print error notice\
8394 local w,h = term.getSize()\
8395 term.setCursorPos( 1, h )\
8396 term.clearLine()\
8397 term.setCursorBlink( false )\
8398 if not ok then\
8399 printError( error )\
8400 end\
8401\
8402 -- Logout\
8403 rednet.send( nHostID, {\
8404 sType = \"logout\",\
8405 nUserID = nUserID,\
8406 }, \"chat\" )\
8407 closeModem()\
8408\
8409 -- Print disconnection notice\
8410 print( \"Disconnected.\" )\
8411\
8412else\
8413 -- \"chat somethingelse\"\
8414 printUsage()\
8415\
8416end",
8417 [ "programs/reboot.lua" ] = "if term.isColour() then\
8418 term.setTextColour( colours.yellow )\
8419end\
8420print( \"Goodbye\" )\
8421term.setTextColour( colours.white )\
8422\
8423sleep( 1 )\
8424os.reboot()",
8425 [ "help/refuel.txt" ] = "refuel is a program for Turtles. Refuel will consume items from the inventory as fuel for turtle.\
8426\
8427ex:\
8428\"refuel\" will refuel with at most one fuel item\
8429\"refuel 10\" will refuel with at most 10 fuel items\
8430\"refuel all\" will refuel with as many fuel items as possible",
8431 [ "programs/programs.lua" ] = "\
8432local bAll = false\
8433local tArgs = { ... }\
8434if #tArgs > 0 and tArgs[1] == \"all\" then\
8435 bAll = true\
8436end\
8437\
8438local tPrograms = shell.programs( bAll )\
8439textutils.pagedTabulate( tPrograms )",
8440 [ "help/redirection.txt" ] = "Redirection ComputerCraft Edition is the CraftOS version of a fun new puzzle game by Dan200, the author of ComputerCraft.\
8441Play it on any Advanced Computer, then visit http://www.redirectiongame.com to play the full game!",
8442 [ "programs/pocket/unequip.lua" ] = "local ok, err = pcall( pocket.unequipBack )\
8443if not ok then\
8444 printError( \"Nothing to unequip\" )\
8445else\
8446 print( \"Item unequipped\" )\
8447end",
8448 [ "programs/emu.lua" ] = "local args = { ... }\
8449\
8450if ccemux then\
8451 local function help()\
8452 print(\"Usages:\")\
8453 print(\"emu close - close this computer\")\
8454 print(\"emu open [id] - open another computer\")\
8455 print(\"emu data - opens the data folder\")\
8456 print(\"emu config - opens the config editor\")\
8457 --print(\"emu set <setting> <values> - edits a setting\")\
8458 --print(\"emu list settings - list editable settings\")\
8459 --print(\"emu save - saves current settings\")\
8460 print(\"Run 'help emu' for additional information\")\
8461 end\
8462\
8463 if #args == 0 then\
8464 help()\
8465 else\
8466 if args[1] == \"close\" then\
8467 ccemux.closeEmu()\
8468 elseif args[1] == \"open\" then\
8469 print(\"Opened computer ID \" .. ccemux.openEmu(tonumber(args[2])))\
8470 elseif args[1] == \"data\" then\
8471 if ccemux.openDataDir() then\
8472 print(\"Opened data folder\")\
8473 else\
8474 print(\"Unable to open data folder\")\
8475 end\
8476 elseif args[1] == \"config\" then\
8477 local ok, err = ccemux.openConfig()\
8478 if ok then\
8479 print(\"Opened config editor\")\
8480 else\
8481 print(err)\
8482 end\
8483 elseif args[1] == \"set\" then\
8484 if #args <= 1 then\
8485 help()\
8486 else\
8487 if args[2] == \"resolution\" then\
8488 if #args == 4 then\
8489 ccemux.setResolution(tonumber(args[3]), tonumber(args[4]))\
8490 print(\"Set resolution to \" .. args[3] .. \"x\" .. args[4])\
8491 elseif #args == 3 then\
8492 if args[3] == \"computer\" then\
8493 ccemux.setResolution(51, 19)\
8494 print(\"Set resolution to computer (51x19)\")\
8495 elseif args[3] == \"pocket\" then\
8496 ccemux.setResolution(26, 20)\
8497 print(\"Set resolution to pocket (26x20)\")\
8498 elseif args[3] == \"turtle\" then\
8499 ccemux.setResolution(39, 13)\
8500 print(\"Set resolution to turtle (39x13)\")\
8501 end\
8502 else\
8503 printError(\"Usage: emu set resolution <width> <height>\")\
8504 end\
8505 --elseif args[2] == \"scale\" then\
8506\
8507 elseif args[2] == \"cursor\" then\
8508 ccemux.setCursorChar(args[3])\
8509 print(\"Set cursor char to \" .. args[3])\
8510 else\
8511 printError(\"Unrecognized setting: \" .. args[2])\
8512 end\
8513 end\
8514 elseif args[1] == \"list\" then\
8515 if args[2] == \"settings\" then\
8516 print(\"Editable settings:\")\
8517 print(\"resolution <width> <height>\")\
8518 -- not yet implemented\
8519 --print(\"scale <pixels>\")\
8520 print(\"cursor <char>\")\
8521 else\
8522 printError(\"Unrecognized subcommand: \" .. args[2])\
8523 end\
8524 elseif args[1] == \"save\" then\
8525 ccemux.saveSettings()\
8526 print(\"Saved settings\")\
8527 else\
8528 printError(\"Unrecognized subcommand: \" .. args[1])\
8529 help()\
8530 end\
8531 end\
8532else\
8533 printError(\"CCEmuX API is disabled or unavailable.\")\
8534end",
8535 [ "programs/fun/advanced/levels/10.dat" ] = "5\
8536 777 77777\
8537 727777778837\
8538 788888878787\
8539 787777888887\
854077877778777777\
85417e8b7888b888e7\
85427787787b777877\
8543 777887887887\
8544 7487807487\
8545 7777777777",
8546 [ "programs/monitor.lua" ] = "local function printUsage()\
8547 print( \"Usage: monitor <name> <program> <arguments>\" )\
8548 return\
8549end\
8550\
8551local tArgs = { ... }\
8552if #tArgs < 2 then\
8553 printUsage()\
8554 return\
8555end\
8556\
8557local sName = tArgs[1]\
8558if peripheral.getType( sName ) ~= \"monitor\" then\
8559 print( \"No monitor named \".. sName )\
8560 return\
8561end\
8562\
8563local sProgram = tArgs[2]\
8564local sPath = shell.resolveProgram( sProgram )\
8565if sPath == nil then\
8566 print( \"No such program: \"..sProgram )\
8567 return\
8568end\
8569\
8570print( \"Running \"..sProgram..\" on monitor \"..sName )\
8571\
8572local monitor = peripheral.wrap( sName )\
8573local previousTerm = term.redirect( monitor )\
8574\
8575local co = coroutine.create( function()\
8576 shell.run( sProgram, table.unpack( tArgs, 3 ) )\
8577end )\
8578\
8579local function resume( ... )\
8580 local ok, param = coroutine.resume( co, ... )\
8581 if not ok then\
8582 printError( param )\
8583 end\
8584 return param\
8585end\
8586\
8587local ok, param = pcall( function()\
8588 local sFilter = resume()\
8589 while coroutine.status( co ) ~= \"dead\" do\
8590 local tEvent = table.pack( os.pullEventRaw() )\
8591 if sFilter == nil or tEvent[1] == sFilter or tEvent[1] == \"terminate\" then\
8592 sFilter = resume( table.unpack( tEvent, 1, tEvent.n ) )\
8593 end\
8594 if coroutine.status( co ) ~= \"dead\" and (sFilter == nil or sFilter == \"mouse_click\") then\
8595 if tEvent[1] == \"monitor_touch\" and tEvent[2] == sName then\
8596 sFilter = resume( \"mouse_click\", 1, table.unpack( tEvent, 3, tEvent.n ) )\
8597 end\
8598 end\
8599 if coroutine.status( co ) ~= \"dead\" and (sFilter == nil or sFilter == \"term_resize\") then\
8600 if tEvent[1] == \"monitor_resize\" and tEvent[2] == sName then\
8601 sFilter = resume( \"term_resize\" )\
8602 end\
8603 end\
8604 end\
8605end )\
8606\
8607term.redirect( previousTerm )\
8608if not ok then\
8609 printError( param )\
8610end",
8611 [ "apis/term.lua" ] = "\
8612local native = (term.native and term.native()) or term\
8613local redirectTarget = native\
8614\
8615local function wrap( _sFunction )\
8616 return function( ... )\
8617 return redirectTarget[ _sFunction ]( ... )\
8618 end\
8619end\
8620\
8621local term = {}\
8622\
8623term.redirect = function( target )\
8624 if type( target ) ~= \"table\" then\
8625 error( \"bad argument #1 (expected table, got \" .. type( target ) .. \")\", 2 )\
8626 end\
8627 if target == term then\
8628 error( \"term is not a recommended redirect target, try term.current() instead\", 2 )\
8629 end\
8630 for k,v in pairs( native ) do\
8631 if type( k ) == \"string\" and type( v ) == \"function\" then\
8632 if type( target[k] ) ~= \"function\" then\
8633 target[k] = function()\
8634 error( \"Redirect object is missing method \"..k..\".\", 2 )\
8635 end\
8636 end\
8637 end\
8638 end\
8639 local oldRedirectTarget = redirectTarget\
8640 redirectTarget = target\
8641 return oldRedirectTarget\
8642end\
8643\
8644term.current = function()\
8645 return redirectTarget\
8646end\
8647\
8648term.native = function()\
8649 -- NOTE: please don't use this function unless you have to.\
8650 -- If you're running in a redirected or multitasked enviorment, term.native() will NOT be\
8651 -- the current terminal when your program starts up. It is far better to use term.current()\
8652 return native\
8653end\
8654\
8655for k,v in pairs( native ) do\
8656 if type( k ) == \"string\" and type( v ) == \"function\" then\
8657 if term[k] == nil then\
8658 term[k] = wrap( k )\
8659 end\
8660 end\
8661end\
8662\
8663local env = _ENV\
8664for k,v in pairs( term ) do\
8665 env[k] = v\
8666end",
8667 [ "help/fs.txt" ] = "Functions in the Filesystem API:\
8668fs.list( path )\
8669fs.find( wildcard )\
8670fs.exists( path )\
8671fs.isDir( path )\
8672fs.isReadOnly( path )\
8673fs.getDir( path )\
8674fs.getName( path )\
8675fs.getSize( path )\
8676fs.getDrive( path )\
8677fs.getFreeSpace( path )\
8678fs.makeDir( path )\
8679fs.move( path, path )\
8680fs.copy( path, path )\
8681fs.delete( path )\
8682fs.combine( path, localpath )\
8683fs.open( path, mode )\
8684fs.complete( path, location )\
8685Available fs.open() modes are \"r\", \"w\", \"a\", \"rb\", \"wb\" and \"ab\".\
8686\
8687Functions on files opened with mode \"r\":\
8688readLine()\
8689readAll()\
8690close()\
8691read( number )\
8692\
8693Functions on files opened with mode \"w\" or \"a\":\
8694write( string )\
8695writeLine( string )\
8696flush()\
8697close()\
8698\
8699Functions on files opened with mode \"rb\":\
8700read()\
8701close()\
8702\
8703Functions on files opened with mode \"wb\" or \"ab\":\
8704write( byte )\
8705flush()\
8706close()",
8707 [ "programs/lua.lua" ] = "\
8708local tArgs = { ... }\
8709if #tArgs > 0 then\
8710 print( \"This is an interactive Lua prompt.\" )\
8711 print( \"To run a lua program, just type its name.\" )\
8712 return\
8713end\
8714\
8715local bRunning = true\
8716local tCommandHistory = {}\
8717local tEnv = {\
8718 [\"exit\"] = function()\
8719 bRunning = false\
8720 end,\
8721 [\"_echo\"] = function( ... )\
8722 return ...\
8723 end,\
8724}\
8725setmetatable( tEnv, { __index = _ENV } )\
8726\
8727if term.isColour() then\
8728 term.setTextColour( colours.yellow )\
8729end\
8730print( \"Interactive Lua prompt.\" )\
8731print( \"Call exit() to exit.\" )\
8732term.setTextColour( colours.white )\
8733\
8734while bRunning do\
8735 --if term.isColour() then\
8736 -- term.setTextColour( colours.yellow )\
8737 --end\
8738 write( \"lua> \" )\
8739 --term.setTextColour( colours.white )\
8740\
8741 local s = read( nil, tCommandHistory, function( sLine )\
8742 if settings.get( \"lua.autocomplete\" ) then\
8743 local nStartPos = string.find( sLine, \"[a-zA-Z0-9_%.:]+$\" )\
8744 if nStartPos then\
8745 sLine = string.sub( sLine, nStartPos )\
8746 end\
8747 if #sLine > 0 then\
8748 return textutils.complete( sLine, tEnv )\
8749 end\
8750 end\
8751 return nil\
8752 end )\
8753 if s:match(\"%S\") and tCommandHistory[#tCommandHistory] ~= s then\
8754 table.insert( tCommandHistory, s )\
8755 end\
8756\
8757 local nForcePrint = 0\
8758 local func, e = load( s, \"lua\", \"t\", tEnv )\
8759 local func2, e2 = load( \"return _echo(\"..s..\");\", \"lua\", \"t\", tEnv )\
8760 if not func then\
8761 if func2 then\
8762 func = func2\
8763 e = nil\
8764 nForcePrint = 1\
8765 end\
8766 else\
8767 if func2 then\
8768 func = func2\
8769 end\
8770 end\
8771\
8772 if func then\
8773 local tResults = table.pack( pcall( func ) )\
8774 if tResults[1] then\
8775 local n = 1\
8776 while n < tResults.n or (n <= nForcePrint) do\
8777 local value = tResults[ n + 1 ]\
8778 if type( value ) == \"table\" then\
8779 local metatable = getmetatable( value )\
8780 if type(metatable) == \"table\" and type(metatable.__tostring) == \"function\" then\
8781 print( tostring( value ) )\
8782 else\
8783 local ok, serialised = pcall( textutils.serialise, value )\
8784 if ok then\
8785 print( serialised )\
8786 else\
8787 print( tostring( value ) )\
8788 end\
8789 end\
8790 else\
8791 print( tostring( value ) )\
8792 end\
8793 n = n + 1\
8794 end\
8795 else\
8796 printError( tResults[2] )\
8797 end\
8798 else\
8799 printError( e )\
8800 end\
8801\
8802end",
8803 [ "programs/fun/advanced/levels/11.dat" ] = "4\
8804 777777777\
8805 727872787\
8806 787878787\
8807777787878787777\
88087be888888888be7\
8809777787878787777\
8810 787878787\
8811 787478747\
8812 777777777",
8813 [ "help/copy.txt" ] = "cp copies a file or directory from one location to another.\
8814\
8815ex:\
8816\"cp rom myrom\" copies \"rom\" to \"myrom\".\
8817\"cp rom mystuff/rom\" copies \"rom\" to \"mystuff/rom\".\
8818\"cp disk/* disk2\" copies the contents of one disk to another",
8819 [ "help/delete.txt" ] = "rm deletes a file or a directory and its contents.\
8820\
8821ex:\
8822\"rm foo\" will delete the file foo.\
8823\"rm disk/*\" will delete the contents of a disk.",
8824 [ "programs/advanced/fg.lua" ] = "\
8825if not shell.openTab then\
8826 printError( \"Requires multishell\" )\
8827 return\
8828end\
8829\
8830local tArgs = { ... }\
8831if #tArgs > 0 then\
8832 local nTask = shell.openTab( table.unpack( tArgs ) )\
8833 if nTask then\
8834 shell.switchTab( nTask )\
8835 end\
8836else\
8837 local nTask = shell.openTab( \"shell\" )\
8838 if nTask then\
8839 shell.switchTab( nTask )\
8840 end\
8841end",
8842 [ "programs/apis.lua" ] = "\
8843local tApis = {}\
8844for k,v in pairs( _G ) do\
8845 if type(k) == \"string\" and type(v) == \"table\" and k ~= \"_G\" then\
8846 table.insert( tApis, k )\
8847 end\
8848end\
8849table.insert( tApis, \"shell\" )\
8850table.insert( tApis, \"package\" )\
8851if multishell then\
8852 table.insert( tApis, \"multishell\" )\
8853end\
8854table.sort( tApis )\
8855\
8856textutils.pagedTabulate( tApis )",
8857 [ "programs/label.lua" ] = "\
8858local function printUsage()\
8859 print( \"Usages:\" )\
8860 print( \"label get\" )\
8861 print( \"label get <drive>\" )\
8862 print( \"label set <text>\" )\
8863 print( \"label set <drive> <text>\" )\
8864 print( \"label clear\" )\
8865 print( \"label clear <drive>\" )\
8866end\
8867\
8868local function checkDrive( sDrive )\
8869 if peripheral.getType( sDrive ) == \"drive\" then\
8870 -- Check the disk exists\
8871 local bData = disk.hasData( sDrive )\
8872 if not bData then\
8873 print( \"No disk in \"..sDrive..\" drive\" )\
8874 return false\
8875 end\
8876 else\
8877 print( \"No disk drive named \"..sDrive )\
8878 return false\
8879 end\
8880 return true\
8881end\
8882\
8883local function get( sDrive )\
8884 if sDrive ~= nil then\
8885 if checkDrive( sDrive ) then\
8886 local sLabel = disk.getLabel( sDrive )\
8887 if sLabel then\
8888 print( \"Disk label is \\\"\"..sLabel..\"\\\"\" )\
8889 else\
8890 print( \"No Disk label\" )\
8891 end\
8892 end\
8893 else\
8894 local sLabel = os.getComputerLabel()\
8895 if sLabel then\
8896 print( \"Computer label is \\\"\"..sLabel..\"\\\"\" )\
8897 else\
8898 print( \"No Computer label\" )\
8899 end\
8900 end\
8901end\
8902\
8903local function set( sDrive, sText )\
8904 if sDrive ~= nil then\
8905 if checkDrive( sDrive ) then\
8906 disk.setLabel( sDrive, sText )\
8907 local sLabel = disk.getLabel( sDrive )\
8908 if sLabel then\
8909 print( \"Disk label set to \\\"\"..sLabel..\"\\\"\" )\
8910 else\
8911 print( \"Disk label cleared\" )\
8912 end\
8913 end\
8914 else\
8915 os.setComputerLabel( sText )\
8916 local sLabel = os.getComputerLabel()\
8917 if sLabel then\
8918 print( \"Computer label set to \\\"\"..sLabel..\"\\\"\" )\
8919 else\
8920 print( \"Computer label cleared\" )\
8921 end\
8922 end\
8923end\
8924\
8925local tArgs = { ... }\
8926local sCommand = tArgs[1]\
8927if sCommand == \"get\" then\
8928 -- Get a label\
8929 if #tArgs == 1 then\
8930 get( nil )\
8931 elseif #tArgs == 2 then\
8932 get( tArgs[2] )\
8933 else\
8934 printUsage()\
8935 end\
8936elseif sCommand == \"set\" then\
8937 -- Set a label\
8938 if #tArgs == 2 then\
8939 set( nil, tArgs[2] )\
8940 elseif #tArgs == 3 then\
8941 set( tArgs[2], tArgs[3] )\
8942 else\
8943 printUsage()\
8944 end\
8945elseif sCommand == \"clear\" then\
8946 -- Clear a label\
8947 if #tArgs == 1 then\
8948 set( nil, nil )\
8949 elseif #tArgs == 2 then\
8950 set( tArgs[2], nil )\
8951 else\
8952 printUsage()\
8953 end\
8954else\
8955 printUsage()\
8956end",
8957 [ "programs/id.lua" ] = "\
8958local sDrive = nil\
8959local tArgs = { ... }\
8960if #tArgs > 0 then\
8961 sDrive = tostring( tArgs[1] )\
8962end\
8963\
8964if sDrive == nil then\
8965 print( \"This is computer #\"..os.getComputerID() )\
8966\
8967 local label = os.getComputerLabel()\
8968 if label then\
8969 print( \"This computer is labelled \\\"\"..label..\"\\\"\" )\
8970 end\
8971\
8972else\
8973 local bData = disk.hasData( sDrive )\
8974 if not bData then\
8975 print( \"No disk in drive \"..sDrive )\
8976 return\
8977 end\
8978\
8979 print( \"The disk is #\"..disk.getID( sDrive ) )\
8980\
8981 local label = disk.getLabel( sDrive )\
8982 if label then\
8983 print( \"The disk is labelled \\\"\"..label..\"\\\"\" )\
8984 end\
8985end",
8986 [ "programs/http/pastebin.lua" ] = "\
8987local function printUsage()\
8988 print( \"Usages:\" )\
8989 print( \"pastebin put <filename>\" )\
8990 print( \"pastebin get <code> <filename>\" )\
8991 print( \"pastebin run <code> <arguments>\" )\
8992end\
8993\
8994local tArgs = { ... }\
8995if #tArgs < 2 then\
8996 printUsage()\
8997 return\
8998end\
8999\
9000if not http then\
9001 printError( \"Pastebin requires http API\" )\
9002 printError( \"Set http_enable to true in ComputerCraft.cfg\" )\
9003 return\
9004end\
9005\
9006local function get(paste)\
9007 write( \"Connecting to pastebin.com... \" )\
9008 local response = http.get(\
9009 \"https://pastebin.com/raw/\"..textutils.urlEncode( paste )\
9010 )\
9011\
9012 if response then\
9013 print( \"Success.\" )\
9014\
9015 local sResponse = response.readAll()\
9016 response.close()\
9017 return sResponse\
9018 else\
9019 print( \"Failed.\" )\
9020 end\
9021end\
9022\
9023local sCommand = tArgs[1]\
9024if sCommand == \"put\" then\
9025 -- Upload a file to pastebin.com\
9026 -- Determine file to upload\
9027 local sFile = tArgs[2]\
9028 local sPath = shell.resolve( sFile )\
9029 if not fs.exists( sPath ) or fs.isDir( sPath ) then\
9030 print( \"No such file\" )\
9031 return\
9032 end\
9033\
9034 -- Read in the file\
9035 local sName = fs.getName( sPath )\
9036 local file = fs.open( sPath, \"r\" )\
9037 local sText = file.readAll()\
9038 file.close()\
9039\
9040 -- POST the contents to pastebin\
9041 write( \"Connecting to pastebin.com... \" )\
9042 local key = \"0ec2eb25b6166c0c27a394ae118ad829\"\
9043 local response = http.post(\
9044 \"https://pastebin.com/api/api_post.php\",\
9045 \"api_option=paste&\"..\
9046 \"api_dev_key=\"..key..\"&\"..\
9047 \"api_paste_format=lua&\"..\
9048 \"api_paste_name=\"..textutils.urlEncode(sName)..\"&\"..\
9049 \"api_paste_code=\"..textutils.urlEncode(sText)\
9050 )\
9051\
9052 if response then\
9053 print( \"Success.\" )\
9054\
9055 local sResponse = response.readAll()\
9056 response.close()\
9057\
9058 local sCode = string.match( sResponse, \"[^/]+$\" )\
9059 print( \"Uploaded as \"..sResponse )\
9060 print( \"Run \\\"pastebin get \"..sCode..\"\\\" to download anywhere\" )\
9061\
9062 else\
9063 print( \"Failed.\" )\
9064 end\
9065\
9066elseif sCommand == \"get\" then\
9067 -- Download a file from pastebin.com\
9068 if #tArgs < 3 then\
9069 printUsage()\
9070 return\
9071 end\
9072\
9073 -- Determine file to download\
9074 local sCode = tArgs[2]\
9075 local sFile = tArgs[3]\
9076 local sPath = shell.resolve( sFile )\
9077 if fs.exists( sPath ) then\
9078 print( \"File already exists\" )\
9079 return\
9080 end\
9081\
9082 -- GET the contents from pastebin\
9083 local res = get(sCode)\
9084 if res then\
9085 local file = fs.open( sPath, \"w\" )\
9086 file.write( res )\
9087 file.close()\
9088\
9089 print( \"Downloaded as \"..sFile )\
9090 end\
9091elseif sCommand == \"run\" then\
9092 local sCode = tArgs[2]\
9093\
9094 local res = get(sCode)\
9095 if res then\
9096 local func, err = load(res, sCode, \"t\", _ENV)\
9097 if not func then\
9098 printError( err )\
9099 return\
9100 end\
9101 local success, msg = pcall(func, select(3, ...))\
9102 if not success then\
9103 printError( msg )\
9104 end\
9105 end\
9106else\
9107 printUsage()\
9108 return\
9109end",
9110 [ "help/programs.txt" ] = "programs lists all the programs on the rom of the computer.",
9111 [ "programs/peripherals.lua" ] = "local tPeripherals = peripheral.getNames()\
9112print( \"Attached Peripherals:\" )\
9113if #tPeripherals > 0 then\
9114 for n=1,#tPeripherals do\
9115 local sPeripheral = tPeripherals[n]\
9116 print( sPeripheral .. \" (\" .. peripheral.getType( sPeripheral ) .. \")\" )\
9117 end\
9118else\
9119 print( \"None\" )\
9120end",
9121 [ "programs/fun/advanced/levels/2.dat" ] = "1\
9122777777777\
91237888888b7\
9124787778887\
9125787 78777\
91267877787\
91277888887\
91287777787\
9129 707\
9130 777",
9131 [ "programs/fun/worm.lua" ] = "\
9132-- Display the start screen\
9133local w,h = term.getSize()\
9134\
9135local titleColour, headingColour, textColour, wormColour, fruitColour\
9136if term.isColour() then\
9137 titleColour = colours.red\
9138 headingColour = colours.yellow\
9139 textColour = colours.white\
9140 wormColour = colours.green\
9141 fruitColour = colours.red\
9142else\
9143 titleColour = colours.white\
9144 headingColour = colours.white\
9145 textColour = colours.white\
9146 wormColour = colours.white\
9147 fruitColour = colours.white\
9148end\
9149\
9150local function printCentred( y, s )\
9151 local x = math.floor((w - string.len(s)) / 2)\
9152 term.setCursorPos(x,y)\
9153 --term.clearLine()\
9154 term.write( s )\
9155end\
9156\
9157local xVel,yVel = 1,0\
9158local xPos, yPos = math.floor(w/2), math.floor(h/2)\
9159local pxVel, pyVel = nil, nil\
9160\
9161local nLength = 1\
9162local nExtraLength = 6\
9163local bRunning = true\
9164\
9165local tailX,tailY = xPos,yPos\
9166local nScore = 0\
9167local nDifficulty = 2\
9168local nSpeed, nInterval\
9169\
9170-- Setup the screen\
9171local screen = {}\
9172for x=1,w do\
9173 screen[x] = {}\
9174 for y=1,h do\
9175 screen[x][y] = {}\
9176 end\
9177end\
9178screen[xPos][yPos] = { snake = true }\
9179\
9180local nFruit = 1\
9181local tFruits = {\
9182 \"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\",\
9183 \"I\", \"J\", \"K\", \"L\", \"M\", \"N\", \"O\", \"P\",\
9184 \"Q\", \"R\", \"S\", \"T\", \"U\", \"V\", \"W\", \"X\",\
9185 \"Y\", \"Z\",\
9186 \"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\",\
9187 \"i\", \"j\", \"k\", \"l\", \"m\", \"n\", \"o\", \"p\",\
9188 \"q\", \"r\", \"s\", \"t\", \"u\", \"v\", \"w\", \"x\",\
9189 \"y\", \"z\",\
9190 \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"0\",\
9191 \"@\", \"$\", \"%\", \"#\", \"&\", \"!\", \"?\", \"+\", \"*\", \"~\"\
9192}\
9193\
9194local function addFruit()\
9195 while true do\
9196 local x = math.random(1,w)\
9197 local y = math.random(2,h)\
9198 local fruit = screen[x][y]\
9199 if fruit.snake == nil and fruit.wall == nil and fruit.fruit == nil then\
9200 screen[x][y] = { fruit = true }\
9201 term.setCursorPos(x,y)\
9202 term.setBackgroundColour( fruitColour )\
9203 term.write(\" \")\
9204 term.setBackgroundColour( colours.black )\
9205 break\
9206 end\
9207 end\
9208\
9209 nFruit = nFruit + 1\
9210 if nFruit > #tFruits then\
9211 nFruit = 1\
9212 end\
9213end\
9214\
9215local function drawMenu()\
9216 term.setTextColour( headingColour )\
9217 term.setCursorPos(1,1)\
9218 term.write( \"SCORE \" )\
9219\
9220 term.setTextColour( textColour )\
9221 term.setCursorPos(7,1)\
9222 term.write( tostring(nScore) )\
9223\
9224 term.setTextColour( headingColour )\
9225 term.setCursorPos(w-11,1)\
9226 term.write( \"DIFFICULTY \")\
9227\
9228 term.setTextColour( textColour )\
9229 term.setCursorPos(w,1)\
9230 term.write( tostring(nDifficulty or \"?\") )\
9231\
9232 term.setTextColour( colours.white )\
9233end\
9234\
9235local function update( )\
9236 local x,y = xPos,yPos\
9237 if pxVel and pyVel then\
9238 xVel, yVel = pxVel, pyVel\
9239 pxVel, pyVel = nil, nil\
9240 end\
9241\
9242 -- Remove the tail\
9243 if nExtraLength == 0 then\
9244 local tail = screen[tailX][tailY]\
9245 screen[tailX][tailY] = {}\
9246 term.setCursorPos(tailX,tailY)\
9247 term.write(\" \")\
9248 tailX = tail.nextX\
9249 tailY = tail.nextY\
9250 else\
9251 nExtraLength = nExtraLength - 1\
9252 end\
9253\
9254 -- Update the head\
9255 local head = screen[xPos][yPos]\
9256 local newXPos = xPos + xVel\
9257 local newYPos = yPos + yVel\
9258 if newXPos < 1 then\
9259 newXPos = w\
9260 elseif newXPos > w then\
9261 newXPos = 1\
9262 end\
9263 if newYPos < 2 then\
9264 newYPos = h\
9265 elseif newYPos > h then\
9266 newYPos = 2\
9267 end\
9268\
9269 local newHead = screen[newXPos][newYPos]\
9270 if newHead.snake == true or newHead.wall == true then\
9271 bRunning = false\
9272\
9273 else\
9274 if newHead.fruit == true then\
9275 nScore = nScore + 10\
9276 nExtraLength = nExtraLength + 1\
9277 addFruit()\
9278 end\
9279 xPos = newXPos\
9280 yPos = newYPos\
9281 head.nextX = newXPos\
9282 head.nextY = newYPos\
9283 screen[newXPos][newYPos] = { snake = true }\
9284\
9285 end\
9286\
9287 term.setCursorPos(xPos,yPos)\
9288 term.setBackgroundColour( wormColour )\
9289 term.write(\" \")\
9290 term.setBackgroundColour( colours.black )\
9291\
9292 drawMenu()\
9293end\
9294\
9295-- Display the frontend\
9296term.clear()\
9297local function drawFrontend()\
9298 --term.setTextColour( titleColour )\
9299 --printCentred( math.floor(h/2) - 4, \" W O R M \" )\
9300\
9301 term.setTextColour( headingColour )\
9302 printCentred( math.floor(h/2) - 3, \"\" )\
9303 printCentred( math.floor(h/2) - 2, \" SELECT DIFFICULTY \" )\
9304 printCentred( math.floor(h/2) - 1, \"\" )\
9305\
9306 printCentred( math.floor(h/2) + 0, \" \" )\
9307 printCentred( math.floor(h/2) + 1, \" \" )\
9308 printCentred( math.floor(h/2) + 2, \" \" )\
9309 printCentred( math.floor(h/2) - 1 + nDifficulty, \" [ ] \" )\
9310\
9311 term.setTextColour( textColour )\
9312 printCentred( math.floor(h/2) + 0, \"EASY\" )\
9313 printCentred( math.floor(h/2) + 1, \"MEDIUM\" )\
9314 printCentred( math.floor(h/2) + 2, \"HARD\" )\
9315 printCentred( math.floor(h/2) + 3, \"\" )\
9316\
9317 term.setTextColour( colours.white )\
9318end\
9319\
9320drawMenu()\
9321drawFrontend()\
9322while true do\
9323 local e,key = os.pullEvent( \"key\" )\
9324 if key == keys.up or key == keys.w then\
9325 -- Up\
9326 if nDifficulty > 1 then\
9327 nDifficulty = nDifficulty - 1\
9328 drawMenu()\
9329 drawFrontend()\
9330 end\
9331 elseif key == keys.down or key == keys.s then\
9332 -- Down\
9333 if nDifficulty < 3 then\
9334 nDifficulty = nDifficulty + 1\
9335 drawMenu()\
9336 drawFrontend()\
9337 end\
9338 elseif key == keys.enter then\
9339 -- Enter\
9340 break\
9341 end\
9342end\
9343\
9344local tSpeeds = { 5, 10, 25 }\
9345nSpeed = tSpeeds[nDifficulty]\
9346nInterval = 1 / nSpeed\
9347\
9348-- Grow the snake to its intended size\
9349term.clear()\
9350drawMenu()\
9351screen[tailX][tailY].snake = true\
9352while nExtraLength > 0 do\
9353 update()\
9354end\
9355addFruit()\
9356addFruit()\
9357\
9358-- Play the game\
9359local timer = os.startTimer(0)\
9360while bRunning do\
9361 local event, p1, p2 = os.pullEvent()\
9362 if event == \"timer\" and p1 == timer then\
9363 timer = os.startTimer(nInterval)\
9364 update( false )\
9365\
9366 elseif event == \"key\" then\
9367 local key = p1\
9368 if key == keys.up or key == keys.w then\
9369 -- Up\
9370 if yVel == 0 then\
9371 pxVel,pyVel = 0,-1\
9372 end\
9373 elseif key == keys.down or key == keys.s then\
9374 -- Down\
9375 if yVel == 0 then\
9376 pxVel,pyVel = 0,1\
9377 end\
9378 elseif key == keys.left or key == keys.a then\
9379 -- Left\
9380 if xVel == 0 then\
9381 pxVel,pyVel = -1,0\
9382 end\
9383\
9384 elseif key == keys.right or key == keys.d then\
9385 -- Right\
9386 if xVel == 0 then\
9387 pxVel,pyVel = 1,0\
9388 end\
9389\
9390 end\
9391 end\
9392end\
9393\
9394-- Display the gameover screen\
9395term.setTextColour( headingColour )\
9396printCentred( math.floor(h/2) - 2, \" \" )\
9397printCentred( math.floor(h/2) - 1, \" G A M E O V E R \" )\
9398\
9399term.setTextColour( textColour )\
9400printCentred( math.floor(h/2) + 0, \" \" )\
9401printCentred( math.floor(h/2) + 1, \" FINAL SCORE \"..nScore..\" \" )\
9402printCentred( math.floor(h/2) + 2, \" \" )\
9403term.setTextColour( colours.white )\
9404\
9405local timer = os.startTimer(2.5)\
9406repeat\
9407 local e,p = os.pullEvent()\
9408 if e == \"timer\" and p == timer then\
9409 term.setTextColour( textColour )\
9410 printCentred( math.floor(h/2) + 2, \" PRESS ANY KEY \" )\
9411 printCentred( math.floor(h/2) + 3, \" \" )\
9412 term.setTextColour( colours.white )\
9413 end\
9414until e == \"char\"\
9415\
9416term.clear()\
9417term.setCursorPos(1,1)",
9418 [ "programs/fun/hello.lua" ] = "if term.isColour() then\
9419 term.setTextColour( 2^math.random(0,15) )\
9420end\
9421textutils.slowPrint( \"Hello World!\" )\
9422term.setTextColour( colours.white )",
9423 [ "programs/fun/dj.lua" ] = "local tArgs = { ... }\
9424\
9425local function printUsage()\
9426 print( \"Usages:\")\
9427 print( \"dj play\" )\
9428 print( \"dj play <drive>\" )\
9429 print( \"dj stop\" )\
9430end\
9431\
9432if #tArgs > 2 then\
9433 printUsage()\
9434 return\
9435end\
9436\
9437local sCommand = tArgs[1]\
9438if sCommand == \"stop\" then\
9439 -- Stop audio\
9440 disk.stopAudio()\
9441\
9442elseif sCommand == \"play\" or sCommand == nil then\
9443 -- Play audio\
9444 local sName = tArgs[2]\
9445 if sName == nil then\
9446 -- No disc specified, pick one at random\
9447 local tNames = {}\
9448 for n,sName in ipairs( peripheral.getNames() ) do\
9449 if disk.isPresent( sName ) and disk.hasAudio( sName ) then\
9450 table.insert( tNames, sName )\
9451 end\
9452 end\
9453 if #tNames == 0 then\
9454 print( \"No Music Discs in attached disk drives\" )\
9455 return\
9456 end\
9457 sName = tNames[ math.random(1,#tNames) ]\
9458 end\
9459\
9460 -- Play the disc\
9461 if disk.isPresent( sName ) and disk.hasAudio( sName ) then\
9462 print( \"Playing \"..disk.getAudioTitle( sName ) )\
9463 disk.playAudio( sName )\
9464 else\
9465 print( \"No Music Disc in disk drive: \"..sName )\
9466 return\
9467 end\
9468\
9469else\
9470 printUsage()\
9471\
9472end",
9473 [ "help/disk.txt" ] = "Functions in the disk API. These functions are for interacting with disk drives:\
9474disk.isPresent( drive )\
9475disk.setLabel( drive, label )\
9476disk.getLabel( drive )\
9477disk.hasData( drive )\
9478disk.getMountPath( drive )\
9479disk.hasAudio( drive )\
9480disk.getAudioTitle( drive )\
9481disk.playAudio( drive )\
9482disk.stopAudio( )\
9483disk.eject( drive )\
9484disk.getID( drive )\
9485\
9486Events fired by the disk API:\
9487\"disk\" when a disk or other item is inserted into a disk drive. Argument is the name of the drive\
9488\"disk_eject\" when a disk is removed from a disk drive. Argument is the name of the drive\
9489Type \"help events\" to learn about the event system.",
9490 [ "programs/fun/advanced/levels/5.dat" ] = "3\
9491777777777\
9492788888887\
9493787787787\
9494787787787\
9495788888887\
9496787787787\
9497787787787\
949878e748887\
9499777777777",
9500 [ "help/credits.txt" ] = "\
9501ComputerCraft was created by Daniel \"dan200\" Ratcliffe, with additional code by Aaron \"Cloudy\" Mills.\
9502Thanks to nitrogenfingers, GopherATL and RamiLego for program contributions.\
9503Thanks to Mojang, the Forge team, and the MCP team.\
9504Uses LuaJ from http://luaj.sourceforge.net/\
9505\
9506The ComputerCraft 1.76 update was sponsored by MinecraftU and Deep Space.\
9507Visit http://www.minecraftu.org and http://www.deepspace.me/space-cadets to find out more.\
9508\
9509Join the ComputerCraft community online at http://www.computercraft.info\
9510Follow @DanTwoHundred on Twitter!\
9511\
9512To help contribute to ComputerCraft, browse the source code at https://github.com/dan200/ComputerCraft.\
9513\
9514GitHub Contributors:\
9515apemanzilla\
9516Bartek Bok\
9517Bomb Bloke\
9518CrazedProgrammer\
9519Cruor\
9520Drew Lemmy\
9521gegy1000\
9522hugeblank\
9523hydraz\
9524Jonathan Leitschuh\
9525Joseph C. Sible\
9526KingofGamesYami\
9527Lignum\
9528Logan Davis\
9529Luca S\
9530MineRobber___T\
9531Nephi (AKA Lupus590)\
9532ObloxCC\
9533Oliver Marks\
9534Restioson\
9535SquidDev\
9536Steven Dirth\
9537theoriginalbit\
9538Tim Ittermann\
9539Vexatos\
9540Wilma456\
9541Wilma456 (Jakob0815)\
9542Wojbie",
9543 [ "programs/gps.lua" ] = "\
9544local function printUsage()\
9545 print( \"Usages:\" )\
9546 print( \"gps host\" )\
9547 print( \"gps host <x> <y> <z>\" )\
9548 print( \"gps locate\" )\
9549end\
9550\
9551local tArgs = { ... }\
9552if #tArgs < 1 then\
9553 printUsage()\
9554 return\
9555end\
9556\
9557 local sCommand = tArgs[1]\
9558if sCommand == \"locate\" then\
9559 -- \"gps locate\"\
9560 -- Just locate this computer (this will print the results)\
9561 gps.locate( 2, true )\
9562\
9563elseif sCommand == \"host\" then\
9564 -- \"gps host\"\
9565 -- Act as a GPS host\
9566 if pocket then\
9567 print( \"GPS Hosts must be stationary\" )\
9568 return\
9569 end\
9570\
9571 -- Find a modem\
9572 local sModemSide = nil\
9573 for n,sSide in ipairs( rs.getSides() ) do\
9574 if peripheral.getType( sSide ) == \"modem\" and peripheral.call( sSide, \"isWireless\" ) then\
9575 sModemSide = sSide\
9576 break\
9577 end\
9578 end\
9579\
9580 if sModemSide == nil then\
9581 print( \"No wireless modems found. 1 required.\" )\
9582 return\
9583 end\
9584\
9585 -- Determine position\
9586 local x,y,z\
9587 if #tArgs >= 4 then\
9588 -- Position is manually specified\
9589 x = tonumber(tArgs[2])\
9590 y = tonumber(tArgs[3])\
9591 z = tonumber(tArgs[4])\
9592 if x == nil or y == nil or z == nil then\
9593 printUsage()\
9594 return\
9595 end\
9596 print( \"Position is \"..x..\",\"..y..\",\"..z )\
9597 else\
9598 -- Position is to be determined using locate\
9599 x,y,z = gps.locate( 2, true )\
9600 if x == nil then\
9601 print( \"Run \\\"gps host <x> <y> <z>\\\" to set position manually\" )\
9602 return\
9603 end\
9604 end\
9605\
9606 -- Open a channel\
9607 local modem = peripheral.wrap( sModemSide )\
9608 print( \"Opening channel on modem \"..sModemSide )\
9609 modem.open( gps.CHANNEL_GPS )\
9610\
9611 -- Serve requests indefinately\
9612 local nServed = 0\
9613 while true do\
9614 local e, p1, p2, p3, p4, p5 = os.pullEvent( \"modem_message\" )\
9615 if e == \"modem_message\" then\
9616 -- We received a message from a modem\
9617 local sSide, sChannel, sReplyChannel, sMessage, nDistance = p1, p2, p3, p4, p5\
9618 if sSide == sModemSide and sChannel == gps.CHANNEL_GPS and sMessage == \"PING\" and nDistance then\
9619 -- We received a ping message on the GPS channel, send a response\
9620 modem.transmit( sReplyChannel, gps.CHANNEL_GPS, { x, y, z } )\
9621\
9622 -- Print the number of requests handled\
9623 nServed = nServed + 1\
9624 if nServed > 1 then\
9625 local x,y = term.getCursorPos()\
9626 term.setCursorPos(1,y-1)\
9627 end\
9628 print( nServed..\" GPS requests served\" )\
9629 end\
9630 end\
9631 end\
9632else\
9633 -- \"gps somethingelse\"\
9634 -- Error\
9635 printUsage()\
9636end",
9637 [ "programs/fun/advanced/levels/12.dat" ] = "6\
963877 777 77\
963972888888897\
9640 8 8 8\
9641 8 8b888 8\
964278 e8888 87\
964378888788887\
964478 8888e 87\
9645 8 888b8 8\
9646 8 8 8\
964775888888807\
964877 777 77",
9649 [ "programs/help.lua" ] = "local tArgs = { ... }\
9650local sTopic\
9651if #tArgs > 0 then\
9652 sTopic = tArgs[1]\
9653else\
9654 sTopic = \"intro\"\
9655end\
9656\
9657if sTopic == \"index\" then\
9658 print( \"Help topics availiable:\" )\
9659 local tTopics = help.topics()\
9660 textutils.pagedTabulate( tTopics )\
9661 return\
9662end\
9663\
9664local sFile = help.lookup( sTopic )\
9665local file = ((sFile ~= nil) and io.open( sFile )) or nil\
9666if file then\
9667 local sContents = file:read(\"*a\")\
9668 file:close()\
9669\
9670 local _, nHeight = term.getSize()\
9671 textutils.pagedPrint( sContents, nHeight - 3 )\
9672else\
9673 print( \"No help available\" )\
9674end",
9675 [ "help/label.txt" ] = "label gets or sets the label of the Computer, or of Floppy Disks in attached disk drives.\
9676\
9677ex:\
9678\"label get\" prints the label of the computer.\
9679\"label get left\" prints the label of the disk in the left drive.\
9680\"label set \"My Computer\"\" set the label of the computer to \"My Computer\".\
9681\"label set left \"My Programs\"\" - sets the label of the disk in the left drive to \"My Programs\".\
9682\"label clear\" clears the label of the computer.\
9683\"label clear left\" clears the label of the disk in the left drive.",
9684 [ "programs/pocket/falling.lua" ] = "--[[\
9685Falling - Based on Tetris by Alexey Pajitnov\
9686This version written by Gopher, at the request of Dan200, for\
9687ComputerCraft v1.6. No particular rights are reserved.\
9688--]]\
9689\
9690local function colorass(c,bw)\
9691 return term.isColor() and c or bw\
9692end\
9693\
9694local block_s1= {\
9695 {\
9696 { 1,0,0,0, },\
9697 { 1,1,0,0, },\
9698 { 0,1,0,0, },\
9699 { 0,0,0,0, },\
9700 },\
9701 {\
9702 { 0,0,0,0, },\
9703 { 0,1,1,0, },\
9704 { 1,1,0,0, },\
9705 { 0,0,0,0, },\
9706 },\
9707 ch=colorass(\" \",\"{}\"),\
9708 fg=colorass(colors.blue,colors.black),\
9709 bg=colorass(colors.cyan,colors.white),\
9710 }\
9711local block_s2= {\
9712 {\
9713 { 0,1,0,0, },\
9714 { 1,1,0,0, },\
9715 { 1,0,0,0, },\
9716 { 0,0,0,0, },\
9717 },\
9718 {\
9719 { 0,0,0,0, },\
9720 { 1,1,0,0, },\
9721 { 0,1,1,0, },\
9722 { 0,0,0,0, },\
9723 },\
9724 ch=colorass(\" \",\"{}\"),\
9725 fg=colorass(colors.green,colors.black),\
9726 bg=colorass(colors.lime,colors.white),\
9727 }\
9728local block_line = {\
9729 {\
9730 { 0,1,0,0, },\
9731 { 0,1,0,0, },\
9732 { 0,1,0,0, },\
9733 { 0,1,0,0, },\
9734 },\
9735 {\
9736 { 0,0,0,0, },\
9737 { 1,1,1,1, },\
9738 { 0,0,0,0, },\
9739 { 0,0,0,0, },\
9740 },\
9741 ch=colorass(\" \",\"[]\"),\
9742 fg=colorass(colors.pink,colors.black),\
9743 bg=colorass(colors.red,colors.white),\
9744 }\
9745local block_square = {\
9746 {\
9747 { 1,1,0,0, },\
9748 { 1,1,0,0, },\
9749 { 0,0,0,0, },\
9750 { 0,0,0,0, },\
9751 },\
9752 ch=colorass(\" \",\"[]\"),\
9753 fg=colorass(colors.lightBlue,colors.black),\
9754 bg=colorass(colors.blue,colors.white),\
9755 }\
9756local block_L1 = {\
9757 {\
9758 { 1,1,0,0, },\
9759 { 0,1,0,0, },\
9760 { 0,1,0,0, },\
9761 { 0,0,0,0, },\
9762 },\
9763 {\
9764 { 0,0,0,0, },\
9765 { 1,1,1,0, },\
9766 { 1,0,0,0, },\
9767 { 0,0,0,0, },\
9768 },\
9769 {\
9770 { 0,1,0,0, },\
9771 { 0,1,0,0, },\
9772 { 0,1,1,0, },\
9773 { 0,0,0,0, },\
9774 },\
9775 {\
9776 { 0,0,1,0, },\
9777 { 1,1,1,0, },\
9778 { 0,0,0,0, },\
9779 { 0,0,0,0, },\
9780 },\
9781 ch=colorass(\" \",\"()\"),\
9782 fg=colorass(colors.orange,colors.black),\
9783 bg=colorass(colors.yellow,colors.white),\
9784 }\
9785local block_L2 = {\
9786 {\
9787 { 0,1,0,0, },\
9788 { 0,1,0,0, },\
9789 { 1,1,0,0, },\
9790 { 0,0,0,0, },\
9791 },\
9792 {\
9793 { 0,0,0,0, },\
9794 { 1,1,1,0, },\
9795 { 0,0,1,0, },\
9796 { 0,0,0,0, },\
9797 },\
9798 {\
9799 { 0,1,1,0, },\
9800 { 0,1,0,0, },\
9801 { 0,1,0,0, },\
9802 { 0,0,0,0, },\
9803 },\
9804 {\
9805 { 1,0,0,0, },\
9806 { 1,1,1,0, },\
9807 { 0,0,0,0, },\
9808 { 0,0,0,0, },\
9809 },\
9810 ch=colorass(\" \",\"()\"),\
9811 fg=colorass(colors.brown,colors.black),\
9812 bg=colorass(colors.orange,colors.white),\
9813 }\
9814local block_T = {\
9815 {\
9816 { 0,1,0,0, },\
9817 { 1,1,0,0, },\
9818 { 0,1,0,0, },\
9819 { 0,0,0,0, },\
9820 },\
9821 {\
9822 { 0,0,0,0, },\
9823 { 1,1,1,0, },\
9824 { 0,1,0,0, },\
9825 { 0,0,0,0, },\
9826 },\
9827 {\
9828 { 0,1,0,0, },\
9829 { 0,1,1,0, },\
9830 { 0,1,0,0, },\
9831 { 0,0,0,0, },\
9832 },\
9833 {\
9834 { 0,1,0,0, },\
9835 { 1,1,1,0, },\
9836 { 0,0,0,0, },\
9837 { 0,0,0,0, },\
9838 },\
9839 ch=colorass(\" \",\"<>\"),\
9840 fg=colorass(colors.cyan,colors.black),\
9841 bg=colorass(colors.purple,colors.white),\
9842 }\
9843\
9844local blocks={ block_line, block_square, block_s1, block_s2, block_L1, block_L2, block_T}\
9845\
9846local points={4,10,30,120}\
9847\
9848local function lpad(text,amt)\
9849 text=tostring(text)\
9850 return string.rep(\" \",amt-#text)..text\
9851end\
9852\
9853local width,height=term.getSize()\
9854\
9855if height<19 or width<26 then\
9856 print(\"Your screen is too small to play :(\")\
9857 return\
9858end\
9859\
9860\
9861local speedsByLevel={\
9862 1.2,\
9863 1.0,\
9864 .8,\
9865 .65,\
9866 .5,\
9867 .4,\
9868 .3,\
9869 .25,\
9870 .2,\
9871 .15,\
9872 .1,\
9873 .05,}\
9874\
9875local level=1\
9876\
9877local function playGame()\
9878 local score=0\
9879 local lines=0\
9880 local initialLevel=level\
9881 local next=blocks[math.random(1,#blocks)]\
9882\
9883 local pit={}\
9884\
9885\
9886 local heightAdjust=0\
9887\
9888 if height<=19 then\
9889 heightAdjust=1\
9890 end\
9891\
9892\
9893\
9894 local function drawScreen()\
9895 term.setTextColor(colors.white)\
9896 term.setBackgroundColor(colors.black)\
9897 term.clear()\
9898\
9899 term.setTextColor(colors.black)\
9900 term.setBackgroundColor(colorass(colors.lightGray, colors.white))\
9901 term.setCursorPos(22,2)\
9902 term.write(\"Score\") --score\
9903 term.setCursorPos(22,5)\
9904 term.write(\"Level\") --level\
9905 term.setCursorPos(22,8)\
9906 term.write(\"Lines\") --lines\
9907 term.setCursorPos(22,12)\
9908 term.write(\"Next\") --next\
9909\
9910 term.setCursorPos(21,1)\
9911 term.write(\" \")\
9912 term.setCursorPos(21,2)\
9913 term.write(\" \") --score\
9914 term.setCursorPos(21,3)\
9915 term.write(\" \")\
9916 term.setCursorPos(21,4)\
9917 term.write(\" \")\
9918 term.setCursorPos(21,5)\
9919 term.write(\" \") --level\
9920 term.setCursorPos(21,6)\
9921 term.write(\" \")\
9922 term.setCursorPos(21,7)\
9923 term.write(\" \")\
9924 term.setCursorPos(21,8)\
9925 term.write(\" \") --lines\
9926 term.setCursorPos(21,9)\
9927 term.write(\" \")\
9928 term.setCursorPos(21,10)\
9929 term.write(\" \")\
9930 term.setCursorPos(21,11)\
9931 term.write(\" \")\
9932 term.setCursorPos(21,12)\
9933 term.write(\" \") --next\
9934 term.setCursorPos(26,12)\
9935 term.write(\" \") --next\
9936 term.setCursorPos(21,13)\
9937 term.write(\" \")\
9938 term.setCursorPos(21,14)\
9939 term.write(\" \")\
9940 term.setCursorPos(21,15)\
9941 term.write(\" \")\
9942 term.setCursorPos(21,16)\
9943 term.write(\" \")\
9944 term.setCursorPos(21,17)\
9945 term.write(\" \")\
9946 term.setCursorPos(21,18)\
9947 term.write(\" \")\
9948 term.setCursorPos(21,19)\
9949 term.write(\" \")\
9950 term.setCursorPos(21,20)\
9951 term.write(\" \")\
9952 end\
9953\
9954 local function updateNumbers()\
9955 term.setTextColor(colors.white)\
9956 term.setBackgroundColor(colors.black)\
9957\
9958 term.setCursorPos(22,3)\
9959 term.write(lpad(score,5)) --score\
9960 term.setCursorPos(22,6)\
9961 term.write(lpad(level,5)) --level\
9962 term.setCursorPos(22,9)\
9963 term.write(lpad(lines,5)) --lines\
9964 end\
9965\
9966 local function drawBlockAt(block,xp,yp,rot)\
9967 term.setTextColor(block.fg)\
9968 term.setBackgroundColor(block.bg)\
9969 for y=1,4 do\
9970 for x=1,4 do\
9971 if block[rot][y][x]==1 then\
9972 term.setCursorPos((xp+x)*2-3,yp+y-1-heightAdjust)\
9973 term.write(block.ch)\
9974 end\
9975 end\
9976 end\
9977 end\
9978\
9979 local function eraseBlockAt(block,xp,yp,rot)\
9980 term.setTextColor(colors.white)\
9981 term.setBackgroundColor(colors.black)\
9982 for y=1,4 do\
9983 for x=1,4 do\
9984 if block[rot][y][x]==1 then\
9985 term.setCursorPos((xp+x)*2-3,yp+y-1-heightAdjust)\
9986 term.write(\" \")\
9987 end\
9988 end\
9989 end\
9990 end\
9991\
9992 local function testBlockAt(block,xp,yp,rot)\
9993 for y=1,4 do\
9994 local ty=yp+y-1\
9995 for x=1,4 do\
9996 local tx=xp+x-1\
9997 if block[rot][y][x]==1 then\
9998 if tx>10 or tx<1 or ty>20 or pit[ty][tx]~=0 then\
9999 return true\
10000 end\
10001 end\
10002 end\
10003 end\
10004 end\
10005\
10006 local function pitBlock(block,xp,yp,rot)\
10007 for y=1,4 do\
10008 for x=1,4 do\
10009 if block[rot][y][x]==1 then\
10010 pit[yp+y-1][xp+x-1]=block\
10011 end\
10012 end\
10013 end\
10014 end\
10015\
10016\
10017 local function clearPit()\
10018 for row=1,20 do\
10019 pit[row]={}\
10020 for col=1,10 do\
10021 pit[row][col]=0\
10022 end\
10023 end\
10024 end\
10025\
10026\
10027\
10028 drawScreen()\
10029 updateNumbers()\
10030\
10031 --declare & init the pit\
10032 clearPit()\
10033\
10034\
10035\
10036 local halt=false\
10037 local dropSpeed=speedsByLevel[math.min(level,12)]\
10038\
10039\
10040 local curBlock=next\
10041 next=blocks[math.random(1,7)]\
10042\
10043 local curX, curY, curRot=4, 1, 1\
10044 local dropTimer=os.startTimer(dropSpeed)\
10045\
10046 drawBlockAt(next,11.5,15+heightAdjust,1)\
10047 drawBlockAt(curBlock,curX,curY,curRot)\
10048\
10049 local function redrawPit()\
10050 for r=1+heightAdjust,20 do\
10051 term.setCursorPos(1,r-heightAdjust)\
10052 for c=1,10 do\
10053 if pit[r][c]==0 then\
10054 term.setTextColor(colors.black)\
10055 term.setBackgroundColor(colors.black)\
10056 term.write(\" \")\
10057 else\
10058 term.setTextColor(pit[r][c].fg)\
10059 term.setBackgroundColor(pit[r][c].bg)\
10060 term.write(pit[r][c].ch)\
10061 end\
10062 end\
10063 end\
10064 end\
10065\
10066 local function hidePit()\
10067 for r=1+heightAdjust,20 do\
10068 term.setCursorPos(1,r-heightAdjust)\
10069 term.setTextColor(colors.black)\
10070 term.setBackgroundColor(colors.black)\
10071 term.write(\" \")\
10072 end\
10073 end\
10074\
10075 local function msgBox(message)\
10076 local x=math.floor((17-#message)/2)\
10077 term.setBackgroundColor(colorass(colors.lightGray,colors.white))\
10078 term.setTextColor(colors.black)\
10079 term.setCursorPos(x,9)\
10080 term.write(\"+\"..string.rep(\"-\",#message+2)..\"+\")\
10081 term.setCursorPos(x,10)\
10082 term.write(\"|\")\
10083 term.setCursorPos(x+#message+3,10)\
10084 term.write(\"|\")\
10085 term.setCursorPos(x,11)\
10086 term.write(\"+\"..string.rep(\"-\",#message+2)..\"+\")\
10087 term.setTextColor(colors.white)\
10088 term.setBackgroundColor(colors.black)\
10089 term.setCursorPos(x+1,10)\
10090 term.write(\" \"..message..\" \")\
10091 end\
10092\
10093 local function clearRows()\
10094 local rows={}\
10095 for r=1,20 do\
10096 local count=0\
10097 for c=1,10 do\
10098 if pit[r][c]~=0 then\
10099 count=count+1\
10100 else\
10101 break\
10102 end\
10103 end\
10104 if count==10 then\
10105 rows[#rows+1]=r\
10106 end\
10107 end\
10108\
10109 if #rows>0 then\
10110 for i=1,4 do\
10111 sleep(.1)\
10112 for r=1,#rows do\
10113 r=rows[r]\
10114 term.setCursorPos(1,r-heightAdjust)\
10115 for c=1,10 do\
10116 term.setTextColor(pit[r][c].bg)\
10117 term.setBackgroundColor(pit[r][c].fg)\
10118 term.write(pit[r][c].ch)\
10119 end\
10120 end\
10121 sleep(.1)\
10122 for r=1,#rows do\
10123 r=rows[r]\
10124 term.setCursorPos(1,r-heightAdjust)\
10125 for c=1,10 do\
10126 term.setTextColor(pit[r][c].fg)\
10127 term.setBackgroundColor(pit[r][c].bg)\
10128 term.write(pit[r][c].ch)\
10129 end\
10130 end\
10131 end\
10132 --now remove the rows and drop everythign else\
10133 term.setBackgroundColor(colors.black)\
10134 for r=1,#rows do\
10135 r=rows[r]\
10136 term.setCursorPos(1,r-heightAdjust)\
10137 term.write(\" \")\
10138 end\
10139 sleep(.25)\
10140 for r=1,#rows do\
10141 table.remove(pit,rows[r])\
10142 table.insert(pit,1,{0,0,0,0,0,0,0,0,0,0})\
10143 end\
10144 redrawPit()\
10145 lines=lines+#rows\
10146 score=score+points[#rows]*math.min(level,20)\
10147 level=math.floor(lines/10)+initialLevel\
10148 dropSpeed=speedsByLevel[math.min(level,12)]\
10149 updateNumbers()\
10150 end\
10151 sleep(.25)\
10152 end\
10153\
10154 local function blockFall()\
10155 local result = false\
10156 if testBlockAt(curBlock,curX,curY+1,curRot) then\
10157 pitBlock(curBlock,curX,curY,curRot)\
10158 --detect rows that clear\
10159 clearRows()\
10160\
10161 curBlock=next\
10162 curX=4\
10163 curY=1\
10164 curRot=1\
10165 if testBlockAt(curBlock,curX,curY,curRot) then\
10166 halt=true\
10167 end\
10168 drawBlockAt(curBlock,curX,curY,curRot)\
10169 eraseBlockAt(next,11.5,15+heightAdjust,1)\
10170 next=blocks[math.random(1,7)]\
10171 drawBlockAt(next,11.5,15+heightAdjust,1)\
10172 return true\
10173 else\
10174 eraseBlockAt(curBlock,curX,curY,curRot)\
10175 curY=curY+1\
10176 drawBlockAt(curBlock,curX,curY,curRot)\
10177 return false\
10178 end\
10179 end\
10180\
10181\
10182 while not halt do\
10183 local e={os.pullEvent()}\
10184 if e[1]==\"timer\" then\
10185 if e[2]==dropTimer then\
10186 blockFall()\
10187 dropTimer=os.startTimer(dropSpeed)\
10188 end\
10189 elseif e[1]==\"key\" then\
10190 local key=e[2]\
10191 local dx,dy,dr=0,0,0\
10192 if key==keys.left or key==keys.a then\
10193 dx=-1\
10194 elseif key==keys.right or key==keys.d then\
10195 dx=1\
10196 elseif key==keys.up or key==keys.w then\
10197 dr=1\
10198 elseif key==keys.down or key==keys.s then\
10199 while not blockFall() do end\
10200 dropTimer=os.startTimer(dropSpeed)\
10201 elseif key==keys.space then\
10202 hidePit()\
10203 msgBox(\"Paused\")\
10204 while ({os.pullEvent(\"key\")})[2]~=keys.space do end\
10205 redrawPit()\
10206 drawBlockAt(curBlock,curX,curY,curRot)\
10207 dropTimer=os.startTimer(dropSpeed)\
10208 end\
10209 if dx+dr~=0 then\
10210 if not testBlockAt(curBlock,curX+dx,curY+dy,(dr>0 and curRot%#curBlock+dr or curRot)) then\
10211 eraseBlockAt(curBlock,curX,curY,curRot)\
10212 curX=curX+dx\
10213 curY=curY+dy\
10214 curRot=dr==0 and curRot or (curRot%#curBlock+dr)\
10215 drawBlockAt(curBlock,curX,curY,curRot)\
10216 end\
10217 end\
10218 elseif e[1]==\"term_resize\" then\
10219 local w,h=term.getSize()\
10220 if h==20 then\
10221 heightAdjust=0\
10222 else\
10223 heightAdjust=1\
10224 end\
10225 redrawPit()\
10226 drawBlockAt(curBlock,curX,curY,curRot)\
10227 end\
10228 end\
10229\
10230 msgBox(\"Game Over!\")\
10231 while true do\
10232 local _,k=os.pullEvent(\"key\")\
10233 if k==keys.space or k==keys.enter then\
10234 break\
10235 end\
10236 end\
10237\
10238 level = math.min(level,9)\
10239end\
10240\
10241\
10242local selected=1\
10243local playersDetected=false\
10244\
10245local function drawMenu()\
10246 term.setBackgroundColor(colors.black)\
10247 term.setTextColor(colorass(colors.red,colors.white))\
10248 term.clear()\
10249\
10250 local cx,cy=math.floor(width/2),math.floor(height/2)\
10251\
10252 term.setCursorPos(cx-6,cy-2)\
10253 term.write(\"F A L L I N G\")\
10254\
10255 if playersDetected then\
10256 if selected==0 then\
10257 term.setTextColor(colorass(colors.blue,colors.black))\
10258 term.setBackgroundColor(colorass(colors.gray,colors.white))\
10259 else\
10260 term.setTextColor(colorass(colors.lightBlue,colors.white))\
10261 term.setBackgroundColor(colors.black)\
10262 end\
10263 term.setCursorPos(cx-12,cy)\
10264 term.write(\" Play head-to-head game! \")\
10265 end\
10266\
10267 term.setCursorPos(cx-10,cy+1)\
10268 if selected==1 then\
10269 term.setTextColor(colorass(colors.blue,colors.black))\
10270 term.setBackgroundColor(colorass(colors.lightGray,colors.white))\
10271 else\
10272 term.setTextColor(colorass(colors.lightBlue,colors.white))\
10273 term.setBackgroundColor(colors.black)\
10274 end\
10275 term.write(\" Play from level: <\" .. level .. \"> \")\
10276\
10277 term.setCursorPos(cx-3,cy+3)\
10278 if selected==2 then\
10279 term.setTextColor(colorass(colors.blue,colors.black))\
10280 term.setBackgroundColor(colorass(colors.lightGray,colors.white))\
10281 else\
10282 term.setTextColor(colorass(colors.lightBlue,colors.white))\
10283 term.setBackgroundColor(colors.black)\
10284 end\
10285 term.write(\" Quit \")\
10286end\
10287\
10288\
10289local function runMenu()\
10290 drawMenu()\
10291\
10292 while true do\
10293 local event={os.pullEvent()}\
10294 if event[1]==\"key\" then\
10295 local key=event[2]\
10296 if key==keys.right or key==keys.d and selected==1 then\
10297 level=math.min(level+1,9)\
10298 drawMenu()\
10299 elseif key==keys.left or key==keys.a and selected==1 then\
10300 level=math.max(level-1,1)\
10301 drawMenu()\
10302 elseif key>=keys.one and key<=keys.nine and selected==1 then\
10303 level=(key-keys.one) + 1\
10304 drawMenu()\
10305 elseif key==keys.up or key==keys.w then\
10306 selected=selected-1\
10307 if selected==0 then\
10308 selected=2\
10309 end\
10310 drawMenu()\
10311 elseif key==keys.down or key==keys.s then\
10312 selected=selected%2+1\
10313 drawMenu()\
10314 elseif key==keys.enter or key==keys.space then\
10315 break --begin play!\
10316 end\
10317 end\
10318 end\
10319end\
10320\
10321while true do\
10322 runMenu()\
10323 if selected==2 then\
10324 break\
10325 end\
10326\
10327 playGame()\
10328end\
10329\
10330\
10331term.setTextColor(colors.white)\
10332term.setBackgroundColor(colors.black)\
10333term.clear()\
10334term.setCursorPos(1,1)",
10335 [ "programs/delete.lua" ] = "\
10336local tArgs = { ... }\
10337if #tArgs < 1 then\
10338 print( \"Usage: rm <path>\" )\
10339 return\
10340end\
10341\
10342local sPath = shell.resolve( tArgs[1] )\
10343local tFiles = fs.find( sPath )\
10344if #tFiles > 0 then\
10345 for n,sFile in ipairs( tFiles ) do\
10346 fs.delete( sFile )\
10347 end\
10348else\
10349 printError( \"No matching files\" )\
10350end",
10351 [ "programs/command/exec.lua" ] = "\
10352local tArgs = { ... }\
10353if not commands then\
10354 printError( \"Requires a Command Computer.\" )\
10355 return\
10356end\
10357if #tArgs == 0 then\
10358 printError( \"Usage: exec <command>\" )\
10359 return\
10360end\
10361\
10362local function printSuccess( text )\
10363 if term.isColor() then\
10364 term.setTextColor( colors.green )\
10365 end\
10366 print( text )\
10367 term.setTextColor( colors.white )\
10368end\
10369\
10370local sCommand = string.lower( tArgs[1] )\
10371for n=2,#tArgs do\
10372 sCommand = sCommand .. \" \" .. tArgs[n]\
10373end\
10374\
10375local bResult, tOutput = commands.exec( sCommand )\
10376if bResult then\
10377 printSuccess( \"Success\" )\
10378 if #tOutput > 0 then\
10379 for n=1,#tOutput do\
10380 print( tOutput[n] )\
10381 end\
10382 end\
10383else\
10384 printError( \"Failed\" )\
10385 if #tOutput > 0 then\
10386 for n=1,#tOutput do\
10387 print( tOutput[n] )\
10388 end\
10389 end\
10390end",
10391 [ "help/helpapi.txt" ] = "Functions in the help API:\
10392help.setPath( path )\
10393help.lookup( topic )\
10394help.topics()\
10395help.completeTopic( topic )",
10396 [ "programs/cd.lua" ] = "\
10397local tArgs = { ... }\
10398if #tArgs < 1 then\
10399 print( \"Usage: cd <path>\" )\
10400 return\
10401end\
10402\
10403local sNewDir = shell.resolve( tArgs[1] )\
10404if fs.isDir( sNewDir ) then\
10405 shell.setDir( sNewDir )\
10406else\
10407 print( \"Not a directory\" )\
10408 return\
10409end",
10410 [ "programs/alias.lua" ] = "\
10411local tArgs = { ... }\
10412if #tArgs > 2 then\
10413 print( \"Usage: alias <alias> <program>\" )\
10414 return\
10415end\
10416\
10417local sAlias = tArgs[1]\
10418local sProgram = tArgs[2]\
10419\
10420if sAlias and sProgram then\
10421 -- Set alias\
10422 shell.setAlias( sAlias, sProgram )\
10423elseif sAlias then\
10424 -- Clear alias\
10425 shell.clearAlias( sAlias )\
10426else\
10427 -- List aliases\
10428 local tAliases = shell.aliases()\
10429 local tList = {}\
10430 for sAlias, sCommand in pairs( tAliases ) do\
10431 table.insert( tList, sAlias..\":\"..sCommand )\
10432 end\
10433 table.sort( tList )\
10434 textutils.pagedTabulate( tList )\
10435end",
10436 [ "help/apis.txt" ] = "apis lists the currently loaded APIs available to programs in CraftOS.\
10437\
10438Type \"help <api>\" to see help for a specific api.\
10439Call os.loadAPI( path ) to load extra apis.",
10440 [ "programs/list.lua" ] = "\
10441local tArgs = { ... }\
10442\
10443-- Get all the files in the directory\
10444local sDir = shell.dir()\
10445if tArgs[1] ~= nil then\
10446 sDir = shell.resolve( tArgs[1] )\
10447end\
10448\
10449if not fs.isDir( sDir ) then\
10450 printError( \"Not a directory\" )\
10451 return\
10452end\
10453\
10454-- Sort into dirs/files, and calculate column count\
10455local tAll = fs.list( sDir )\
10456local tFiles = {}\
10457local tDirs = {}\
10458\
10459local bShowHidden = settings.get( \"list.show_hidden\" )\
10460for n, sItem in pairs( tAll ) do\
10461 if bShowHidden or string.sub( sItem, 1, 1 ) ~= \".\" then\
10462 local sPath = fs.combine( sDir, sItem )\
10463 if fs.isDir( sPath ) then\
10464 table.insert( tDirs, sItem )\
10465 else\
10466 table.insert( tFiles, sItem )\
10467 end\
10468 end\
10469end\
10470table.sort( tDirs )\
10471table.sort( tFiles )\
10472\
10473if term.isColour() then\
10474 textutils.pagedTabulate( colors.green, tDirs, colors.white, tFiles )\
10475else\
10476 textutils.pagedTabulate( tDirs, tFiles )\
10477end",
10478 [ "programs/advanced/bg.lua" ] = "\
10479if not shell.openTab then\
10480 printError( \"Requires multishell\" )\
10481 return\
10482end\
10483\
10484local tArgs = { ... }\
10485if #tArgs > 0 then\
10486 shell.openTab( table.unpack( tArgs ) )\
10487else\
10488 shell.openTab( \"shell\" )\
10489end",
10490 [ "programs/fun/advanced/levels/6.dat" ] = "4\
104917777777777\
104927288888837\
1049378 87\
10494788888b 87\
10495788888b 87\
10496788888b 87\
10497788888b 87\
1049878 87\
104997188888807\
105007777777777",
10501 [ "help/printers.txt" ] = "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\".\
10502\
10503Methods exposed by the Printer:\
10504getInkLevel()\
10505getPaperLevel()\
10506newPage()\
10507setPageTitle( title )\
10508getPageSize()\
10509setCursorPos( x, y )\
10510getCursorPos()\
10511write( text )\
10512endPage()",
10513 [ "help/lua.txt" ] = "lua is an interactive prompt for the lua programming language. It's a useful tool for learning the language.",
10514 [ "help/changelog.txt" ] = "New Features in ComputerCraft 1.80:\
10515\
10516* Added .getResponseHeaders() to HTTP responses.\
10517* Return a HTTP response when a HTTP error occurs.\
10518* Added a GUI to change ComputerCraft config options.\
10519* os.time() and os.day() now accept parameters to give the real world time.\
10520* Added os.epoch()\
10521* Monitor text now glows in the dark.\
10522* Added a \"Pocket Computer upgrade API\" so mod developers can add their own pocket upgrades.\
10523* Added pocket.equipBack()/pocket.unequipBack() to add/remove pocket upgrades.\
10524* Added term.setPaletteColor()/term.getPaletteColor() to change/check colors\
10525* Added colors.rgb8()/colours.rgb8() \
10526* Performance improvements to fs.find\
10527* Requires the player to be interacting with the computer when typing\
10528* Disk labels are limited to 32 characters\
10529* Labels can now only include characters within the printable range ( to ~)\
10530* Various model improvements\
10531* There is now a configurable file descriptor limit\
10532* Threads are now daemon threads\
10533* Termination signals are now sent unless the computer is off\
10534* Fixed compilation errors\
10535* Now handles tile entity changes\
10536* GPS coordinates now have to be numbers\
10537* Turtle upgrades now act as tools and peripherals\
10538* The Filesystem.list result is now sorted\
10539* The number of values to unpack can now be manually specified\
10540* Small terminal & monitor rendering improvements\
10541* General improvements to the documentation\
10542* Redstone inputs are no longer reset when adding peripherals\
10543* Turtles now use tinting\
10544* shell.resolveProgram now picks up on *.lua files\
10545* Fixed a handful of bugs in ComputerCraft\
10546* Added speaker block, turtle upgrade, pocket upgrade, and peripheral api\
10547* Startup can now be a directory containing multiple startup files\
10548* Added .getLabel to the computer peripheral\
10549\
10550New Features in ComputerCraft 1.79:\
10551\
10552* Ported ComputerCraftEdu to Minecraft 1.8.9\
10553* Fixed a handful of bugs in ComputerCraft\
10554\
10555New Features in ComputerCraft 1.77:\
10556\
10557* Ported to Minecraft 1.8.9\
10558* Added \"settings\" API\
10559* Added \"set\" and \"wget\" programs\
10560* Added settings to disable multishell, startup scripts, and tab completion on a per-computer basis. The default values for these settings can be customised in ComputerCraft.cfg\
10561* All Computer and Turtle items except Command Computers can now be mounted in Disk Drives\
10562\
10563New Features in ComputerCraft 1.76:\
10564\
10565* Ported to Minecraft 1.8\
10566* Added Ender Modems for cross-dimensional communication\
10567* Fixed handling of 8-bit characters. All the characters in the ISO 8859-1 codepage can now be displayed\
10568* Added some extra graphical characters in the unused character positions, including a suite of characters for Teletext style drawing\
10569* Added support for the new commands in Minecraft 1.8 to the Command Computer\
10570* The return values of turtle.inspect() and commands.getBlockInfo() now include blockstate information\
10571* Added commands.getBlockInfos() function for Command Computers\
10572* Added new \"peripherals\" program\
10573* Replaced the \"_CC_VERSION\" and \"_MC_VERSION\" constants with a new \"_HOST\" constant\
10574* Shortened the length of time that \"Ctrl+T\", \"Ctrl+S\" and \"Ctrl+R\" must be held down for to terminate, shutdown and reboot the computer\
10575* textutils.serialiseJSON() now takes an optional parameter allowing it to produce JSON text with unquoted object keys. This is used by all autogenerated methods in the \"commands\" api except for \"title\" and \"tellraw\"\
10576* Fixed many bugs\
10577\
10578New Features in ComputerCraft 1.75:\
10579\
10580* Fixed monitors sometimes rendering without part of their text.\
10581* Fixed a regression in the \"bit\" API.\
10582\
10583New Features in ComputerCraft 1.74:\
10584\
10585* Added tab completion to \"edit\", \"lua\" and the shell.\
10586* Added textutils.complete(), fs.complete(), shell.complete(), shell.setCompletionFunction() and help.complete().\
10587* Added tab completion options to read().\
10588* Added \"key_up\" and \"mouse_up\" events.\
10589* Non-advanced terminals now accept both grey colours.\
10590* Added term.getTextColour(), term.getBackgroundColour() and term.blit().\
10591* Improved the performance of text rendering on Advanced Computers.\
10592* Added a \"Run\" button to the edit program on Advanced Computers.\
10593* Turtles can now push players and entities (configurable).\
10594* Turtles now respect server spawn protection (configurable).\
10595* Added a turtle permissions API for mod authors.\
10596* Implemented a subset of the Lua 5.2 API so programs can be written against it now, ahead of a future Lua version upgrade.\
10597* Added a config option to disable parts of the Lua 5.1 API which will be removed when a future Lua version upgrade happens.\
10598* Command Computers can no longer be broken by survival players.\
10599* Fixed the \"pick block\" key not working on ComputerCraft items in creative mode.\
10600* Fixed the \"edit\" program being hard to use on certain European keyboards.\
10601* Added \"_CC_VERSION\" and \"_MC_VERSION\" constants.\
10602\
10603New Features in ComputerCraft 1.73:\
10604\
10605* The \"exec\" program, commands.exec() and all related Command Computer functions now return the console output of the command.\
10606* Fixed two multiplayer crash bugs.\
10607\
10608New Features in ComputerCraft 1.7:\
10609\
10610* Added Command Computers\
10611* Added new API: commands\
10612* Added new programs: commands, exec\
10613* Added textutils.serializeJSON()\
10614* Added ILuaContext.executeMainThreadTask() for peripheral developers\
10615* Disk Drives and Printers can now be renamed with Anvils\
10616* Fixed various bugs, crashes and exploits\
10617* Fixed problems with HD texture packs\
10618* Documented the new features in the in-game help\
10619\
10620New Features in ComputerCraft 1.65:\
10621\
10622* Fixed a multiplayer-only crash with turtle.place()\
10623* Fixed some problems with http.post()\
10624* Fixed fs.getDrive() returning incorrect results on remote peripherals\
10625\
10626New Features in ComputerCraft 1.64:\
10627\
10628* Ported to Minecraft 1.7.10\
10629* New turtle functions: turtle.inspect(), turtle.inspectUp(), turtle.inspectDown(), turtle.getItemDetail()\
10630* Lots of bug and crash fixes, a huge stability improvement over previous versions\
10631\
10632New Features in ComputerCraft 1.63:\
10633\
10634* Turtles can now be painted with dyes, and cleaned with water buckets\
10635* Added a new game: Redirection - ComputerCraft Edition\
10636* Turtle label nameplates now only show when the Turtle is moused-over\
10637* The HTTP API is now enabled by default, and can be configured with a whitelist of permitted domains\
10638* http.get() and http.post() now accept parameters to control the request headers\
10639* New fs function: fs.getDir( path )\
10640* Fixed some bugs\
10641\
10642New Features in ComputerCraft 1.62:\
10643\
10644* Added IRC-style commands to the \"chat\" program\
10645* Fixed some bugs and crashes\
10646\
10647New Features in ComputerCraft 1.6:\
10648\
10649* Added Pocket Computers\
10650* Added a multi-tasking system for Advanced Computers and Turtles\
10651* Turtles can now swap out their tools and peripherals at runtime\
10652* Turtles can now carry two tools or peripherals at once in any combination\
10653* Turtles and Computers can now be labelled using Name Tags and Anvils\
10654* Added a configurable fuel limit for Turtles\
10655* Added hostnames, protocols and long distance routing to the rednet API\
10656* Added a peer-to-peer chat program to demonstrate new rednet capabilities\
10657* Added a new game, only on Pocket Computers: \"falling\" by GopherATL\
10658* File system commands in the shell now accept wildcard arguments\
10659* The shell now accepts long arguments in quotes\
10660* 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.\
10661* Added a new Windowing API for addressing sub-areas of the terminal\
10662* New programs: fg, bg, multishell, chat, repeat, redstone, equip, unequip\
10663* Improved programs: copy, move, delete, rename, paint, shell\
10664* Removed programs: redset, redprobe, redpulse\
10665* New APIs: window, multishell\
10666* New turtle functions: turtle.equipLeft() and turtle.equipRight()\
10667* New peripheral functions: peripheral.find( [type] )\
10668* New rednet functions: rednet.host( protocol, hostname ), rednet.unhost( protocol ), rednet.locate( protocol, [hostname] )\
10669* New fs function: fs.find( wildcard )\
10670* New shell functions: shell.openTab(), shell.switchTab( [number] )\
10671* New event \"term_resize\" fired when the size of a terminal changes\
10672* Improved rednet functions: rednet.send(), rednet.broadcast() and rednet.receive() now take optional protocol parameters\
10673* 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\
10674* turtle.suck( [limit] ) can now be used to limit the number of items picked up\
10675* 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)\
10676* textutils.serialise( text ) now produces human-readable output\
10677* Refactored most of the codebase and fixed many old bugs and instabilities, turtles should never ever lose their content now\
10678* Fixed the \"turtle_inventory\" event firing when it shouldn't have\
10679* Added error messages to many more turtle functions after they return false\
10680* Documented all new programs and API changes in the \"help\" system\
10681\
10682New Features in ComputerCraft 1.58:\
10683\
10684* Fixed a long standing bug where turtles could lose their identify if they travel too far away\
10685* Fixed use of deprecated code, ensuring mod compatibility with the latest versions of Minecraft Forge, and world compatibility with future versions of Minecraft\
10686\
10687New Features in ComputerCraft 1.57:\
10688\
10689* Ported to Minecraft 1.6.4\
10690* Added two new Treasure Disks: Conway's Game of Life by vilsol and Protector by fredthead\
10691* Fixed a very nasty item duplication bug\
10692\
10693New Features in ComputerCraft 1.56:\
10694\
10695* Added Treasure Disks: Floppy Disks in dungeons which contain interesting community made programs. Find them all!\
10696* All turtle functions now return additional error messages when they fail.\
10697* Resource Packs with Lua Programs can now be edited when extracted to a folder, for easier editing.\
10698\
10699New Features in ComputerCraft 1.55:\
10700\
10701* Ported to Minecraft 1.6.2\
10702* Added Advanced Turtles\
10703* Added \"turtle_inventory\" event. Fires when any change is made to the inventory of a turtle\
10704* Added missing functions io.close, io.flush, io.input, io.lines, io.output\
10705* Tweaked the screen colours used by Advanced Computers, Monitors and Turtles\
10706* Added new features for Peripheral authors\
10707* Lua programs can now be included in Resource Packs\
10708\
10709New Features in ComputerCraft 1.52:\
10710\
10711* Ported to Minecraft 1.5.1\
10712\
10713New Features in ComputerCraft 1.51:\
10714\
10715* Ported to Minecraft 1.5\
10716* Added Wired Modems\
10717* Added Networking Cables\
10718* Made Wireless Modems more expensive to craft\
10719* New redstone API functions: getAnalogInput(), setAnalogOutput(), getAnalogOutput()\
10720* Peripherals can now be controlled remotely over wired networks. New peripheral API function: getNames()\
10721* New event: \"monitor_resize\" when the size of a monitor changes\
10722* Except for labelled computers and turtles, ComputerCraft blocks no longer drop items in creative mode\
10723* The pick block function works in creative mode now works for all ComputerCraft blocks\
10724* All blocks and items now use the IDs numbers assigned by FTB by default\
10725* Fixed turtles sometimes placing blocks with incorrect orientations\
10726* Fixed Wireless modems being able to send messages to themselves\
10727* Fixed turtle.attack() having a very short range\
10728* Various bugfixes\
10729\
10730New Features in ComputerCraft 1.5:\
10731\
10732* 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\
10733* Floppy Disks can now be dyed with multiple dyes, just like armour\
10734* The \"excavate\" program now retains fuel in it's inventory, so can run unattended\
10735* turtle.place() now tries all possible block orientations before failing\
10736* turtle.refuel(0) returns true if a fuel item is selected\
10737* turtle.craft(0) returns true if the inventory is a valid recipe\
10738* The in-game help system now has documentation for all the peripherals and their methods, including the new modem functionality\
10739* A romantic surprise\
10740\
10741New Features in ComputerCraft 1.48:\
10742\
10743* Ported to Minecraft 1.4.6\
10744* Advanced Monitors now emit a \"monitor_touch\" event when right clicked\
10745* Advanced Monitors are now cheaper to craft\
10746* Turtles now get slightly less fuel from items\
10747* Computers can now interact with Command Blocks (if enabled in ComputerCraft.cfg)\
10748* New API function: os.day()\
10749* A christmas surprise\
10750\
10751New Features in ComputerCraft 1.45:\
10752\
10753* Added Advanced Computers\
10754* Added Advanced Monitors\
10755* New program: paint by nitrogenfingers\
10756* New API: paintutils\
10757* New term functions: term.setBackgroundColor, term.setTextColor, term.isColor\
10758* New turtle function: turtle.transferTo\
10759\
10760New Features in ComputerCraft 1.43:\
10761\
10762* Added Printed Pages\
10763* Added Printed Books\
10764* Fixed incompatibility with Forge 275 and above\
10765* Labelled Turtles now keep their fuel when broken\
10766\
10767New Features in ComputerCraft 1.42:\
10768\
10769* Ported to Minecraft 1.3.2\
10770* Added Printers\
10771* Floppy Disks can be dyed different colours\
10772* Wireless Crafty Turtles can now be crafted\
10773* New textures\
10774* New forge config file\
10775* Bug fixes\
10776\
10777New Features in ComputerCraft 1.4:\
10778\
10779* Ported to Forge Mod Loader. ComputerCraft can now be ran directly from the .zip without extraction\
10780* Added Farming Turtles\
10781* Added Felling Turtles\
10782* Added Digging Turtles\
10783* Added Melee Turtles\
10784* Added Crafty Turtles\
10785* Added 14 new Turtle Combinations accessible by combining the turtle upgrades above\
10786* Labelled computers and turtles can now be crafted into turtles or other turtle types without losing their ID, label and data\
10787* Added a \"Turtle Upgrade API\" for mod developers to create their own tools and peripherals for turtles\
10788* Turtles can now attack entities with turtle.attack(), and collect their dropped items\
10789* Turtles can now use turtle.place() with any item the player can, and can interact with entities\
10790* Turtles can now craft items with turtle.craft()\
10791* Turtles can now place items into inventories with turtle.drop()\
10792* Changed the behaviour of turtle.place() and turtle.drop() to only consider the currently selected slot\
10793* Turtles can now pick up items from the ground, or from inventories, with turtle.suck()\
10794* Turtles can now compare items in their inventories\
10795* Turtles can place signs with text on them with turtle.place( [signText] )\
10796* Turtles now optionally require fuel items to move, and can refuel themselves\
10797* The size of the the turtle inventory has been increased to 16\
10798* The size of the turtle screen has been increased\
10799* New turtle functions: turtle.compareTo( [slotNum] ), turtle.craft(), turtle.attack(), turtle.attackUp(), turtle.attackDown(), turtle.dropUp(), turtle.dropDown(), turtle.getFuelLevel(), turtle.refuel()\
10800* New disk function: disk.getID()\
10801* New turtle programs: craft, refuel\
10802* \"excavate\" program now much smarter: Will return items to a chest when full, attack mobs, and refuel itself automatically\
10803* New API: keys\
10804* Added optional Floppy Disk and Hard Drive space limits for computers and turtles\
10805* New fs function: fs.getFreeSpace( path ), also fs.getDrive() works again\
10806* The send and receive range of wireless modems now increases with altitude, allowing long range networking from high-altitude computers (great for GPS networks)\
10807* http.request() now supports https:// URLs\
10808* Right clicking a Disk Drive with a Floppy Disk or a Record when sneaking will insert the item into the Disk Drive automatically\
10809* The default size of the computer screen has been increased\
10810* 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.\
10811\
10812New Features in ComputerCraft 1.31:\
10813\
10814* Ported to Minecraft 1.2.3\
10815* Added Monitors (thanks to Cloudy)\
10816* Updated LuaJ to a newer, less memory hungry version\
10817* rednet_message event now has a third parameter, \"distance\", to support position triangulation.\
10818* New programs: gps, monitor, pastebin.\
10819* Added a secret program. Use with large monitors!\
10820* New apis: gps, vector\
10821* New turtle functions: turtle.compare(), turtle.compareUp(), turtle.compareDown(), turtle.drop( quantity )\
10822* New http functions: http.post().\
10823* New term functions: term.redirect(), term.restore()\
10824* New textutils functions: textutils.urlEncode()\
10825* New rednet functions: rednet.isOpen()\
10826* New config options: modem_range, modem_rangeDuringStorm\
10827* Bug fixes, program tweaks, and help updates\
10828\
10829New Features in ComputerCraft 1.3:\
10830\
10831* Ported to Minecraft Forge\
10832* Added Turtles\
10833* Added Wireless Modems\
10834* Added Mining Turtles\
10835* Added Wireless Turtles\
10836* Added Wireless Mining Turtles\
10837* Computers and Disk Drives no longer get destroyed by water.\
10838* Computers and Turtles can now be labelled with the label program, and labelled devices keep their state when destroyed.\
10839* Computers/Turtles can connect to adjacent devices, and turn them on and off\
10840* User programs now give line numbers in their error messages\
10841* New APIs: turtle, peripheral\
10842* New programs for turtles: tunnel, excavate, go, turn, dance\
10843* New os functions: os.getComputerLabel(), os.setComputerLabel()\
10844* Added \"filter\" parameter to os.pullEvent()\
10845* New shell function: shell.getCurrentProgram()\
10846* New textutils functions: textutils.serialize(), textutils.unserialize(), textutils.tabulate(), textutils.pagedTabulate(), textutils.slowWrite()\
10847* New io file function: file:lines()\
10848* New fs function: fs.getSize()\
10849* Disk Drives can now play records from other mods\
10850* Bug fixes, program tweaks, and help updates\
10851\
10852New Features in ComputerCraft 1.2:\
10853\
10854* Added Disk Drives and Floppy Disks\
10855* Added Ctrl+T shortcut to terminate the current program (hold)\
10856* Added Ctrl+S shortcut to shutdown the computer (hold)\
10857* Added Ctrl+R shortcut to reboot the computer (hold)\
10858* New Programs: alias, apis, copy, delete, dj, drive, eject, id, label, list, move, reboot, redset, rename, time, worm.\
10859* New APIs: bit, colours, disk, help, rednet, parallel, textutils.\
10860* New color functions: colors.combine(), colors.subtract(), colors.test()\
10861* New fs functions: fs.getName(), new modes for fs.open()\
10862* New os functions: os.loadAPI(), os.unloadAPI(),\
10863os.clock(), os.time(), os.setAlarm(),\
10864os.reboot(), os.queueEvent()\
10865* New redstone function: redstone.getSides()\
10866* New shell functions: shell.setPath(), shell.programs(), shell.resolveProgram(), shell.setAlias()\
10867* Lots of updates to the help pages\
10868* Bug fixes\
10869\
10870New Features in ComputerCraft 1.1:\
10871\
10872* Added Multiplayer support throughout.\
10873* Added connectivity with RedPower bundled cables\
10874* Added HTTP api, enabled via the mod config, to allow computers to access the real world internet\
10875* Added command history to the shell.\
10876* Programs which spin in an infinite loop without yielding will no longer freeze minecraft\
10877* Help updates and bug fixes\
10878\
10879New Features in ComputerCraft 1.0:\
10880\
10881* First Release!",
10882 [ "help/emu.txt" ] = "USAGE\
10883\
10884* emu close\
10885Closes the current emulated computer, without affecting the others. Can be called from within programs via ccemux.closeEmu().\
10886\
10887* emu open [id]\
10888Opens a new emulated computer, with the given ID (if specified) or with the next ID. Can be called from within programs via ccemux.openEmu() or ccemux.openEmu(id)\
10889\
10890* emu data\
10891This will open the CCEmuX data dir (where config files and computer save folders are stored) in your default file browser. Can be called from within programs via ccemux.openDataDir(). Note that it may fail on some Linux systems (i.e. if you don't have a DE installed)\
10892\
10893* emu config\
10894Opens an interface to edit the CCEmuX configuration. Note that not all rendering backends support this.\
10895\
10896CREDITS\
10897\
10898* Lignum - developer\
10899* apemanzilla - developer\
10900* Lemmmy - contributions to ccemux API and program\
10901* SquidDev - CCTweaks support and general help during development\
10902* BombBloke - created and allowed us to use the HD font\
10903\
10904LICENSE INFORMATION\
10905\
10906CCEmuX is licensed under the MIT license. The complete source code and license for CCEmuX can be found at https://github.com/Lignum/CCEmuX\
10907\
10908CCEmuX is designed around and includes ComputerCraft, a Minecraft modification by Daniel \"dan200\" Ratcliffe, which is licensed under the ComputerCraft Public License. The complete source code and license for ComputerCraft can be found at https://github.com/dan200/ComputerCraft",
10909 [ "help/pastebin.txt" ] = "pastebin is a program for uploading files to and downloading files from pastebin.com. This is useful for sharing programs with other players.\
10910The HTTP API must be enabled in ComputerCraft.cfg to use this program.\
10911\
10912ex:\
10913\"pastebin put foo\" will upload the file \"foo\" to pastebin.com, and print the URL.\
10914\"pastebin get xq5gc7LB foo\" will download the file from the URL http://pastebin.com/xq5gc7LB, and save it as \"foo\".\
10915\"pastebin run CxaWmPrX\" will download the file from the URL http://pastebin.com/CxaWmPrX, and immediately run it.",
10916 [ "help/monitors.txt" ] = "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.\
10917\
10918Methods exposed by the Monitor:\
10919write( text )\
10920blit( text, textColor, backgroundColor )\
10921clear()\
10922clearLine()\
10923getCursorPos()\
10924setCursorPos( x, y )\
10925setCursorBlink( blink )\
10926isColor()\
10927setTextColor( color )\
10928setBackgroundColor( color )\
10929getTextColor()\
10930getBackgroundColor()\
10931getSize()\
10932scroll( n )\
10933setPaletteColor( color, r, g, b )\
10934getPaletteColor( color )\
10935\
10936Events fired by the Monitor:\
10937\"monitor_touch\" when an Advanced Monitor is touched by the player. Arguments are name, x, y\
10938\"monitor_resize\" when the size of a Monitor changes. Argument is the name of the monitor.",
10939 [ "modules/command/.ignoreme" ] = "--[[\
10940Alright then, don't ignore me. This file is to ensure the existence of the \"modules/command\" folder.\
10941You can use this folder to add modules who can be loaded with require() to your Resourcepack.\
10942]]",
10943 [ "help/window.txt" ] = "Functions in the window API:\
10944window.create( parent, x, y, width, height, visible )\
10945\
10946Windows created with the window API have the following methods:\
10947write( text )\
10948blit( text, textColor, backgroundColor )\
10949clear()\
10950clearLine()\
10951getCursorPos()\
10952setCursorPos( x, y )\
10953setCursorBlink( blink )\
10954isColor()\
10955setTextColor( color )\
10956setBackgroundColor( color )\
10957getTextColor()\
10958getBackgroundColor()\
10959getSize()\
10960scroll( n )\
10961setVisible( bVisible )\
10962redraw()\
10963restoreCursor()\
10964getPosition()\
10965reposition( x, y, width, height )\
10966getPaletteColor( color )\
10967setPaletteColor( color, r, g, b )",
10968 [ "help/commands.txt" ] = "On a Command Computer, \"commands\" will list all the commands available for use. Use \"exec\" to execute them.\
10969Type \"help commandsapi\" for help using commands in lua programs.",
10970 [ "apis/io.lua" ] = "-- Definition for the IO API\
10971local typeOf = _G.type\
10972\
10973--- If we return nil then close the file, as we've reached the end.\
10974-- We use this weird wrapper function as we wish to preserve the varargs\
10975local function checkResult(handle, ...)\
10976 if ... == nil and handle._autoclose and not handle._closed then handle:close() end\
10977 return ...\
10978end\
10979\
10980local handleMetatable\
10981handleMetatable = {\
10982 __name = \"FILE*\",\
10983 __tostring = function(self)\
10984 if self._closed then\
10985 return \"file (closed)\"\
10986 else\
10987 local hash = tostring(self._handle):match(\"table: (%x+)\")\
10988 return \"file (\" .. hash .. \")\"\
10989 end\
10990 end,\
10991 __index = {\
10992 close = function(self)\
10993 if typeOf(self) ~= \"table\" or getmetatable(self) ~= handleMetatable then\
10994 error(\"bad argument #1 (FILE expected, got \" .. typeOf(self) .. \")\", 2)\
10995 end\
10996 if self._closed then error(\"attempt to use a closed file\", 2) end\
10997\
10998 local handle = self._handle\
10999 if handle.close then\
11000 self._closed = true\
11001 handle.close()\
11002 return true\
11003 else\
11004 return nil, \"attempt to close standard stream\"\
11005 end\
11006 end,\
11007 flush = function(self)\
11008 if typeOf(self) ~= \"table\" or getmetatable(self) ~= handleMetatable then\
11009 error(\"bad argument #1 (FILE expected, got \" .. typeOf(self) .. \")\", 2)\
11010 end\
11011 if self._closed then error(\"attempt to use a closed file\", 2) end\
11012\
11013 local handle = self._handle\
11014 if handle.flush then handle.flush() end\
11015 end,\
11016 lines = function(self, ...)\
11017 if typeOf(self) ~= \"table\" or getmetatable(self) ~= handleMetatable then\
11018 error(\"bad argument #1 (FILE expected, got \" .. typeOf(self) .. \")\", 2)\
11019 end\
11020 if self._closed then error(\"attempt to use a closed file\", 2) end\
11021\
11022 local handle = self._handle\
11023 if not handle.read then return nil, \"file is not readable\" end\
11024\
11025 local args = table.pack(...)\
11026 return function() return checkResult(self, self:read(table.unpack(args, 1, args.n))) end\
11027 end,\
11028 read = function(self, ...)\
11029 if typeOf(self) ~= \"table\" or getmetatable(self) ~= handleMetatable then\
11030 error(\"bad argument #1 (FILE expected, got \" .. typeOf(self) .. \")\", 2)\
11031 end\
11032 if self._closed then error(\"attempt to use a closed file\", 2) end\
11033\
11034 local handle = self._handle\
11035 if not handle.read and not handle.readLine then return nil, \"Not opened for reading\" end\
11036\
11037 local n = select('#', ...)\
11038 local output = {}\
11039 for i = 1, n do\
11040 local arg = select(i, ...)\
11041 local res\
11042 if typeOf(arg) == \"number\" then\
11043 if handle.read then res = handle.read(arg) end\
11044 elseif typeOf(arg) == \"string\" then\
11045 local format = arg:gsub(\"^%*\", \"\"):sub(1, 1)\
11046\
11047 if format == \"l\" then\
11048 if handle.readLine then res = handle.readLine() end\
11049 elseif format == \"L\" and handle.readLine then\
11050 if handle.readLine then res = handle.readLine(true) end\
11051 elseif format == \"a\" then\
11052 if handle.readAll then res = handle.readAll() or \"\" end\
11053 elseif format == \"n\" then\
11054 res = nil -- Skip this format as we can't really handle it\
11055 else\
11056 error(\"bad argument #\" .. i .. \" (invalid format)\", 2)\
11057 end\
11058 else\
11059 error(\"bad argument #\" .. i .. \" (expected string, got \" .. typeOf(arg) .. \")\", 2)\
11060 end\
11061\
11062 output[i] = res\
11063 if not res then break end\
11064 end\
11065\
11066 -- Default to \"l\" if possible\
11067 if n == 0 and handle.readLine then return handle.readLine() end\
11068 return table.unpack(output, 1, n)\
11069 end,\
11070 seek = function(self, whence, offset)\
11071 if typeOf(self) ~= \"table\" or getmetatable(self) ~= handleMetatable then\
11072 error(\"bad argument #1 (FILE expected, got \" .. typeOf(self) .. \")\", 2)\
11073 end\
11074 if self._closed then error(\"attempt to use a closed file\", 2) end\
11075\
11076 local handle = self._handle\
11077 if not handle.seek then return nil, \"file is not seekable\" end\
11078\
11079 -- It's a tail call, so error positions are preserved\
11080 return handle.seek(whence, offset)\
11081 end,\
11082 setvbuf = function(self, mode, size) end,\
11083 write = function(self, ...)\
11084 if typeOf(self) ~= \"table\" or getmetatable(self) ~= handleMetatable then\
11085 error(\"bad argument #1 (FILE expected, got \" .. typeOf(self) .. \")\", 2)\
11086 end\
11087 if self._closed then error(\"attempt to use a closed file\", 2) end\
11088\
11089 local handle = self._handle\
11090 if not handle.write then return nil, \"file is not writable\" end\
11091\
11092 local n = select(\"#\", ...)\
11093 for i = 1, n do handle.write(select(i, ...)) end\
11094 return self\
11095 end,\
11096 },\
11097}\
11098\
11099local defaultInput = setmetatable({\
11100 _handle = { readLine = _G.read }\
11101}, handleMetatable)\
11102\
11103local defaultOutput = setmetatable({\
11104 _handle = { write = _G.write }\
11105}, handleMetatable)\
11106\
11107local defaultError = setmetatable({\
11108 _handle = {\
11109 write = function(...)\
11110 local oldColour\
11111 if term.isColour() then\
11112 oldColour = term.getTextColour()\
11113 term.setTextColour(colors.red)\
11114 end\
11115 _G.write(...)\
11116 if term.isColour() then term.setTextColour(oldColour) end\
11117 end,\
11118 }\
11119}, handleMetatable)\
11120\
11121local currentInput = defaultInput\
11122local currentOutput = defaultOutput\
11123\
11124stdin = defaultInput\
11125stdout = defaultOutput\
11126stderr = defaultError\
11127\
11128function close(_file)\
11129 if _file == nil then return currentOutput:close() end\
11130\
11131 if typeOf(_file) ~= \"table\" or getmetatable(_file) ~= handleMetatable then\
11132 error(\"bad argument #1 (FILE expected, got \" .. typeOf(_file) .. \")\", 2)\
11133 end\
11134 return _file:close()\
11135end\
11136\
11137function flush()\
11138 return currentOutput:flush()\
11139end\
11140\
11141function input(_arg)\
11142 if typeOf(_arg) == \"string\" then\
11143 local res, err = open(_arg, \"rb\")\
11144 if not res then error(err, 2) end\
11145 currentInput = res\
11146 elseif typeOf(_arg) == \"table\" and getmetatable(_arg) == handleMetatable then\
11147 currentInput = _arg\
11148 elseif _arg ~= nil then\
11149 error(\"bad argument #1 (FILE expected, got \" .. typeOf(_arg) .. \")\", 2)\
11150 end\
11151\
11152 return currentInput\
11153end\
11154\
11155function lines(_sFileName)\
11156 if _sFileName ~= nil and typeOf(_sFileName) ~= \"string\" then\
11157 error(\"bad argument #1 (expected string, got \" .. typeOf(_sFileName) .. \")\", 2)\
11158 end\
11159 if _sFileName then\
11160 local ok, err = open(_sFileName, \"rb\")\
11161 if not ok then error(err, 2) end\
11162\
11163 -- We set this magic flag to mark this file as being opened by io.lines and so should be\
11164 -- closed automatically\
11165 ok._autoclose = true\
11166 return ok:lines()\
11167 else\
11168 return currentInput:lines()\
11169 end\
11170end\
11171\
11172function open(_sPath, _sMode)\
11173 if typeOf(_sPath) ~= \"string\" then\
11174 error(\"bad argument #1 (expected string, got \" .. typeOf(_sPath) .. \")\", 2)\
11175 end\
11176 if _sMode ~= nil and typeOf(_sMode) ~= \"string\" then\
11177 error(\"bad argument #2 (expected string, got \" .. typeOf(_sMode) .. \")\", 2)\
11178 end\
11179\
11180 local sMode = _sMode and _sMode:gsub(\"%+\", \"\") or \"rb\"\
11181 local file, err = fs.open(_sPath, sMode)\
11182 if not file then return nil, err end\
11183\
11184 return setmetatable({ _handle = file }, handleMetatable)\
11185end\
11186\
11187function output(_arg)\
11188 if typeOf(_arg) == \"string\" then\
11189 local res, err = open(_arg, \"w\")\
11190 if not res then error(err, 2) end\
11191 currentOutput = res\
11192 elseif typeOf(_arg) == \"table\" and getmetatable(_arg) == handleMetatable then\
11193 currentOutput = _arg\
11194 elseif _arg ~= nil then\
11195 error(\"bad argument #1 (FILE expected, got \" .. typeOf(_arg) .. \")\", 2)\
11196 end\
11197\
11198 return currentOutput\
11199end\
11200\
11201function read(...)\
11202 return currentInput:read(...)\
11203end\
11204\
11205function type(handle)\
11206 if typeOf(handle) == \"table\" and getmetatable(handle) == handleMetatable then\
11207 if handle._closed then\
11208 return \"closed file\"\
11209 else\
11210 return \"file\"\
11211 end\
11212 end\
11213 return nil\
11214end\
11215\
11216function write(...)\
11217 return currentOutput:write(...)\
11218end",
11219 [ "help/rs.txt" ] = "Functions in the Redstone API:\
11220rs.getSides( )\
11221rs.getInput( side )\
11222rs.setOutput( side, boolean )\
11223rs.getOutput( side )\
11224rs.getAnalogInput( side )\
11225rs.setAnalogOutput( side, number )\
11226rs.getAnalogOutput( side )\
11227\
11228Functions in the Redstone API for working with RedPower bundled cables:\
11229rs.getBundledInput( side )\
11230rs.testBundledInput( side, color )\
11231rs.setBundledOutput( side, colors )\
11232rs.getBundledOutput( side )\
11233Type \"help bundled\" for usage examples.\
11234\
11235Events emitted by the redstone API:\
11236\"redstone\", when the state of any redstone input changes. Use getInput() or getBundledInput() to inspect the changes\
11237Type \"help events\" to learn about the event system.",
11238 [ "help/http.txt" ] = "Functions in the HTTP API:\
11239http.checkURL( url )\
11240http.checkURLAsync( url )\
11241http.request( url, [postData], [headers] )\
11242http.get( url, [headers] )\
11243http.post( url, postData, [headers] )\
11244\
11245The HTTP API may be disabled in ComputerCraft.cfg\
11246A 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. Arguments are nil, an error message, and (optionally) a file handle if the request failed. http.get() and http.post() block until this event fires instead.",
11247 [ "help/repeat.txt" ] = "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.",
11248 [ "help/bg.txt" ] = "bg is a program for Advanced Computers which opens a new tab in the background.\
11249\
11250ex:\
11251\"bg\" will open a background tab running the shell\
11252\"bg worm\" will open a background tab running the \"worm\" program",
11253 [ "help/gpsapi.txt" ] = "Functions in the GPS API:\
11254gps.locate( timeout )\
11255\
11256The 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.",
11257 [ "help/multishell.txt" ] = "multishell is the toplevel program on Advanced Computers which manages background tabs.\
11258Type \"help shellapi\" for information about the shell lua api.",
11259 [ "help/vector.txt" ] = "Functions in the 3D Vector Math API:\
11260vector.new( x,y,z )\
11261\
11262Vectors returned by vector.new() have the following fields and methods:\
11263vector.x\
11264vector.y\
11265vector.z\
11266vector:add( vector )\
11267vector:sub( vector )\
11268vector:mul( number )\
11269vector:dot( vector )\
11270vector:cross( vector )\
11271vector:length()\
11272vector:normalize()\
11273vector:round()\
11274vector:tostring()\
11275The +, - and * operators can also be used on vectors.",
11276 [ "help/alias.txt" ] = "alias assigns shell commands to run other programs.\
11277\
11278ex:\
11279\"alias dir ls\" will make the \"dir\" command run the \"ls\" program\
11280\"alias dir\" will remove the alias set on \"dir\"\
11281\"alias\" will list all current aliases.",
11282 [ "help/shellapi.txt" ] = "Functions in the Shell API:\
11283shell.exit()\
11284shell.dir()\
11285shell.setDir( path )\
11286shell.path()\
11287shell.setPath( path )\
11288shell.resolve( localpath )\
11289shell.resolveProgram( name )\
11290shell.aliases()\
11291shell.setAlias( alias, command )\
11292shell.clearAlias( alias )\
11293shell.programs()\
11294shell.run( program, arguments )\
11295shell.getRunningProgram()\
11296shell.complete( line )\
11297shell.completeProgram( program )\
11298shell.setCompletionFunction( program, fnComplete )\
11299shell.openTab( program, arguments ) (Advanced Computer required)\
11300shell.switchTab( n ) (Advanced Computer required)",
11301 [ "programs/turtle/tunnel.lua" ] = "\
11302local tArgs = { ... }\
11303if #tArgs ~= 1 then\
11304 print( \"Usage: tunnel <length>\" )\
11305 return\
11306end\
11307\
11308-- Mine in a quarry pattern until we hit something we can't dig\
11309local length = tonumber( tArgs[1] )\
11310if length < 1 then\
11311 print( \"Tunnel length must be positive\" )\
11312 return\
11313end\
11314\
11315local depth = 0\
11316local collected = 0\
11317\
11318local function collect()\
11319 collected = collected + 1\
11320 if math.fmod(collected, 25) == 0 then\
11321 print( \"Mined \"..collected..\" items.\" )\
11322 end\
11323end\
11324\
11325local function tryDig()\
11326 while turtle.detect() do\
11327 if turtle.dig() then\
11328 collect()\
11329 sleep(0.5)\
11330 else\
11331 return false\
11332 end\
11333 end\
11334 return true\
11335end\
11336\
11337local function tryDigUp()\
11338 while turtle.detectUp() do\
11339 if turtle.digUp() then\
11340 collect()\
11341 sleep(0.5)\
11342 else\
11343 return false\
11344 end\
11345 end\
11346 return true\
11347end\
11348\
11349local function tryDigDown()\
11350 while turtle.detectDown() do\
11351 if turtle.digDown() then\
11352 collect()\
11353 sleep(0.5)\
11354 else\
11355 return false\
11356 end\
11357 end\
11358 return true\
11359end\
11360\
11361local function refuel()\
11362 local fuelLevel = turtle.getFuelLevel()\
11363 if fuelLevel == \"unlimited\" or fuelLevel > 0 then\
11364 return\
11365 end\
11366\
11367 local function tryRefuel()\
11368 for n=1,16 do\
11369 if turtle.getItemCount(n) > 0 then\
11370 turtle.select(n)\
11371 if turtle.refuel(1) then\
11372 turtle.select(1)\
11373 return true\
11374 end\
11375 end\
11376 end\
11377 turtle.select(1)\
11378 return false\
11379 end\
11380\
11381 if not tryRefuel() then\
11382 print( \"Add more fuel to continue.\" )\
11383 while not tryRefuel() do\
11384 os.pullEvent( \"turtle_inventory\" )\
11385 end\
11386 print( \"Resuming Tunnel.\" )\
11387 end\
11388end\
11389\
11390local function tryUp()\
11391 refuel()\
11392 while not turtle.up() do\
11393 if turtle.detectUp() then\
11394 if not tryDigUp() then\
11395 return false\
11396 end\
11397 elseif turtle.attackUp() then\
11398 collect()\
11399 else\
11400 sleep( 0.5 )\
11401 end\
11402 end\
11403 return true\
11404end\
11405\
11406local function tryDown()\
11407 refuel()\
11408 while not turtle.down() do\
11409 if turtle.detectDown() then\
11410 if not tryDigDown() then\
11411 return false\
11412 end\
11413 elseif turtle.attackDown() then\
11414 collect()\
11415 else\
11416 sleep( 0.5 )\
11417 end\
11418 end\
11419 return true\
11420end\
11421\
11422local function tryForward()\
11423 refuel()\
11424 while not turtle.forward() do\
11425 if turtle.detect() then\
11426 if not tryDig() then\
11427 return false\
11428 end\
11429 elseif turtle.attack() then\
11430 collect()\
11431 else\
11432 sleep( 0.5 )\
11433 end\
11434 end\
11435 return true\
11436end\
11437\
11438print( \"Tunnelling...\" )\
11439\
11440for n=1,length do\
11441 turtle.placeDown()\
11442 tryDigUp()\
11443 turtle.turnLeft()\
11444 tryDig()\
11445 tryUp()\
11446 tryDig()\
11447 turtle.turnRight()\
11448 turtle.turnRight()\
11449 tryDig()\
11450 tryDown()\
11451 tryDig()\
11452 turtle.turnLeft()\
11453\
11454 if n<length then\
11455 tryDig()\
11456 if not tryForward() then\
11457 print( \"Aborting Tunnel.\" )\
11458 break\
11459 end\
11460 else\
11461 print( \"Tunnel complete.\" )\
11462 end\
11463\
11464end\
11465\
11466--[[\
11467print( \"Returning to start...\" )\
11468\
11469-- Return to where we started\
11470turtle.turnLeft()\
11471turtle.turnLeft()\
11472while depth > 0 do\
11473 if turtle.forward() then\
11474 depth = depth - 1\
11475 else\
11476 turtle.dig()\
11477 end\
11478end\
11479turtle.turnRight()\
11480turtle.turnRight()\
11481]]\
11482\
11483print( \"Tunnel complete.\" )\
11484print( \"Mined \"..collected..\" items total.\" )",
11485 [ "apis/disk.lua" ] = "\
11486local function isDrive( name )\
11487 if type( name ) ~= \"string\" then\
11488 error( \"bad argument #1 (expected string, got \" .. type( name ) .. \")\", 3 )\
11489 end\
11490 return peripheral.getType( name ) == \"drive\"\
11491end\
11492\
11493function isPresent( name )\
11494 if isDrive( name ) then\
11495 return peripheral.call( name, \"isDiskPresent\" )\
11496 end\
11497 return false\
11498end\
11499\
11500function getLabel( name )\
11501 if isDrive( name ) then\
11502 return peripheral.call( name, \"getDiskLabel\" )\
11503 end\
11504 return nil\
11505end\
11506\
11507function setLabel( name, label )\
11508 if isDrive( name ) then\
11509 peripheral.call( name, \"setDiskLabel\", label )\
11510 end\
11511end\
11512\
11513function hasData( name )\
11514 if isDrive( name ) then\
11515 return peripheral.call( name, \"hasData\" )\
11516 end\
11517 return false\
11518end\
11519\
11520function getMountPath( name )\
11521 if isDrive( name ) then\
11522 return peripheral.call( name, \"getMountPath\" )\
11523 end\
11524 return nil\
11525end\
11526\
11527function hasAudio( name )\
11528 if isDrive( name ) then\
11529 return peripheral.call( name, \"hasAudio\" )\
11530 end\
11531 return false\
11532end\
11533\
11534function getAudioTitle( name )\
11535 if isDrive( name ) then\
11536 return peripheral.call( name, \"getAudioTitle\" )\
11537 end\
11538 return nil\
11539end\
11540\
11541function playAudio( name )\
11542 if isDrive( name ) then\
11543 peripheral.call( name, \"playAudio\" )\
11544 end\
11545end\
11546\
11547function stopAudio( name )\
11548 if not name then\
11549 for n,sName in ipairs( peripheral.getNames() ) do\
11550 stopAudio( sName )\
11551 end\
11552 else\
11553 if isDrive( name ) then\
11554 peripheral.call( name, \"stopAudio\" )\
11555 end\
11556 end\
11557end\
11558\
11559function eject( name )\
11560 if isDrive( name ) then\
11561 peripheral.call( name, \"ejectDisk\" )\
11562 end\
11563end\
11564\
11565function getID( name )\
11566 if isDrive( name ) then\
11567 return peripheral.call( name, \"getDiskID\" )\
11568 end\
11569 return nil\
11570end",
11571 [ "help/craft.txt" ] = "craft is a program for Crafty Turtles. Craft will craft a stack of items using the current inventory.\
11572\
11573ex:\
11574\"craft\" will craft as many items as possible\
11575\"craft 5\" will craft at most 5 times",
11576 [ "help/redstoneapi.txt" ] = "Functions in the Redstone API:\
11577redstone.getSides( )\
11578redstone.getInput( side )\
11579redstone.setOutput( side, boolean )\
11580redstone.getOutput( side )\
11581redstone.getAnalogInput( side )\
11582redstone.setAnalogOutput( side, number )\
11583redstone.getAnalogOutput( side )\
11584\
11585Functions in the Redstone API for working with bundled cables:\
11586redstone.getBundledInput( side )\
11587redstone.testBundledInput( side, color )\
11588redstone.setBundledOutput( side, colors )\
11589redstone.getBundledOutput( side )\
11590Type \"help bundled\" for usage examples.\
11591\
11592Events emitted by the redstone API:\
11593\"redstone\", when the state of any redstone input changes. Use getInput() or getBundledInput() to inspect the changes\
11594Type \"help events\" to learn about the event system.",
11595 [ "help/peripherals.txt" ] = "The \"peripherals\" program will list all of the peripheral devices accessible from this computer.\
11596Peripherals are external devices which CraftOS Computers and Turtles can interact with using the peripheral API.\
11597Type \"help peripheral\" to learn about using the peripheral API.\
11598Type \"help drives\" to learn about using Disk Drives.\
11599Type \"help modems\" to learn about using Modems.\
11600Type \"help monitors\" to learn about using Monitors.\
11601Type \"help printers\" to learn about using Printers.",
11602 [ "autorun/.ignoreme" ] = "--[[\
11603Alright then, don't ignore me. This file is to ensure the existence of the \"autorun\" folder, files placed in this folder\
11604using resource packs will always run when computers startup.\
11605]]",
11606 [ "help/earth.txt" ] = "Mostly harmless.",
11607 [ "programs/turtle/refuel.lua" ] = "\
11608local tArgs = { ... }\
11609local nLimit = 1\
11610if #tArgs > 1 then\
11611 print( \"Usage: refuel [number]\" )\
11612 return\
11613elseif #tArgs > 0 then\
11614 if tArgs[1] == \"all\" then\
11615 nLimit = 64 * 16\
11616 else\
11617 nLimit = tonumber( tArgs[1] )\
11618 end\
11619end\
11620\
11621if turtle.getFuelLevel() ~= \"unlimited\" then\
11622 for n=1,16 do\
11623 local nCount = turtle.getItemCount(n)\
11624 if nLimit > 0 and nCount > 0 and turtle.getFuelLevel() < turtle.getFuelLimit() then\
11625 local nBurn = math.min( nLimit, nCount )\
11626 turtle.select( n )\
11627 if turtle.refuel( nBurn ) then\
11628 local nNewCount = turtle.getItemCount(n)\
11629 nLimit = nLimit - (nCount - nNewCount)\
11630 end\
11631 end\
11632 end\
11633 print( \"Fuel level is \"..turtle.getFuelLevel() )\
11634 if turtle.getFuelLevel() == turtle.getFuelLimit() then\
11635 print( \"Fuel limit reached\" )\
11636 end\
11637else\
11638 print( \"Fuel level is unlimited\" )\
11639end",
11640 [ "help/paint.txt" ] = "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.\
11641\
11642ex:\
11643\"edit mario\" opens an image called \"mario\" for editing.",
11644 [ "help/bit.txt" ] = "Functions in the bit manipulation API (NOTE: This API will be removed in a future version. Use bit32 instead):\
11645bit.bnot(n) -- bitwise not (~n)\
11646bit.band(m, n) -- bitwise and (m & n)\
11647bit.bor(m, n) -- bitwise or (m | n)\
11648bit.bxor(m, n) -- bitwise xor (m ^ n)\
11649bit.brshift(n, bits) -- right shift (n >> bits)\
11650bit.blshift(n, bits) -- left shift (n << bits)",
11651 [ "help/drive.txt" ] = "drive tells you which disk drive the current or specified directory is located in.\
11652\
11653ex:\
11654\"drive\" tell you the disk drive of the current directory.\
11655\"drive foo\" tells you the disk drive of the subdirectory \"foo\"",
11656 [ "help/events.txt" ] = "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.\
11657\
11658Some events which can occur are:\
11659\"char\" when text is typed on the keyboard. Argument is the character typed.\
11660\"key\" when a key is pressed on the keyboard. Arguments are the keycode and whether the key is a repeat. Compare the keycode to the values in keys API to see which key was pressed.\
11661\"key_up\" when a key is released on the keyboard. Argument is the numerical keycode. Compare to the values in keys API to see which key was released.\
11662\"paste\" when text is pasted from the users keyboard. Argument is the line of text pasted.\
11663\
11664Events only on advanced computers:\
11665\"mouse_click\" when a user clicks the mouse. Arguments are button, xPos, yPos.\
11666\"mouse_drag\" when a user moves the mouse when held. Arguments are button, xPos, yPos.\
11667\"mouse_up\" when a user releases the mouse button. Arguments are button, xPos, yPos.\
11668\"mouse_scroll\" when a user uses the scrollwheel on the mouse. Arguments are direction, xPos, yPos.\
11669\
11670Other APIs and peripherals will emit their own events. See their respective help pages for details.",
11671 [ "help/help.txt" ] = "help is the help tool you're currently using.\
11672Type \"help index\" to see all help topics.\
11673Type \"help\" to see the help intro.\
11674Type \"help helpapi\" for information on the help Lua API.",
11675 [ "help/modems.txt" ] = "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\".\
11676\
11677Methods exposed by Modems:\
11678open( channel )\
11679isOpen( channel )\
11680close( channel )\
11681closeAll()\
11682transmit( channel, replyChannel, message )\
11683isWireless()\
11684\
11685Events fired by Modems:\
11686\"modem_message\" when a message is received on an open channel. Arguments are name, channel, replyChannel, message, distance",
11687 [ "help/keys.txt" ] = "The keys API contains constants for all the key codes that can be returned by the \"key\" event:\
11688\
11689Example usage:\
11690local sEvent, nKey = os.pullEvent()\
11691if sEvent == \"key\" and nKey == keys.enter then\
11692 -- Do something \
11693end\
11694\
11695See http://www.minecraftwiki.net/wiki/Key_codes, or the source code, for a complete reference.",
11696 [ "modules/turtle/.ignoreme" ] = "--[[\
11697Alright then, don't ignore me. This file is to ensure the existence of the \"modules/turtle\" folder.\
11698You can use this folder to add modules who can be loaded with require() to your Resourcepack.\
11699]]",
11700 [ "apis/window.lua" ] = "\
11701local tHex = {\
11702 [ colors.white ] = \"0\",\
11703 [ colors.orange ] = \"1\",\
11704 [ colors.magenta ] = \"2\",\
11705 [ colors.lightBlue ] = \"3\",\
11706 [ colors.yellow ] = \"4\",\
11707 [ colors.lime ] = \"5\",\
11708 [ colors.pink ] = \"6\",\
11709 [ colors.gray ] = \"7\",\
11710 [ colors.lightGray ] = \"8\",\
11711 [ colors.cyan ] = \"9\",\
11712 [ colors.purple ] = \"a\",\
11713 [ colors.blue ] = \"b\",\
11714 [ colors.brown ] = \"c\",\
11715 [ colors.green ] = \"d\",\
11716 [ colors.red ] = \"e\",\
11717 [ colors.black ] = \"f\",\
11718}\
11719\
11720local type = type\
11721local string_rep = string.rep\
11722local string_sub = string.sub\
11723local table_unpack = table.unpack\
11724\
11725function create( parent, nX, nY, nWidth, nHeight, bStartVisible )\
11726 if type( parent ) ~= \"table\" then error( \"bad argument #1 (expected table, got \" .. type( parent ) .. \")\", 2 ) end\
11727 if type( nX ) ~= \"number\" then error( \"bad argument #2 (expected number, got \" .. type( nX ) .. \")\", 2 ) end\
11728 if type( nY ) ~= \"number\" then error( \"bad argument #3 (expected number, got \" .. type( nY ) .. \")\", 2 ) end\
11729 if type( nWidth ) ~= \"number\" then error( \"bad argument #4 (expected number, got \" .. type( nWidth ) .. \")\", 2 ) end\
11730 if type( nHeight ) ~= \"number\" then error( \"bad argument #5 (expected number, got \" .. type( nHeight ) .. \")\", 2 ) end\
11731 if bStartVisible ~= nil and type( bStartVisible ) ~= \"boolean\" then error( \"bad argument #6 (expected boolean, got \" .. type( bStartVisible ) .. \")\", 2 ) end\
11732\
11733 if parent == term then\
11734 error( \"term is not a recommended window parent, try term.current() instead\", 2 )\
11735 end\
11736\
11737 local sEmptySpaceLine\
11738 local tEmptyColorLines = {}\
11739 local function createEmptyLines( nWidth )\
11740 sEmptySpaceLine = string_rep( \" \", nWidth )\
11741 for n=0,15 do\
11742 local nColor = 2^n\
11743 local sHex = tHex[nColor]\
11744 tEmptyColorLines[nColor] = string_rep( sHex, nWidth )\
11745 end\
11746 end\
11747\
11748 createEmptyLines( nWidth )\
11749\
11750 -- Setup\
11751 local bVisible = (bStartVisible ~= false)\
11752 local nCursorX = 1\
11753 local nCursorY = 1\
11754 local bCursorBlink = false\
11755 local nTextColor = colors.white\
11756 local nBackgroundColor = colors.black\
11757 local tLines = {}\
11758 local tPalette = {}\
11759 do\
11760 local sEmptyText = sEmptySpaceLine\
11761 local sEmptyTextColor = tEmptyColorLines[ nTextColor ]\
11762 local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ]\
11763 for y=1,nHeight do\
11764 tLines[y] = {\
11765 text = sEmptyText,\
11766 textColor = sEmptyTextColor,\
11767 backgroundColor = sEmptyBackgroundColor,\
11768 }\
11769 end\
11770\
11771 for i=0,15 do\
11772 local c = 2 ^ i\
11773 tPalette[c] = { parent.getPaletteColour( c ) }\
11774 end\
11775 end\
11776\
11777 -- Helper functions\
11778 local function updateCursorPos()\
11779 if nCursorX >= 1 and nCursorY >= 1 and\
11780 nCursorX <= nWidth and nCursorY <= nHeight then\
11781 parent.setCursorPos( nX + nCursorX - 1, nY + nCursorY - 1 )\
11782 else\
11783 parent.setCursorPos( 0, 0 )\
11784 end\
11785 end\
11786\
11787 local function updateCursorBlink()\
11788 parent.setCursorBlink( bCursorBlink )\
11789 end\
11790\
11791 local function updateCursorColor()\
11792 parent.setTextColor( nTextColor )\
11793 end\
11794\
11795 local function redrawLine( n )\
11796 local tLine = tLines[ n ]\
11797 parent.setCursorPos( nX, nY + n - 1 )\
11798 parent.blit( tLine.text, tLine.textColor, tLine.backgroundColor )\
11799 end\
11800\
11801 local function redraw()\
11802 for n=1,nHeight do\
11803 redrawLine( n )\
11804 end\
11805 end\
11806\
11807 local function updatePalette()\
11808 for k,v in pairs( tPalette ) do\
11809 parent.setPaletteColour( k, v[1], v[2], v[3] )\
11810 end\
11811 end\
11812\
11813 local function internalBlit( sText, sTextColor, sBackgroundColor )\
11814 local nStart = nCursorX\
11815 local nEnd = nStart + #sText - 1\
11816 if nCursorY >= 1 and nCursorY <= nHeight then\
11817 if nStart <= nWidth and nEnd >= 1 then\
11818 -- Modify line\
11819 local tLine = tLines[ nCursorY ]\
11820 if nStart == 1 and nEnd == nWidth then\
11821 tLine.text = sText\
11822 tLine.textColor = sTextColor\
11823 tLine.backgroundColor = sBackgroundColor\
11824 else\
11825 local sClippedText, sClippedTextColor, sClippedBackgroundColor\
11826 if nStart < 1 then\
11827 local nClipStart = 1 - nStart + 1\
11828 local nClipEnd = nWidth - nStart + 1\
11829 sClippedText = string_sub( sText, nClipStart, nClipEnd )\
11830 sClippedTextColor = string_sub( sTextColor, nClipStart, nClipEnd )\
11831 sClippedBackgroundColor = string_sub( sBackgroundColor, nClipStart, nClipEnd )\
11832 elseif nEnd > nWidth then\
11833 local nClipEnd = nWidth - nStart + 1\
11834 sClippedText = string_sub( sText, 1, nClipEnd )\
11835 sClippedTextColor = string_sub( sTextColor, 1, nClipEnd )\
11836 sClippedBackgroundColor = string_sub( sBackgroundColor, 1, nClipEnd )\
11837 else\
11838 sClippedText = sText\
11839 sClippedTextColor = sTextColor\
11840 sClippedBackgroundColor = sBackgroundColor\
11841 end\
11842\
11843 local sOldText = tLine.text\
11844 local sOldTextColor = tLine.textColor\
11845 local sOldBackgroundColor = tLine.backgroundColor\
11846 local sNewText, sNewTextColor, sNewBackgroundColor\
11847 if nStart > 1 then\
11848 local nOldEnd = nStart - 1\
11849 sNewText = string_sub( sOldText, 1, nOldEnd ) .. sClippedText\
11850 sNewTextColor = string_sub( sOldTextColor, 1, nOldEnd ) .. sClippedTextColor\
11851 sNewBackgroundColor = string_sub( sOldBackgroundColor, 1, nOldEnd ) .. sClippedBackgroundColor\
11852 else\
11853 sNewText = sClippedText\
11854 sNewTextColor = sClippedTextColor\
11855 sNewBackgroundColor = sClippedBackgroundColor\
11856 end\
11857 if nEnd < nWidth then\
11858 local nOldStart = nEnd + 1\
11859 sNewText = sNewText .. string_sub( sOldText, nOldStart, nWidth )\
11860 sNewTextColor = sNewTextColor .. string_sub( sOldTextColor, nOldStart, nWidth )\
11861 sNewBackgroundColor = sNewBackgroundColor .. string_sub( sOldBackgroundColor, nOldStart, nWidth )\
11862 end\
11863\
11864 tLine.text = sNewText\
11865 tLine.textColor = sNewTextColor\
11866 tLine.backgroundColor = sNewBackgroundColor\
11867 end\
11868\
11869 -- Redraw line\
11870 if bVisible then\
11871 redrawLine( nCursorY )\
11872 end\
11873 end\
11874 end\
11875\
11876 -- Move and redraw cursor\
11877 nCursorX = nEnd + 1\
11878 if bVisible then\
11879 updateCursorColor()\
11880 updateCursorPos()\
11881 end\
11882 end\
11883\
11884 -- Terminal implementation\
11885 local window = {}\
11886\
11887 function window.write( sText )\
11888 sText = tostring( sText )\
11889 internalBlit( sText, string_rep( tHex[ nTextColor ], #sText ), string_rep( tHex[ nBackgroundColor ], #sText ) )\
11890 end\
11891\
11892 function window.blit( sText, sTextColor, sBackgroundColor )\
11893 if type( sText ) ~= \"string\" then error( \"bad argument #1 (expected string, got \" .. type( sText ) .. \")\", 2 ) end\
11894 if type( sTextColor ) ~= \"string\" then error( \"bad argument #2 (expected string, got \" .. type( sTextColor ) .. \")\", 2 ) end\
11895 if type( sBackgroundColor ) ~= \"string\" then error( \"bad argument #3 (expected string, got \" .. type( sBackgroundColor ) .. \")\", 2 ) end\
11896 if #sTextColor ~= #sText or #sBackgroundColor ~= #sText then\
11897 error( \"Arguments must be the same length\", 2 )\
11898 end\
11899 internalBlit( sText, sTextColor, sBackgroundColor )\
11900 end\
11901\
11902 function window.clear()\
11903 local sEmptyText = sEmptySpaceLine\
11904 local sEmptyTextColor = tEmptyColorLines[ nTextColor ]\
11905 local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ]\
11906 for y=1,nHeight do\
11907 tLines[y] = {\
11908 text = sEmptyText,\
11909 textColor = sEmptyTextColor,\
11910 backgroundColor = sEmptyBackgroundColor,\
11911 }\
11912 end\
11913 if bVisible then\
11914 redraw()\
11915 updateCursorColor()\
11916 updateCursorPos()\
11917 end\
11918 end\
11919\
11920 function window.clearLine()\
11921 if nCursorY >= 1 and nCursorY <= nHeight then\
11922 local sEmptyText = sEmptySpaceLine\
11923 local sEmptyTextColor = tEmptyColorLines[ nTextColor ]\
11924 local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ]\
11925 tLines[ nCursorY ] = {\
11926 text = sEmptyText,\
11927 textColor = sEmptyTextColor,\
11928 backgroundColor = sEmptyBackgroundColor,\
11929 }\
11930 if bVisible then\
11931 redrawLine( nCursorY )\
11932 updateCursorColor()\
11933 updateCursorPos()\
11934 end\
11935 end\
11936 end\
11937\
11938 function window.getCursorPos()\
11939 return nCursorX, nCursorY\
11940 end\
11941\
11942 function window.setCursorPos( x, y )\
11943 if type( x ) ~= \"number\" then error( \"bad argument #1 (expected number, got \" .. type( x ) .. \")\", 2 ) end\
11944 if type( y ) ~= \"number\" then error( \"bad argument #2 (expected number, got \" .. type( y ) .. \")\", 2 ) end\
11945 nCursorX = math.floor( x )\
11946 nCursorY = math.floor( y )\
11947 if bVisible then\
11948 updateCursorPos()\
11949 end\
11950 end\
11951\
11952 function window.setCursorBlink( blink )\
11953 if type( blink ) ~= \"boolean\" then error( \"bad argument #1 (expected boolean, got \" .. type( blink ) .. \")\", 2 ) end\
11954 bCursorBlink = blink\
11955 if bVisible then\
11956 updateCursorBlink()\
11957 end\
11958 end\
11959\
11960 function window.getCursorBlink()\
11961 return bCursorBlink\
11962 end\
11963\
11964 local function isColor()\
11965 return parent.isColor()\
11966 end\
11967\
11968 function window.isColor()\
11969 return isColor()\
11970 end\
11971\
11972 function window.isColour()\
11973 return isColor()\
11974 end\
11975\
11976 local function setTextColor( color )\
11977 if type( color ) ~= \"number\" then\
11978 error( \"bad argument #1 (expected number, got \" .. type( color ) .. \")\", 2 )\
11979 elseif tHex[color] == nil then\
11980 error( \"Invalid color (got \" .. color .. \")\" , 2 )\
11981 end\
11982 nTextColor = color\
11983 if bVisible then\
11984 updateCursorColor()\
11985 end\
11986 end\
11987\
11988 window.setTextColor = setTextColor\
11989 window.setTextColour = setTextColor\
11990\
11991 function window.setPaletteColour( colour, r, g, b )\
11992 if type( colour ) ~= \"number\" then error( \"bad argument #1 (expected number, got \" .. type( colour ) .. \")\", 2 ) end\
11993\
11994 if tHex[colour] == nil then\
11995 error( \"Invalid color (got \" .. colour .. \")\" , 2 )\
11996 end\
11997\
11998 local tCol\
11999 if type(r) == \"number\" and g == nil and b == nil then\
12000 tCol = { colours.rgb8( r ) }\
12001 tPalette[ colour ] = tCol\
12002 else\
12003 if type( r ) ~= \"number\" then error( \"bad argument #2 (expected number, got \" .. type( r ) .. \")\", 2 ) end\
12004 if type( g ) ~= \"number\" then error( \"bad argument #3 (expected number, got \" .. type( g ) .. \")\", 2 ) end\
12005 if type( b ) ~= \"number\" then error( \"bad argument #4 (expected number, got \" .. type( b ) .. \")\", 2 ) end\
12006\
12007 tCol = tPalette[ colour ]\
12008 tCol[1] = r\
12009 tCol[2] = g\
12010 tCol[3] = b\
12011 end\
12012\
12013 if bVisible then\
12014 return parent.setPaletteColour( colour, tCol[1], tCol[2], tCol[3] )\
12015 end\
12016 end\
12017\
12018 window.setPaletteColor = window.setPaletteColour\
12019\
12020 function window.getPaletteColour( colour )\
12021 if type( colour ) ~= \"number\" then error( \"bad argument #1 (expected number, got \" .. type( colour ) .. \")\", 2 ) end\
12022 if tHex[colour] == nil then\
12023 error( \"Invalid color (got \" .. colour .. \")\" , 2 )\
12024 end\
12025 local tCol = tPalette[ colour ]\
12026 return tCol[1], tCol[2], tCol[3]\
12027 end\
12028\
12029 window.getPaletteColor = window.getPaletteColour\
12030\
12031 local function setBackgroundColor( color )\
12032 if type( color ) ~= \"number\" then\
12033 error( \"bad argument #1 (expected number, got \" .. type( color ) .. \")\", 2 )\
12034 elseif tHex[color] == nil then\
12035 error( \"Invalid color (got \" .. color .. \")\", 2 )\
12036 end\
12037 nBackgroundColor = color\
12038 end\
12039\
12040 window.setBackgroundColor = setBackgroundColor\
12041 window.setBackgroundColour = setBackgroundColor\
12042\
12043 function window.getSize()\
12044 return nWidth, nHeight\
12045 end\
12046\
12047 function window.scroll( n )\
12048 if type( n ) ~= \"number\" then error( \"bad argument #1 (expected number, got \" .. type( n ) .. \")\", 2 ) end\
12049 if n ~= 0 then\
12050 local tNewLines = {}\
12051 local sEmptyText = sEmptySpaceLine\
12052 local sEmptyTextColor = tEmptyColorLines[ nTextColor ]\
12053 local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ]\
12054 for newY=1,nHeight do\
12055 local y = newY + n\
12056 if y >= 1 and y <= nHeight then\
12057 tNewLines[newY] = tLines[y]\
12058 else\
12059 tNewLines[newY] = {\
12060 text = sEmptyText,\
12061 textColor = sEmptyTextColor,\
12062 backgroundColor = sEmptyBackgroundColor,\
12063 }\
12064 end\
12065 end\
12066 tLines = tNewLines\
12067 if bVisible then\
12068 redraw()\
12069 updateCursorColor()\
12070 updateCursorPos()\
12071 end\
12072 end\
12073 end\
12074\
12075 function window.getTextColor()\
12076 return nTextColor\
12077 end\
12078\
12079 function window.getTextColour()\
12080 return nTextColor\
12081 end\
12082\
12083 function window.getBackgroundColor()\
12084 return nBackgroundColor\
12085 end\
12086\
12087 function window.getBackgroundColour()\
12088 return nBackgroundColor\
12089 end\
12090\
12091 -- Other functions\
12092 function window.setVisible( bVis )\
12093 if type( bVis ) ~= \"boolean\" then error( \"bad argument #1 (expected boolean, got \" .. type( bVis ) .. \")\", 2 ) end\
12094 if bVisible ~= bVis then\
12095 bVisible = bVis\
12096 if bVisible then\
12097 window.redraw()\
12098 end\
12099 end\
12100 end\
12101\
12102 function window.redraw()\
12103 if bVisible then\
12104 redraw()\
12105 updatePalette()\
12106 updateCursorBlink()\
12107 updateCursorColor()\
12108 updateCursorPos()\
12109 end\
12110 end\
12111\
12112 function window.restoreCursor()\
12113 if bVisible then\
12114 updateCursorBlink()\
12115 updateCursorColor()\
12116 updateCursorPos()\
12117 end\
12118 end\
12119\
12120 function window.getPosition()\
12121 return nX, nY\
12122 end\
12123\
12124 function window.reposition( nNewX, nNewY, nNewWidth, nNewHeight )\
12125 if type( nNewX ) ~= \"number\" then error( \"bad argument #1 (expected number, got \" .. type( nNewX ) .. \")\", 2 ) end\
12126 if type( nNewY ) ~= \"number\" then error( \"bad argument #2 (expected number, got \" .. type( nNewY ) .. \")\", 2 ) end\
12127 if nNewWidth ~= nil or nNewHeight ~= nil then\
12128 if type( nNewWidth ) ~= \"number\" then error( \"bad argument #3 (expected number, got \" .. type( nNewWidth ) .. \")\", 2 ) end\
12129 if type( nNewHeight ) ~= \"number\" then error( \"bad argument #4 (expected number, got \" .. type( nNewHeight ) .. \")\", 2 ) end\
12130 end\
12131\
12132 nX = nNewX\
12133 nY = nNewY\
12134 if nNewWidth and nNewHeight then\
12135 local tNewLines = {}\
12136 createEmptyLines( nNewWidth )\
12137 local sEmptyText = sEmptySpaceLine\
12138 local sEmptyTextColor = tEmptyColorLines[ nTextColor ]\
12139 local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ]\
12140 for y=1,nNewHeight do\
12141 if y > nHeight then\
12142 tNewLines[y] = {\
12143 text = sEmptyText,\
12144 textColor = sEmptyTextColor,\
12145 backgroundColor = sEmptyBackgroundColor\
12146 }\
12147 else\
12148 local tOldLine = tLines[y]\
12149 if nNewWidth == nWidth then\
12150 tNewLines[y] = tOldLine\
12151 elseif nNewWidth < nWidth then\
12152 tNewLines[y] = {\
12153 text = string_sub( tOldLine.text, 1, nNewWidth ),\
12154 textColor = string_sub( tOldLine.textColor, 1, nNewWidth ),\
12155 backgroundColor = string_sub( tOldLine.backgroundColor, 1, nNewWidth ),\
12156 }\
12157 else\
12158 tNewLines[y] = {\
12159 text = tOldLine.text .. string_sub( sEmptyText, nWidth + 1, nNewWidth ),\
12160 textColor = tOldLine.textColor .. string_sub( sEmptyTextColor, nWidth + 1, nNewWidth ),\
12161 backgroundColor = tOldLine.backgroundColor .. string_sub( sEmptyBackgroundColor, nWidth + 1, nNewWidth ),\
12162 }\
12163 end\
12164 end\
12165 end\
12166 nWidth = nNewWidth\
12167 nHeight = nNewHeight\
12168 tLines = tNewLines\
12169 end\
12170 if bVisible then\
12171 window.redraw()\
12172 end\
12173 end\
12174\
12175 if bVisible then\
12176 window.redraw()\
12177 end\
12178 return window\
12179end",
12180 },
12181 compressed = false,
12182 main = false,
12183}