· 6 years ago · May 23, 2019, 06:10 AM
1{
2 mainFile = false,
3 compressed = false,
4 data = {
5 [ "help/pocket.txt" ] = "pocket is an API available on pocket computers, which allows modifying its upgrades.\
6Functions in the pocket API:\
7pocket.equipBack()\
8pocket.unequipBack()\
9\
10When 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.",
11 [ "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.\
12\
13ex:\
14\"chat host forgecraft\" will create a chatroom with the name \"forgecraft\"\
15\"chat join forgecraft direwolf20\" will connect to the chatroom with the name \"forgecraft\", using the nickname \"direwolf20\"",
16 [ "apis/keys.lua" ] = "\
17-- Minecraft key code bindings\
18-- See http://www.minecraftwiki.net/wiki/Key_codes for more info\
19\
20local tKeys = {\
21 nil, \"one\", \"two\", \"three\", \"four\", -- 1\
22 \"five\", \"six\", \"seven\", \"eight\", \"nine\", -- 6\
23 \"zero\", \"minus\", \"equals\", \"backspace\",\"tab\", -- 11\
24 \"q\", \"w\", \"e\", \"r\", \"t\", -- 16\
25 \"y\", \"u\", \"i\", \"o\", \"p\", -- 21\
26 \"leftBracket\",\"rightBracket\",\"enter\",\"leftCtrl\",\"a\", -- 26\
27 \"s\", \"d\", \"f\", \"g\", \"h\", -- 31\
28 \"j\", \"k\", \"l\", \"semiColon\",\"apostrophe\", -- 36\
29 \"grave\", \"leftShift\",\"backslash\",\"z\", \"x\", -- 41\
30 \"c\", \"v\", \"b\", \"n\", \"m\", -- 46\
31 \"comma\", \"period\", \"slash\", \"rightShift\",\"multiply\", -- 51\
32 \"leftAlt\", \"space\", \"capsLock\", \"f1\", \"f2\", -- 56\
33 \"f3\", \"f4\", \"f5\", \"f6\", \"f7\", -- 61\
34 \"f8\", \"f9\", \"f10\", \"numLock\", \"scrollLock\", -- 66\
35 \"numPad7\", \"numPad8\", \"numPad9\", \"numPadSubtract\",\"numPad4\", -- 71\
36 \"numPad5\", \"numPad6\", \"numPadAdd\",\"numPad1\", \"numPad2\", -- 76\
37 \"numPad3\", \"numPad0\", \"numPadDecimal\",nil, nil, -- 81\
38 nil, \"f11\", \"f12\", nil, nil, -- 86\
39 nil, nil, nil, nil, nil, -- 91\
40 nil, nil, nil, nil, \"f13\", -- 96\
41 \"f14\", \"f15\", nil, nil, nil, -- 101\
42 nil, nil, nil, nil, nil, -- 106\
43 nil, \"kana\", nil, nil, nil, -- 111\
44 nil, nil, nil, nil, nil, -- 116\
45 \"convert\", nil, \"noconvert\",nil, \"yen\", -- 121\
46 nil, nil, nil, nil, nil, -- 126\
47 nil, nil, nil, nil, nil, -- 131\
48 nil, nil, nil, nil, nil, -- 136\
49 \"numPadEquals\",nil, nil, \"circumflex\",\"at\", -- 141\
50 \"colon\", \"underscore\",\"kanji\", \"stop\", \"ax\", -- 146\
51 nil, nil, nil, nil, nil, -- 151\
52 \"numPadEnter\",\"rightCtrl\",nil, nil, nil, -- 156\
53 nil, nil, nil, nil, nil, -- 161\
54 nil, nil, nil, nil, nil, -- 166\
55 nil, nil, nil, nil, nil, -- 171\
56 nil, nil, nil, \"numPadComma\",nil, -- 176\
57 \"numPadDivide\",nil, nil, \"rightAlt\", nil, -- 181\
58 nil, nil, nil, nil, nil, -- 186\
59 nil, nil, nil, nil, nil, -- 191\
60 nil, \"pause\", nil, \"home\", \"up\", -- 196\
61 \"pageUp\", nil, \"left\", nil, \"right\", -- 201\
62 nil, \"end\", \"down\", \"pageDown\", \"insert\", -- 206\
63 \"delete\" -- 211\
64}\
65\
66local keys = _ENV\
67for nKey, sKey in pairs( tKeys ) do\
68 keys[sKey] = nKey\
69end\
70keys[\"return\"] = keys.enter\
71--backwards compatibility to earlier, typo prone, versions\
72keys.scollLock = keys.scrollLock\
73keys.cimcumflex = keys.circumflex\
74\
75function getName( _nKey )\
76 if type( _nKey ) ~= \"number\" then\
77 error( \"bad argument #1 (expected number, got \" .. type( _nKey ) .. \")\", 2 )\
78 end\
79 return tKeys[ _nKey ]\
80end",
81 [ "programs/fun/advanced/levels/3.dat" ] = "2\
82 77777777\
83777888188777\
847b78777787b7\
8578787 78787\
8678787 78787\
8778887 78887\
88777877778777\
89 78838887\
90 77777777",
91 [ "programs/fun/advanced/levels/7.dat" ] = "3\
92728777778b7\
9378888888887\
9478777877787\
95787 787 787\
96787 7877788\
97787 7888889\
9888777877777\
99e888887\
1007777887",
101 [ "help/textutils.txt" ] = "Functions in the Text Utilities API:\
102textutils.slowPrint( text )\
103textutils.tabulate( table, table2, ... )\
104textutils.pagedTabulate( table, table2, ... )\
105textutils.formatTime( time, bTwentyFourHour )\
106textutils.serialize( table )\
107textutils.unserialize( string )\
108textutils.serializeJSON( table, [useNBTStyle] )\
109textutils.urlEncode( string )\
110textutils.complete( string, table )",
111 [ "help/shell.txt" ] = "shell is the toplevel program which interprets commands and runs program.\
112Type \"help shellapi\" for information about the shell lua api.",
113 [ "programs/clear.lua" ] = "term.clear()\
114term.setCursorPos( 1, 1 )",
115 [ "programs/fun/advanced/levels/1.dat" ] = "1\
116 777\
117 7b7\
118 787\
1197777778777\
1207188888887\
1217777777777",
122 [ "help/math.txt" ] = "math is a standard Lua5.1 API.\
123Refer to http://www.lua.org/manual/5.1/ for more information.",
124 [ "help/hello.txt" ] = "hello prints the text \"Hello World!\" to the screen.",
125 [ "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\".\
126\
127Methods exposed by the Disk Drive:\
128isDiskPresent()\
129getDiskLabel()\
130setDiskLabel( label )\
131hasData()\
132getMountPath()\
133hasAudio()\
134getAudioTitle()\
135playAudio()\
136stopAudio()\
137ejectDisk()\
138getDiskID()\
139\
140Events fired by the Disk Drive:\
141\"disk\" when a disk or other item is inserted into the drive. Argument is the name of the drive.\
142\"disk_eject\" when a disk is removed from a drive. Argument is the name of the drive.\
143Type \"help events\" to learn about the event system.",
144 [ "help/table.txt" ] = "table is a standard Lua5.1 API.\
145Refer to http://www.lua.org/manual/5.1/ for more information.",
146 [ "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!",
147 [ "help/move.txt" ] = "mv moves a file or directory from one location to another.\
148\
149ex:\
150\"mv foo bar\" renames the file \"foo\" to \"bar\".\
151\"mv foo bar/foo\" moves the file \"foo\" to a folder called \"bar\".\
152\"mv disk/* disk2\" moves the contents of one disk to another",
153 [ "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\".\
154\
155Methods exposed by the Speaker:\
156playSound( sResourceName, nVolume, nPitch )\
157playNote( sInstrumentName, nVolume, nPitch )\
158\
159Resource name is the same as used by the /playsound command, such as \"minecraft:entity.cow.ambient\".\
160Instruments 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.\
161Ticks is the amount of times a noteblock has been tuned (right clicked).",
162 [ "apis/vector.lua" ] = "\
163local vector = {\
164 add = function( self, o )\
165 return vector.new(\
166 self.x + o.x,\
167 self.y + o.y,\
168 self.z + o.z\
169 )\
170 end,\
171 sub = function( self, o )\
172 return vector.new(\
173 self.x - o.x,\
174 self.y - o.y,\
175 self.z - o.z\
176 )\
177 end,\
178 mul = function( self, m )\
179 return vector.new(\
180 self.x * m,\
181 self.y * m,\
182 self.z * m\
183 )\
184 end,\
185 div = function( self, m )\
186 return vector.new(\
187 self.x / m,\
188 self.y / m,\
189 self.z / m\
190 )\
191 end,\
192 unm = function( self )\
193 return vector.new(\
194 -self.x,\
195 -self.y,\
196 -self.z\
197 )\
198 end,\
199 dot = function( self, o )\
200 return self.x*o.x + self.y*o.y + self.z*o.z\
201 end,\
202 cross = function( self, o )\
203 return vector.new(\
204 self.y*o.z - self.z*o.y,\
205 self.z*o.x - self.x*o.z,\
206 self.x*o.y - self.y*o.x\
207 )\
208 end,\
209 length = function( self )\
210 return math.sqrt( self.x*self.x + self.y*self.y + self.z*self.z )\
211 end,\
212 normalize = function( self )\
213 return self:mul( 1 / self:length() )\
214 end,\
215 round = function( self, nTolerance )\
216 nTolerance = nTolerance or 1.0\
217 return vector.new(\
218 math.floor( (self.x + (nTolerance * 0.5)) / nTolerance ) * nTolerance,\
219 math.floor( (self.y + (nTolerance * 0.5)) / nTolerance ) * nTolerance,\
220 math.floor( (self.z + (nTolerance * 0.5)) / nTolerance ) * nTolerance\
221 )\
222 end,\
223 tostring = function( self )\
224 return self.x..\",\"..self.y..\",\"..self.z\
225 end,\
226}\
227\
228local vmetatable = {\
229 __index = vector,\
230 __add = vector.add,\
231 __sub = vector.sub,\
232 __mul = vector.mul,\
233 __div = vector.div,\
234 __unm = vector.unm,\
235 __tostring = vector.tostring,\
236}\
237\
238function new( x, y, z )\
239 local v = {\
240 x = tonumber(x) or 0,\
241 y = tonumber(y) or 0,\
242 z = tonumber(z) or 0\
243 }\
244 setmetatable( v, vmetatable )\
245 return v\
246end",
247 [ "help/type.txt" ] = "type determines the type of a file or directory. Prints \"file\", \"directory\" or \"does not exist\".",
248 [ "help/tunnel.txt" ] = "tunnel is a program for Mining Turtles. Tunnel will mine a 3x2 tunnel of the depth specified.\
249\
250ex:\
251\"tunnel 20\" will tunnel a tunnel 20 blocks long.",
252 [ "help/redstone.txt" ] = "The redstone program can be used to get, set or pulse redstone inputs and outputs from the computer.\
253\
254ex:\
255\"redstone probe\" will list all the redstone inputs to the computer\
256\"redstone set left true\" turns on the left redstone output.\
257\"redstone set right blue false\" turns off the blue wire in the bundled cable on the right redstone output.\
258\"redstone pulse front 10 1\" emits 10 one second redstone pulses on the front redstone output.\
259\
260Type \"help redstoneapi\" or \"help rs\" for information on the redstone Lua API.",
261 [ "programs/turtle/craft.lua" ] = "\
262if not turtle.craft then\
263 print( \"Requires a Crafty Turtle\" )\
264 return\
265end\
266\
267local tArgs = { ... }\
268local nLimit = nil\
269if #tArgs < 1 then\
270 print( \"Usage: craft [number]\" )\
271 return\
272else\
273 nLimit = tonumber( tArgs[1] )\
274end\
275\
276local nCrafted = 0\
277local nOldCount = turtle.getItemCount( turtle.getSelectedSlot() )\
278if turtle.craft( nLimit ) then\
279 local nNewCount = turtle.getItemCount( turtle.getSelectedSlot() )\
280 if nOldCount <= nLimit then\
281 nCrafted = nNewCount\
282 else\
283 nCrafted = nOldCount - nNewCount\
284 end\
285end\
286\
287if nCrafted > 1 then\
288 print( nCrafted..\" items crafted\" )\
289elseif nCrafted == 1 then\
290 print( \"1 item crafted\" )\
291else\
292 print( \"No items crafted\" )\
293end",
294 [ "programs/move.lua" ] = "\
295local tArgs = { ... }\
296if #tArgs < 2 then\
297 print( \"Usage: mv <source> <destination>\" )\
298 return\
299end\
300\
301local sSource = shell.resolve( tArgs[1] )\
302local sDest = shell.resolve( tArgs[2] )\
303local tFiles = fs.find( sSource )\
304if #tFiles > 0 then\
305 for n,sFile in ipairs( tFiles ) do\
306 if fs.isDir( sDest ) then\
307 fs.move( sFile, fs.combine( sDest, fs.getName(sFile) ) )\
308 elseif #tFiles == 1 then\
309 fs.move( sFile, sDest )\
310 else\
311 printError( \"Cannot overwrite file multiple times\" )\
312 return\
313 end\
314 end\
315else\
316 printError( \"No matching files\" )\
317end",
318 [ "programs/rename.lua" ] = "local tArgs = { ... }\
319if #tArgs < 2 then\
320 print( \"Usage: rename <source> <destination>\" )\
321 return\
322end\
323\
324local sSource = shell.resolve( tArgs[1] )\
325local sDest = shell.resolve( tArgs[2] )\
326\
327if fs.exists( sDest ) then\
328 printError( \"Destination exists\" )\
329end\
330\
331fs.move( sSource, sDest )",
332 [ "programs/fun/advanced/redirection.lua" ] = "--CCRedirection by : RamiLego4Game and Dan200--\
333--Based on Redirection by Dan200: http://www.redirectiongame.com--\
334--Clearing Screen--\
335\
336--Vars--\
337local TermW,TermH = term.getSize()\
338\
339local sLevelTitle\
340local tScreen\
341local oScreen\
342local SizeW,SizeH\
343local aExits\
344local fExit\
345local nSpeed\
346local Speed\
347local fSpeed\
348local fSpeedS\
349local bPaused\
350local Tick\
351local Blocks\
352local XOrgin,YOrgin\
353local fLevel\
354\
355local function reset()\
356 sLevelTitle = \"\"\
357 tScreen = {}\
358 oScreen = {}\
359 SizeW,SizeH = TermW,TermH\
360 aExits = 0\
361 fExit = \"nop\"\
362 nSpeed = 0.6\
363 Speed = nSpeed\
364 fSpeed = 0.2\
365 fSpeedS = false\
366 bPaused = false\
367 Tick = os.startTimer(Speed)\
368 Blocks = 0\
369 XOrgin,YOrgin = 1,1\
370\
371 term.setBackgroundColor(colors.black)\
372 term.setTextColor(colors.white)\
373 term.clear()\
374end\
375\
376local InterFace = {}\
377InterFace.cExit = colors.red\
378InterFace.cSpeedD = colors.white\
379InterFace.cSpeedA = colors.red\
380InterFace.cTitle = colors.red\
381\
382local cG = colors.lightGray\
383local cW = colors.gray\
384local cS = colors.black\
385local cR1 = colors.blue\
386local cR2 = colors.red\
387local cR3 = colors.green\
388local cR4 = colors.yellow\
389\
390local tArgs = { ... }\
391\
392--Functions--\
393local function printCentred( yc, stg )\
394 local xc = math.floor((TermW - string.len(stg)) / 2) + 1\
395 term.setCursorPos(xc,yc)\
396 term.write( stg )\
397end\
398\
399local function centerOrgin()\
400 XOrgin = math.floor((TermW/2)-(SizeW/2))\
401 YOrgin = math.floor((TermH/2)-(SizeH/2))\
402end\
403\
404local function reMap()\
405 tScreen = nil\
406 tScreen = {}\
407 for x=1,SizeW do\
408 tScreen[x] = {}\
409 for y=1,SizeH do\
410 tScreen[x][y] = { space = true, wall = false, ground = false, robot = \"zz\", start = \"zz\", exit = \"zz\" }\
411 end\
412 end\
413end\
414\
415local function tablecopy(t)\
416 local t2 = {}\
417 for k,v in pairs(t) do\
418 t2[k] = v\
419 end\
420 return t2\
421end\
422\
423local function buMap()\
424 oScreen = nil\
425 oScreen = {}\
426 for x=1,SizeW do\
427 oScreen[x] = {}\
428 for y=1,SizeH do\
429 oScreen[x][y] = tablecopy(tScreen[x][y])\
430 end\
431 end\
432end\
433\
434local function addRobot(x,y,side,color)\
435 local obj = tScreen[x][y]\
436 local data = side..color\
437 if obj.wall == nil and obj.robot == nil then\
438 tScreen[x][y].robot = data\
439 else\
440 obj.wall = nil\
441 obj.robot = \"zz\"\
442 tScreen[x][y].robot = data\
443 end\
444end\
445\
446local function addStart(x,y,side,color)\
447 local obj = tScreen[x][y]\
448 local data = side..color\
449 if obj.wall == nil and obj.space == nil then\
450 tScreen[x][y].start = data\
451 else\
452 obj.wall = nil\
453 obj.space = nil\
454 tScreen[x][y].start = data\
455 end\
456 aExits = aExits+1\
457end\
458\
459local function addGround(x,y)\
460 local obj = tScreen[x][y]\
461 if obj.space == nil and obj.exit == nil and obj.wall == nil and obj.robot == nil and obj.start == nil then\
462 tScreen[x][y].ground = true\
463 else\
464 obj.space = nil\
465 obj.exit = \"zz\"\
466 obj.wall = nil\
467 obj.robot = \"zz\"\
468 obj.start = \"zz\"\
469 tScreen[x][y].ground = true\
470 end\
471end\
472\
473local function addExit(x,y,cl)\
474 local obj = tScreen[x][y]\
475 if obj.space == nil and obj.ground == nil and obj.wall == nil and obj.robot == nil and obj.start == nil then\
476 tScreen[x][y].exit = cl\
477 else\
478 obj.space = nil\
479 obj.ground = nil\
480 obj.wall = nil\
481 obj.robot = \"zz\"\
482 obj.start = \"zz\"\
483 tScreen[x][y].exit = cl\
484 end\
485end\
486\
487local function addWall(x,y)\
488 local obj = tScreen[x][y]\
489 if obj == nil then\
490 return error(\"Here X\"..x..\" Y\"..y)\
491 end\
492 if obj.space == nil and obj.exit == nil and obj.ground == nil and obj.robot == nil and obj.start == nil then\
493 tScreen[x][y].wall = true\
494 else\
495 obj.space = nil\
496 obj.exit = nil\
497 obj.ground = nil\
498 obj.robot = nil\
499 obj.start = nil\
500 tScreen[x][y].wall = true\
501 end\
502end\
503\
504local function loadLevel(nNum)\
505 sLevelTitle = \"Level \"..nNum\
506 if nNum == nil then return error(\"nNum == nil\") end\
507 local sDir = fs.getDir( shell.getRunningProgram() )\
508 local sLevelD = sDir .. \"/levels/\" .. tostring(nNum)..\".dat\"\
509 if not ( fs.exists(sLevelD) or fs.isDir(sLevelD) ) then return error(\"Level Not Exists : \"..sLevelD) end\
510 fLevel = fs.open(sLevelD,\"r\")\
511 local Line = 0\
512 local wl = true\
513 Blocks = tonumber(string.sub(fLevel.readLine(),1,1))\
514 local xSize = string.len(fLevel.readLine())+2\
515 local Lines = 3\
516 while wl do\
517 local wLine = fLevel.readLine()\
518 if wLine == nil then\
519 fLevel.close()\
520 wl = false\
521 else\
522 xSize = math.max(string.len(wLine)+2,xSize)\
523 Lines = Lines + 1\
524 end\
525 end\
526 SizeW,SizeH = xSize,Lines\
527 reMap()\
528 fLevel = fs.open(sLevelD,\"r\")\
529 fLevel.readLine()\
530 for Line=2,Lines-1 do\
531 local sLine = fLevel.readLine()\
532 local chars = string.len(sLine)\
533 for char = 1, chars do\
534 local el = string.sub(sLine,char,char)\
535 if el == \"8\" then\
536 addGround(char+1,Line)\
537 elseif el == \"0\" then\
538 addStart(char+1,Line,\"a\",\"a\")\
539 elseif el == \"1\" then\
540 addStart(char+1,Line,\"b\",\"a\")\
541 elseif el == \"2\" then\
542 addStart(char+1,Line,\"c\",\"a\")\
543 elseif el == \"3\" then\
544 addStart(char+1,Line,\"d\",\"a\")\
545 elseif el == \"4\" then\
546 addStart(char+1,Line,\"a\",\"b\")\
547 elseif el == \"5\" then\
548 addStart(char+1,Line,\"b\",\"b\")\
549 elseif el == \"6\" then\
550 addStart(char+1,Line,\"c\",\"b\")\
551 elseif el == \"9\" then\
552 addStart(char+1,Line,\"d\",\"b\")\
553 elseif el == \"b\" then\
554 addExit(char+1,Line,\"a\")\
555 elseif el == \"e\" then\
556 addExit(char+1,Line,\"b\")\
557 elseif el == \"7\" then\
558 addWall(char+1,Line)\
559 end\
560 end\
561 end\
562 fLevel.close()\
563end\
564\
565local function drawStars()\
566 --CCR Background By : RamiLego--\
567 local cStar,cStarG,crStar,crStarB = colors.lightGray,colors.gray,\".\",\"*\"\
568 local DStar,BStar,nStar,gStar = 14,10,16,3\
569 local TermW,TermH = term.getSize()\
570\
571 term.clear()\
572 term.setCursorPos(1,1)\
573 for x=1,TermW do\
574 for y=1,TermH do\
575 local StarT = math.random(1,30)\
576 if StarT == DStar then\
577 term.setCursorPos(x,y)\
578 term.setTextColor(cStar)\
579 write(crStar)\
580 elseif StarT == BStar then\
581 term.setCursorPos(x,y)\
582 term.setTextColor(cStar)\
583 write(crStarB)\
584 elseif StarT == nStar then\
585 term.setCursorPos(x,y)\
586 term.setTextColor(cStarG)\
587 write(crStar)\
588 elseif StarT == gStar then\
589 term.setCursorPos(x,y)\
590 term.setTextColor(cStarG)\
591 write(crStarB)\
592 end\
593 end\
594 end\
595end\
596\
597local function drawMap()\
598 for x=1,SizeW do\
599 for y=1,SizeH do\
600\
601 local obj = tScreen[x][y]\
602 if obj.ground == true then\
603 paintutils.drawPixel(XOrgin+x,YOrgin+y+1,cG)\
604 end\
605 if obj.wall == true then\
606 paintutils.drawPixel(XOrgin+x,YOrgin+y+1,cW)\
607 end\
608\
609 local ex = tostring(tScreen[x][y].exit)\
610 if not(ex == \"zz\" or ex == \"nil\") then\
611 if ex == \"a\" then\
612 ex = cR1\
613 elseif ex == \"b\" then\
614 ex = cR2\
615 elseif ex == \"c\" then\
616 ex = cR3\
617 elseif ex == \"d\" then\
618 ex = cR4\
619 else\
620 return error(\"Exit Color Out\")\
621 end\
622 term.setBackgroundColor(cG)\
623 term.setTextColor(ex)\
624 term.setCursorPos(XOrgin+x,YOrgin+y+1)\
625 print(\"X\")\
626 end\
627\
628 local st = tostring(tScreen[x][y].start)\
629 if not(st == \"zz\" or st == \"nil\") then\
630 local Cr = string.sub(st,2,2)\
631 if Cr == \"a\" then\
632 Cr = cR1\
633 elseif Cr == \"b\" then\
634 Cr = cR2\
635 elseif Cr == \"c\" then\
636 Cr = cR3\
637 elseif Cr == \"d\" then\
638 Cr = cR4\
639 else\
640 return error(\"Start Color Out\")\
641 end\
642\
643 term.setTextColor(Cr)\
644 term.setBackgroundColor(cG)\
645 term.setCursorPos(XOrgin+x,YOrgin+y+1)\
646\
647 local sSide = string.sub(st,1,1)\
648 if sSide == \"a\" then\
649 print(\"^\")\
650 elseif sSide == \"b\" then\
651 print(\">\")\
652 elseif sSide == \"c\" then\
653 print(\"v\")\
654 elseif sSide == \"d\" then\
655 print(\"<\")\
656 else\
657 print(\"@\")\
658 end\
659 end\
660\
661 if obj.space == true then\
662 paintutils.drawPixel(XOrgin+x,YOrgin+y+1,cS)\
663 end\
664\
665 local rb = tostring(tScreen[x][y].robot)\
666 if not(rb == \"zz\" or rb == \"nil\") then\
667 local Cr = string.sub(rb,2,2)\
668 if Cr == \"a\" then\
669 Cr = cR1\
670 elseif Cr == \"b\" then\
671 Cr = cR2\
672 elseif Cr == \"c\" then\
673 Cr = cR3\
674 elseif Cr == \"d\" then\
675 Cr = cR4\
676 else\
677 Cr = colors.white\
678 end\
679 term.setBackgroundColor(Cr)\
680 term.setTextColor(colors.white)\
681 term.setCursorPos(XOrgin+x,YOrgin+y+1)\
682 local sSide = string.sub(rb,1,1)\
683 if sSide == \"a\" then\
684 print(\"^\")\
685 elseif sSide == \"b\" then\
686 print(\">\")\
687 elseif sSide == \"c\" then\
688 print(\"v\")\
689 elseif sSide == \"d\" then\
690 print(\"<\")\
691 else\
692 print(\"@\")\
693 end\
694 end\
695 end\
696 end\
697end\
698\
699local function isBrick(x,y)\
700 local brb = tostring(tScreen[x][y].robot)\
701 local bobj = oScreen[x][y]\
702 if (brb == \"zz\" or brb == \"nil\") and not bobj.wall == true then\
703 return false\
704 else\
705 return true\
706 end\
707end\
708\
709local function gRender(sContext)\
710 if sContext == \"start\" then\
711 for x=1,SizeW do\
712 for y=1,SizeH do\
713 local st = tostring(tScreen[x][y].start)\
714 if not(st == \"zz\" or st == \"nil\") then\
715 local Cr = string.sub(st,2,2)\
716 local sSide = string.sub(st,1,1)\
717 addRobot(x,y,sSide,Cr)\
718 end\
719 end\
720 end\
721 elseif sContext == \"tick\" then\
722 buMap()\
723 for x=1,SizeW do\
724 for y=1,SizeH do\
725 local rb = tostring(oScreen[x][y].robot)\
726 if not(rb == \"zz\" or rb == \"nil\") then\
727 local Cr = string.sub(rb,2,2)\
728 local sSide = string.sub(rb,1,1)\
729 local sobj = oScreen[x][y]\
730 if sobj.space == true then\
731 tScreen[x][y].robot = \"zz\"\
732 if not sSide == \"g\" then\
733 addRobot(x,y,\"g\",Cr)\
734 end\
735 elseif sobj.exit == Cr then\
736 if sSide == \"a\" or sSide == \"b\" or sSide == \"c\" or sSide == \"d\" then\
737 tScreen[x][y].robot = \"zz\"\
738 addRobot(x,y,\"g\",Cr)\
739 aExits = aExits-1\
740 end\
741 elseif sSide == \"a\" then\
742 local obj = isBrick(x,y-1)\
743 tScreen[x][y].robot = \"zz\"\
744 if not obj == true then\
745 addRobot(x,y-1,sSide,Cr)\
746 else\
747 local obj2 = isBrick(x-1,y)\
748 local obj3 = isBrick(x+1,y)\
749 if not obj2 == true and not obj3 == true then\
750 if Cr == \"a\" then\
751 addRobot(x,y,\"d\",Cr)\
752 elseif Cr == \"b\" then\
753 addRobot(x,y,\"b\",Cr)\
754 end\
755 elseif obj == true and obj2 == true and obj3 == true then\
756 addRobot(x,y,\"c\",Cr)\
757 else\
758 if obj3 == true then\
759 addRobot(x,y,\"d\",Cr)\
760 elseif obj2 == true then\
761 addRobot(x,y,\"b\",Cr)\
762 end\
763 end\
764 end\
765 elseif sSide == \"b\" then\
766 local obj = isBrick(x+1,y)\
767 tScreen[x][y].robot = \"zz\"\
768 if not obj == true then\
769 addRobot(x+1,y,sSide,Cr)\
770 else\
771 local obj2 = isBrick(x,y-1)\
772 local obj3 = isBrick(x,y+1)\
773 if not obj2 == true and not obj3 == true then\
774 if Cr == \"a\" then\
775 addRobot(x,y,\"a\",Cr)\
776 elseif Cr == \"b\" then\
777 addRobot(x,y,\"c\",Cr)\
778 end\
779 elseif obj == true and obj2 == true and obj3 == true then\
780 addRobot(x,y,\"d\",Cr)\
781 else\
782 if obj3 == true then\
783 addRobot(x,y,\"a\",Cr)\
784 elseif obj2 == true then\
785 addRobot(x,y,\"c\",Cr)\
786 end\
787 end\
788 end\
789 elseif sSide == \"c\" then\
790 local obj = isBrick(x,y+1)\
791 tScreen[x][y].robot = \"zz\"\
792 if not obj == true then\
793 addRobot(x,y+1,sSide,Cr)\
794 else\
795 local obj2 = isBrick(x-1,y)\
796 local obj3 = isBrick(x+1,y)\
797 if not obj2 == true and not obj3 == true then\
798 if Cr == \"a\" then\
799 addRobot(x,y,\"b\",Cr)\
800 elseif Cr == \"b\" then\
801 addRobot(x,y,\"d\",Cr)\
802 end\
803 elseif obj == true and obj2 == true and obj3 == true then\
804 addRobot(x,y,\"a\",Cr)\
805 else\
806 if obj3 == true then\
807 addRobot(x,y,\"d\",Cr)\
808 elseif obj2 == true then\
809 addRobot(x,y,\"b\",Cr)\
810 end\
811 end\
812 end\
813 elseif sSide == \"d\" then\
814 local obj = isBrick(x-1,y)\
815 tScreen[x][y].robot = \"zz\"\
816 if not obj == true then\
817 addRobot(x-1,y,sSide,Cr)\
818 else\
819 local obj2 = isBrick(x,y-1)\
820 local obj3 = isBrick(x,y+1)\
821 if not obj2 == true and not obj3 == true then\
822 if Cr == \"a\" then\
823 addRobot(x,y,\"c\",Cr)\
824 elseif Cr == \"b\" then\
825 addRobot(x,y,\"a\",Cr)\
826 end\
827 elseif obj == true and obj2 == true and obj3 == true then\
828 addRobot(x,y,\"b\",Cr)\
829 else\
830 if obj3 == true then\
831 addRobot(x,y,\"a\",Cr)\
832 elseif obj2 == true then\
833 addRobot(x,y,\"c\",Cr)\
834 end\
835 end\
836 end\
837 else\
838 addRobot(x,y,sSide,\"g\")\
839 end\
840 end\
841 end\
842 end\
843 end\
844end\
845\
846function InterFace.drawBar()\
847 term.setBackgroundColor( colors.black )\
848 term.setTextColor( InterFace.cTitle )\
849 printCentred( 1, \" \"..sLevelTitle..\" \" )\
850\
851 term.setCursorPos(1,1)\
852 term.setBackgroundColor( cW )\
853 write( \" \" )\
854 term.setBackgroundColor( colors.black )\
855 write( \" x \"..tostring(Blocks)..\" \" )\
856\
857 term.setCursorPos( TermW-8,TermH )\
858 term.setBackgroundColor( colors.black )\
859 term.setTextColour(InterFace.cSpeedD)\
860 write(\" <<\" )\
861 if bPaused then\
862 term.setTextColour(InterFace.cSpeedA)\
863 else\
864 term.setTextColour(InterFace.cSpeedD)\
865 end\
866 write(\" ||\")\
867 if fSpeedS then\
868 term.setTextColour(InterFace.cSpeedA)\
869 else\
870 term.setTextColour(InterFace.cSpeedD)\
871 end\
872 write(\" >>\")\
873\
874 term.setCursorPos( TermW-1, 1 )\
875 term.setBackgroundColor( colors.black )\
876 term.setTextColour( InterFace.cExit )\
877 write(\" X\")\
878 term.setBackgroundColor(colors.black)\
879end\
880\
881function InterFace.render()\
882 local id,p1,p2,p3 = os.pullEvent()\
883 if id == \"mouse_click\" then\
884 if p3 == 1 and p2 == TermW then\
885 return \"end\"\
886 elseif p3 == TermH and p2 >= TermW-7 and p2 <= TermW-6 then\
887 return \"retry\"\
888 elseif p3 == TermH and p2 >= TermW-4 and p2 <= TermW-3 then\
889 bPaused = not bPaused\
890 fSpeedS = false\
891 Speed = (bPaused and 0) or nSpeed\
892 if Speed > 0 then\
893 Tick = os.startTimer(Speed)\
894 else\
895 Tick = nil\
896 end\
897 InterFace.drawBar()\
898 elseif p3 == TermH and p2 >= TermW-1 then\
899 bPaused = false\
900 fSpeedS = not fSpeedS\
901 Speed = (fSpeedS and fSpeed) or nSpeed\
902 Tick = os.startTimer(Speed)\
903 InterFace.drawBar()\
904 elseif p3-1 < YOrgin+SizeH+1 and p3-1 > YOrgin and\
905 p2 < XOrgin+SizeW+1 and p2 > XOrgin then\
906 local eobj = tScreen[p2-XOrgin][p3-YOrgin-1]\
907 local erobj = tostring(tScreen[p2-XOrgin][p3-YOrgin-1].robot)\
908 if (erobj == \"zz\" or erobj == \"nil\") and not eobj.wall == true and not eobj.space == true and Blocks > 0 then\
909 addWall(p2-XOrgin,p3-YOrgin-1)\
910 Blocks = Blocks-1\
911 InterFace.drawBar()\
912 drawMap()\
913 end\
914 end\
915 elseif id == \"timer\" and p1 == Tick then\
916 gRender(\"tick\")\
917 drawMap()\
918 if Speed > 0 then\
919 Tick = os.startTimer(Speed)\
920 else\
921 Tick = nil\
922 end\
923 end\
924end\
925\
926local function startG(LevelN)\
927 drawStars()\
928 loadLevel(LevelN)\
929 centerOrgin()\
930 local create = true\
931 drawMap()\
932 InterFace.drawBar()\
933 gRender(\"start\")\
934 drawMap()\
935\
936 local NExit = true\
937 if aExits == 0 then\
938 NExit = false\
939 end\
940\
941 while true do\
942 local isExit = InterFace.render()\
943 if isExit == \"end\" then\
944 return nil\
945 elseif isExit == \"retry\" then\
946 return LevelN\
947 elseif fExit == \"yes\" then\
948 if fs.exists( fs.getDir( shell.getRunningProgram() ) .. \"/levels/\" .. tostring(LevelN + 1) .. \".dat\" ) then\
949 return LevelN + 1\
950 else\
951 return nil\
952 end\
953 end\
954 if aExits == 0 and NExit == true then\
955 fExit = \"yes\"\
956 end\
957 end\
958end\
959\
960local ok, err = true, nil\
961\
962--Menu--\
963local sStartLevel = tArgs[1]\
964if ok and not sStartLevel then\
965 ok, err = pcall( function()\
966 term.setTextColor(colors.white)\
967 term.setBackgroundColor( colors.black )\
968 term.clear()\
969 drawStars()\
970 term.setTextColor( colors.red )\
971 printCentred( TermH/2 - 1, \" REDIRECTION \" )\
972 printCentred( TermH/2 - 0, \" ComputerCraft Edition \" )\
973 term.setTextColor( colors.yellow )\
974 printCentred( TermH/2 + 2, \" Click to Begin \" )\
975 os.pullEvent( \"mouse_click\" )\
976 end )\
977end\
978\
979--Game--\
980if ok then\
981 ok,err = pcall( function()\
982 local nLevel\
983 if sStartLevel then\
984 nLevel = tonumber( sStartLevel )\
985 else\
986 nLevel = 1\
987 end\
988 while nLevel do\
989 reset()\
990 nLevel = startG(nLevel)\
991 end\
992 end )\
993end\
994\
995--Upsell screen--\
996if ok then\
997 ok, err = pcall( function()\
998 term.setTextColor(colors.white)\
999 term.setBackgroundColor( colors.black )\
1000 term.clear()\
1001 drawStars()\
1002 term.setTextColor( colors.red )\
1003 if TermW >= 40 then\
1004 printCentred( TermH/2 - 1, \" Thank you for playing Redirection \" )\
1005 printCentred( TermH/2 - 0, \" ComputerCraft Edition \" )\
1006 printCentred( TermH/2 + 2, \" Check out the full game: \" )\
1007 term.setTextColor( colors.yellow )\
1008 printCentred( TermH/2 + 3, \" http://www.redirectiongame.com \" )\
1009 else\
1010 printCentred( TermH/2 - 2, \" Thank you for \" )\
1011 printCentred( TermH/2 - 1, \" playing Redirection \" )\
1012 printCentred( TermH/2 - 0, \" ComputerCraft Edition \" )\
1013 printCentred( TermH/2 + 2, \" Check out the full game: \" )\
1014 term.setTextColor( colors.yellow )\
1015 printCentred( TermH/2 + 3, \" www.redirectiongame.com \" )\
1016 end\
1017 parallel.waitForAll(\
1018 function() sleep(2) end,\
1019 function() os.pullEvent( \"mouse_click\" ) end\
1020 )\
1021 end )\
1022end\
1023\
1024--Clear and exit--\
1025term.setCursorPos(1,1)\
1026term.setTextColor(colors.white)\
1027term.setBackgroundColor(colors.black)\
1028term.clear()\
1029if not ok then\
1030 if err == \"Terminated\" then\
1031 print( \"Check out the full version of Redirection:\" )\
1032 print( \"http://www.redirectiongame.com\" )\
1033 else\
1034 printError( err )\
1035 end\
1036end",
1037 [ "help/credits-emu.txt" ] = "CCEmuX would not be possible without the help of several open source projects:\
1038\
1039## Commons CLI\
1040Apache Commons CLI\
1041Copyright 2001-2017 The Apache Software Foundation\
1042\
1043This product includes software developed at\
1044The Apache Software Foundation (http://www.apache.org/).\
1045\
1046Licensed to the Apache Software Foundation (ASF) under one or more\
1047contributor license agreements. See the NOTICE file distributed with\
1048this work for additional information regarding copyright ownership.\
1049The ASF licenses this file to You under the Apache License, Version 2.0\
1050(the \"License\"); you may not use this file except in compliance with\
1051the License. You may obtain a copy of the License at\
1052\
1053 http://www.apache.org/licenses/LICENSE-2.0\
1054\
1055Unless required by applicable law or agreed to in writing, software\
1056distributed under the License is distributed on an \"AS IS\" BASIS,\
1057WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\
1058See the License for the specific language governing permissions and\
1059limitations under the License.\
1060\
1061## Commons Lang\
1062Apache Commons Lang\
1063Copyright 2001-2017 The Apache Software Foundation\
1064\
1065This product includes software developed at\
1066The Apache Software Foundation (http://www.apache.org/).\
1067\
1068This product includes software from the Spring Framework,\
1069under the Apache License 2.0 (see: StringUtils.containsWhitespace())\
1070\
1071Licensed to the Apache Software Foundation (ASF) under one or more\
1072contributor license agreements. See the NOTICE file distributed with\
1073this work for additional information regarding copyright ownership.\
1074The ASF licenses this file to You under the Apache License, Version 2.0\
1075(the \"License\"); you may not use this file except in compliance with\
1076the License. You may obtain a copy of the License at\
1077\
1078 http://www.apache.org/licenses/LICENSE-2.0\
1079\
1080Unless required by applicable law or agreed to in writing, software\
1081distributed under the License is distributed on an \"AS IS\" BASIS,\
1082WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\
1083See the License for the specific language governing permissions and\
1084limitations under the License.\
1085\
1086## Guava\
1087Copyright (C) 2008 The Guava Authors\
1088\
1089Licensed under the Apache License, Version 2.0 (the \"License\");\
1090you may not use this file except in compliance with the License.\
1091You may obtain a copy of the License at\
1092\
1093http://www.apache.org/licenses/LICENSE-2.0\
1094\
1095Unless required by applicable law or agreed to in writing, software\
1096distributed under the License is distributed on an \"AS IS\" BASIS,\
1097WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\
1098See the License for the specific language governing permissions and\
1099limitations under the License.\
1100\
1101## Log4J\
1102Apache Log4j API\
1103Copyright 1999-2017 The Apache Software Foundation\
1104\
1105This product includes software developed at\
1106The Apache Software Foundation (http://www.apache.org/).\
1107\
1108Licensed to the Apache Software Foundation (ASF) under one or more\
1109contributor license agreements. See the NOTICE file distributed with\
1110this work for additional information regarding copyright ownership.\
1111The ASF licenses this file to You under the Apache license, Version 2.0\
1112(the \"License\"); you may not use this file except in compliance with\
1113the License. You may obtain a copy of the License at\
1114\
1115 http://www.apache.org/licenses/LICENSE-2.0\
1116\
1117Unless required by applicable law or agreed to in writing, software\
1118distributed under the License is distributed on an \"AS IS\" BASIS,\
1119WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\
1120See the license for the specific language governing permissions and\
1121limitations under the license.\
1122\
1123## Netty\
1124Copyright 2012 The Netty Project\
1125\
1126The Netty Project licenses this file to you under the Apache License,\
1127version 2.0 (the \"License\"); you may not use this file except in compliance\
1128with the License. You may obtain a copy of the License at:\
1129\
1130 http://www.apache.org/licenses/LICENSE-2.0\
1131\
1132Unless required by applicable law or agreed to in writing, software\
1133distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\
1134WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\
1135License for the specific language governing permissions and limitations\
1136under the License.",
1137 [ "help/commandsapi.txt" ] = "Functions in the commands API:\
1138commands.exec( command )\
1139commands.execAsync( command )\
1140commands.list()\
1141commands.getBlockPosition()\
1142commands.getBlockInfo( x, y, z )\
1143commands.getBlockInfos( minx, miny, minz, maxx, maxy, maxz )\
1144\
1145The commands API can also be used to invoke commands directly, like so:\
1146commands.say( \"Hello World\" )\
1147commands.give( \"dan200\", \"minecraft:diamond\", 64 )\
1148This works with any command. Use \"commands.async\" instead of \"commands\" to execute asynchronously.\
1149\
1150The commands API is only available on Command Computers.\
1151Visit http://minecraft.gamepedia.com/Commands for documentation on all commands.",
1152 [ "help/io.txt" ] = "io is a standard Lua5.1 API, reimplemented for CraftOS. Not all the features are availiable.\
1153Refer to http://www.lua.org/manual/5.1/ for more information.",
1154 [ "help/dj.txt" ] = "dj plays Music Discs from disk drives attached to the computer.\
1155\
1156ex:\
1157\"dj\" or \"dj play\" plays a random disc.\
1158\"dj play left\" plays the disc in the drive on the left of the computer.\
1159\"dj stop\" stops the current disc.",
1160 [ "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.\
1161\
1162ex:\
1163\"equip 5 left\" will equip the item from slot 5 of the turtle onto the left side of the turtle\
1164\"equip\" on a Pocket Computer will equip the first item from your inventory.",
1165 [ "programs/advanced/multishell.lua" ] = "\
1166-- Setup process switching\
1167local parentTerm = term.current()\
1168local w,h = parentTerm.getSize()\
1169\
1170local tProcesses = {}\
1171local nCurrentProcess = nil\
1172local nRunningProcess = nil\
1173local bShowMenu = false\
1174local bWindowsResized = false\
1175local nScrollPos = 1\
1176local bScrollRight = false\
1177\
1178local function selectProcess( n )\
1179 if nCurrentProcess ~= n then\
1180 if nCurrentProcess then\
1181 local tOldProcess = tProcesses[ nCurrentProcess ]\
1182 tOldProcess.window.setVisible( false )\
1183 end\
1184 nCurrentProcess = n\
1185 if nCurrentProcess then\
1186 local tNewProcess = tProcesses[ nCurrentProcess ]\
1187 tNewProcess.window.setVisible( true )\
1188 tNewProcess.bInteracted = true\
1189 end\
1190 end\
1191end\
1192\
1193local function setProcessTitle( n, sTitle )\
1194 tProcesses[ n ].sTitle = sTitle\
1195end\
1196\
1197local function resumeProcess( nProcess, sEvent, ... )\
1198 local tProcess = tProcesses[ nProcess ]\
1199 local sFilter = tProcess.sFilter\
1200 if sFilter == nil or sFilter == sEvent or sEvent == \"terminate\" then\
1201 local nPreviousProcess = nRunningProcess\
1202 nRunningProcess = nProcess\
1203 term.redirect( tProcess.terminal )\
1204 local ok, result = coroutine.resume( tProcess.co, sEvent, ... )\
1205 tProcess.terminal = term.current()\
1206 if ok then\
1207 tProcess.sFilter = result\
1208 else\
1209 printError( result )\
1210 end\
1211 nRunningProcess = nPreviousProcess\
1212 end\
1213end\
1214\
1215local function launchProcess( bFocus, tProgramEnv, sProgramPath, ... )\
1216 local tProgramArgs = table.pack( ... )\
1217 local nProcess = #tProcesses + 1\
1218 local tProcess = {}\
1219 tProcess.sTitle = fs.getName( sProgramPath )\
1220 if bShowMenu then\
1221 tProcess.window = window.create( parentTerm, 1, 2, w, h-1, false )\
1222 else\
1223 tProcess.window = window.create( parentTerm, 1, 1, w, h, false )\
1224 end\
1225 tProcess.co = coroutine.create( function()\
1226 os.run( tProgramEnv, sProgramPath, table.unpack( tProgramArgs, 1, tProgramArgs.n ) )\
1227 if not tProcess.bInteracted then\
1228 term.setCursorBlink( false )\
1229 print( \"Press any key to continue\" )\
1230 os.pullEvent( \"char\" )\
1231 end\
1232 end )\
1233 tProcess.sFilter = nil\
1234 tProcess.terminal = tProcess.window\
1235 tProcess.bInteracted = false\
1236 tProcesses[ nProcess ] = tProcess\
1237 if bFocus then\
1238 selectProcess( nProcess )\
1239 end\
1240 resumeProcess( nProcess )\
1241 return nProcess\
1242end\
1243\
1244local function cullProcess( nProcess )\
1245 local tProcess = tProcesses[ nProcess ]\
1246 if coroutine.status( tProcess.co ) == \"dead\" then\
1247 if nCurrentProcess == nProcess then\
1248 selectProcess( nil )\
1249 end\
1250 table.remove( tProcesses, nProcess )\
1251 if nCurrentProcess == nil then\
1252 if nProcess > 1 then\
1253 selectProcess( nProcess - 1 )\
1254 elseif #tProcesses > 0 then\
1255 selectProcess( 1 )\
1256 end\
1257 end\
1258 if nScrollPos ~= 1 then\
1259 nScrollPos = nScrollPos - 1\
1260 end\
1261 return true\
1262 end\
1263 return false\
1264end\
1265\
1266local function cullProcesses()\
1267 local culled = false\
1268 for n=#tProcesses,1,-1 do\
1269 culled = culled or cullProcess( n )\
1270 end\
1271 return culled\
1272end\
1273\
1274-- Setup the main menu\
1275local menuMainTextColor, menuMainBgColor, menuOtherTextColor, menuOtherBgColor\
1276if parentTerm.isColor() then\
1277 menuMainTextColor, menuMainBgColor = colors.yellow, colors.black\
1278 menuOtherTextColor, menuOtherBgColor = colors.black, colors.gray\
1279else\
1280 menuMainTextColor, menuMainBgColor = colors.white, colors.black\
1281 menuOtherTextColor, menuOtherBgColor = colors.black, colors.gray\
1282end\
1283\
1284local function redrawMenu()\
1285 if bShowMenu then\
1286 -- Draw menu\
1287 parentTerm.setCursorPos( 1, 1 )\
1288 parentTerm.setBackgroundColor( menuOtherBgColor )\
1289 parentTerm.clearLine()\
1290 local nCharCount = 0\
1291 local nSize = parentTerm.getSize()\
1292 if nScrollPos ~= 1 then\
1293 parentTerm.setTextColor( menuOtherTextColor )\
1294 parentTerm.setBackgroundColor( menuOtherBgColor )\
1295 parentTerm.write( \"<\" )\
1296 nCharCount = 1\
1297 end\
1298 for n=nScrollPos,#tProcesses do\
1299 if n == nCurrentProcess then\
1300 parentTerm.setTextColor( menuMainTextColor )\
1301 parentTerm.setBackgroundColor( menuMainBgColor )\
1302 else\
1303 parentTerm.setTextColor( menuOtherTextColor )\
1304 parentTerm.setBackgroundColor( menuOtherBgColor )\
1305 end\
1306 parentTerm.write( \" \" .. tProcesses[n].sTitle .. \" \" )\
1307 nCharCount = nCharCount + #tProcesses[n].sTitle + 2\
1308 end\
1309 if nCharCount > nSize then\
1310 parentTerm.setTextColor( menuOtherTextColor )\
1311 parentTerm.setBackgroundColor( menuOtherBgColor )\
1312 parentTerm.setCursorPos( nSize, 1 )\
1313 parentTerm.write( \">\" )\
1314 bScrollRight = true\
1315 else\
1316 bScrollRight = false\
1317 end\
1318\
1319 -- Put the cursor back where it should be\
1320 local tProcess = tProcesses[ nCurrentProcess ]\
1321 if tProcess then\
1322 tProcess.window.restoreCursor()\
1323 end\
1324 end\
1325end\
1326\
1327local function resizeWindows()\
1328 local windowY, windowHeight\
1329 if bShowMenu then\
1330 windowY = 2\
1331 windowHeight = h-1\
1332 else\
1333 windowY = 1\
1334 windowHeight = h\
1335 end\
1336 for n=1,#tProcesses do\
1337 local tProcess = tProcesses[n]\
1338 local window = tProcess.window\
1339 local x,y = tProcess.window.getCursorPos()\
1340 if y > windowHeight then\
1341 tProcess.window.scroll( y - windowHeight )\
1342 tProcess.window.setCursorPos( x, windowHeight )\
1343 end\
1344 tProcess.window.reposition( 1, windowY, w, windowHeight )\
1345 end\
1346 bWindowsResized = true\
1347end\
1348\
1349local function setMenuVisible( bVis )\
1350 if bShowMenu ~= bVis then\
1351 bShowMenu = bVis\
1352 resizeWindows()\
1353 redrawMenu()\
1354 end\
1355end\
1356\
1357local multishell = {}\
1358\
1359function multishell.getFocus()\
1360 return nCurrentProcess\
1361end\
1362\
1363function multishell.setFocus( n )\
1364 if type( n ) ~= \"number\" then\
1365 error( \"bad argument #1 (expected number, got \" .. type( n ) .. \")\", 2 )\
1366 end\
1367 if n >= 1 and n <= #tProcesses then\
1368 selectProcess( n )\
1369 redrawMenu()\
1370 return true\
1371 end\
1372 return false\
1373end\
1374\
1375function multishell.getTitle( n )\
1376 if type( n ) ~= \"number\" then\
1377 error( \"bad argument #1 (expected number, got \" .. type( n ) .. \")\", 2 )\
1378 end\
1379 if n >= 1 and n <= #tProcesses then\
1380 return tProcesses[n].sTitle\
1381 end\
1382 return nil\
1383end\
1384\
1385function multishell.setTitle( n, sTitle )\
1386 if type( n ) ~= \"number\" then\
1387 error( \"bad argument #1 (expected number, got \" .. type( n ) .. \")\", 2 )\
1388 end\
1389 if type( sTitle ) ~= \"string\" then\
1390 error( \"bad argument #2 (expected string, got \" .. type( sTitle ) .. \")\", 2 )\
1391 end\
1392 if n >= 1 and n <= #tProcesses then\
1393 setProcessTitle( n, sTitle )\
1394 redrawMenu()\
1395 end\
1396end\
1397\
1398function multishell.getCurrent()\
1399 return nRunningProcess\
1400end\
1401\
1402function multishell.launch( tProgramEnv, sProgramPath, ... )\
1403 if type( tProgramEnv ) ~= \"table\" then\
1404 error( \"bad argument #1 (expected table, got \" .. type( tProgramEnv ) .. \")\", 2 )\
1405 end\
1406 if type( sProgramPath ) ~= \"string\" then\
1407 error( \"bad argument #2 (expected string, got \" .. type( sProgramPath ) .. \")\", 2 )\
1408 end\
1409 local previousTerm = term.current()\
1410 setMenuVisible( (#tProcesses + 1) >= 2 )\
1411 local nResult = launchProcess( false, tProgramEnv, sProgramPath, ... )\
1412 redrawMenu()\
1413 term.redirect( previousTerm )\
1414 return nResult\
1415end\
1416\
1417function multishell.getCount()\
1418 return #tProcesses\
1419end\
1420\
1421-- Begin\
1422parentTerm.clear()\
1423setMenuVisible( false )\
1424launchProcess( true, {\
1425 [\"shell\"] = shell,\
1426 [\"multishell\"] = multishell,\
1427}, \"/rom/programs/shell.lua\" )\
1428\
1429-- Run processes\
1430while #tProcesses > 0 do\
1431 -- Get the event\
1432 local tEventData = table.pack( os.pullEventRaw() )\
1433 local sEvent = tEventData[1]\
1434 if sEvent == \"term_resize\" then\
1435 -- Resize event\
1436 w,h = parentTerm.getSize()\
1437 resizeWindows()\
1438 redrawMenu()\
1439\
1440 elseif sEvent == \"char\" or sEvent == \"key\" or sEvent == \"key_up\" or sEvent == \"paste\" or sEvent == \"terminate\" then\
1441 -- Keyboard event\
1442 -- Passthrough to current process\
1443 resumeProcess( nCurrentProcess, table.unpack( tEventData, 1, tEventData.n ) )\
1444 if cullProcess( nCurrentProcess ) then\
1445 setMenuVisible( #tProcesses >= 2 )\
1446 redrawMenu()\
1447 end\
1448\
1449 elseif sEvent == \"mouse_click\" then\
1450 -- Click event\
1451 local button, x, y = tEventData[2], tEventData[3], tEventData[4]\
1452 if bShowMenu and y == 1 then\
1453 -- Switch process\
1454 if x == 1 and nScrollPos ~= 1 then\
1455 nScrollPos = nScrollPos - 1\
1456 redrawMenu()\
1457 elseif bScrollRight and x == term.getSize() then\
1458 nScrollPos = nScrollPos + 1\
1459 redrawMenu()\
1460 else\
1461 local tabStart = 1\
1462 if nScrollPos ~= 1 then\
1463 tabStart = 2\
1464 end\
1465 for n=nScrollPos,#tProcesses do\
1466 local tabEnd = tabStart + string.len( tProcesses[n].sTitle ) + 1\
1467 if x >= tabStart and x <= tabEnd then\
1468 selectProcess( n )\
1469 redrawMenu()\
1470 break\
1471 end\
1472 tabStart = tabEnd + 1\
1473 end\
1474 end\
1475 else\
1476 -- Passthrough to current process\
1477 resumeProcess( nCurrentProcess, sEvent, button, x, (bShowMenu and y-1) or y )\
1478 if cullProcess( nCurrentProcess ) then\
1479 setMenuVisible( #tProcesses >= 2 )\
1480 redrawMenu()\
1481 end\
1482 end\
1483\
1484 elseif sEvent == \"mouse_drag\" or sEvent == \"mouse_up\" or sEvent == \"mouse_scroll\" then\
1485 -- Other mouse event\
1486 local p1, x, y = tEventData[2], tEventData[3], tEventData[4]\
1487 if bShowMenu and sEvent == \"mouse_scroll\" and y == 1 then\
1488 if p1 == -1 and nScrollPos ~= 1 then\
1489 nScrollPos = nScrollPos - 1\
1490 redrawMenu()\
1491 elseif bScrollRight and p1 == 1 then\
1492 nScrollPos = nScrollPos + 1\
1493 redrawMenu()\
1494 end\
1495 elseif not (bShowMenu and y == 1) then\
1496 -- Passthrough to current process\
1497 resumeProcess( nCurrentProcess, sEvent, p1, x, (bShowMenu and y-1) or y )\
1498 if cullProcess( nCurrentProcess ) then\
1499 setMenuVisible( #tProcesses >= 2 )\
1500 redrawMenu()\
1501 end\
1502 end\
1503\
1504 else\
1505 -- Other event\
1506 -- Passthrough to all processes\
1507 local nLimit = #tProcesses -- Storing this ensures any new things spawned don't get the event\
1508 for n=1,nLimit do\
1509 resumeProcess( n, table.unpack( tEventData, 1, tEventData.n ) )\
1510 end\
1511 if cullProcesses() then\
1512 setMenuVisible( #tProcesses >= 2 )\
1513 redrawMenu()\
1514 end\
1515 end\
1516\
1517 if bWindowsResized then\
1518 -- Pass term_resize to all processes\
1519 local nLimit = #tProcesses -- Storing this ensures any new things spawned don't get the event\
1520 for n=1,nLimit do\
1521 resumeProcess( n, \"term_resize\" )\
1522 end\
1523 bWindowsResized = false\
1524 if cullProcesses() then\
1525 setMenuVisible( #tProcesses >= 2 )\
1526 redrawMenu()\
1527 end\
1528 end\
1529end\
1530\
1531-- Shutdown\
1532term.redirect( parentTerm )",
1533 [ "programs/fun/adventure.lua" ] = "\
1534local tBiomes = {\
1535 \"in a forest\",\
1536 \"in a pine forest\",\
1537 \"knee deep in a swamp\",\
1538 \"in a mountain range\",\
1539 \"in a desert\",\
1540 \"in a grassy plain\",\
1541 \"in frozen tundra\",\
1542}\
1543\
1544local function hasTrees( _nBiome )\
1545 return _nBiome <= 3\
1546end\
1547\
1548local function hasStone( _nBiome )\
1549 return _nBiome == 4\
1550end\
1551\
1552local function hasRivers( _nBiome )\
1553 return _nBiome ~= 3 and _nBiome ~= 5\
1554end\
1555\
1556local items = {\
1557 [\"no tea\"] = {\
1558 droppable = false,\
1559 desc = \"Pull yourself together man.\",\
1560 },\
1561 [\"a pig\"] = {\
1562 heavy = true,\
1563 creature = true,\
1564 drops = { \"some pork\" },\
1565 aliases = { \"pig\" },\
1566 desc = \"The pig has a square nose.\",\
1567 },\
1568 [\"a cow\"] = {\
1569 heavy = true,\
1570 creature = true,\
1571 aliases = { \"cow\" },\
1572 desc = \"The cow stares at you blankly.\",\
1573 },\
1574 [\"a sheep\"] = {\
1575 heavy = true,\
1576 creature = true,\
1577 hitDrops = { \"some wool\" },\
1578 aliases = { \"sheep\" },\
1579 desc = \"The sheep is fluffy.\",\
1580 },\
1581 [\"a chicken\"] = {\
1582 heavy = true,\
1583 creature = true,\
1584 drops = { \"some chicken\" },\
1585 aliases = { \"chicken\" },\
1586 desc = \"The chicken looks delicious.\",\
1587 },\
1588 [\"a creeper\"] = {\
1589 heavy = true,\
1590 creature = true,\
1591 monster = true,\
1592 aliases = { \"creeper\" },\
1593 desc = \"The creeper needs a hug.\",\
1594 },\
1595 [\"a skeleton\"] = {\
1596 heavy = true,\
1597 creature = true,\
1598 monster = true,\
1599 aliases = { \"skeleton\" },\
1600 nocturnal = true,\
1601 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.\",\
1602 },\
1603 [\"a zombie\"] = {\
1604 heavy = true,\
1605 creature = true,\
1606 monster = true,\
1607 aliases = { \"zombie\" },\
1608 nocturnal = true,\
1609 desc = \"All he wants to do is eat your brains.\",\
1610 },\
1611 [\"a spider\"] = {\
1612 heavy = true,\
1613 creature = true,\
1614 monster = true,\
1615 aliases = { \"spider\" },\
1616 desc = \"Dozens of eyes stare back at you.\",\
1617 },\
1618 [\"a cave entrance\"] = {\
1619 heavy = true,\
1620 aliases = { \"cave entance\", \"cave\", \"entrance\" },\
1621 desc = \"The entrance to the cave is dark, but it looks like you can climb down.\",\
1622 },\
1623 [\"an exit to the surface\"] = {\
1624 heavy = true,\
1625 aliases = { \"exit to the surface\", \"exit\", \"opening\" },\
1626 desc = \"You can just see the sky through the opening.\",\
1627 },\
1628 [\"a river\"] = {\
1629 heavy = true,\
1630 aliases = { \"river\" },\
1631 desc = \"The river flows majestically towards the horizon. It doesn't do anything else.\",\
1632 },\
1633 [\"some wood\"] = {\
1634 aliases = { \"wood\" },\
1635 material = true,\
1636 desc = \"You could easilly craft this wood into planks.\",\
1637 },\
1638 [\"some planks\"] = {\
1639 aliases = { \"planks\", \"wooden planks\", \"wood planks\" },\
1640 desc = \"You could easilly craft these planks into sticks.\",\
1641 },\
1642 [\"some sticks\"] = {\
1643 aliases = { \"sticks\", \"wooden sticks\", \"wood sticks\" },\
1644 desc = \"A perfect handle for torches or a pickaxe.\",\
1645 },\
1646 [\"a crafting table\"] = {\
1647 aliases = { \"crafting table\", \"craft table\", \"work bench\", \"workbench\", \"crafting bench\", \"table\", },\
1648 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.\",\
1649 },\
1650 [\"a furnace\"] = {\
1651 aliases = { \"furnace\" },\
1652 desc = \"It's a furnace. Between you and me, these don't actually do anything in this game.\",\
1653 },\
1654 [\"a wooden pickaxe\"] = {\
1655 aliases = { \"pickaxe\", \"pick\", \"wooden pick\", \"wooden pickaxe\", \"wood pick\", \"wood pickaxe\" },\
1656 tool = true,\
1657 toolLevel = 1,\
1658 toolType = \"pick\",\
1659 desc = \"The pickaxe looks good for breaking stone and coal.\",\
1660 },\
1661 [\"a stone pickaxe\"] = {\
1662 aliases = { \"pickaxe\", \"pick\", \"stone pick\", \"stone pickaxe\" },\
1663 tool = true,\
1664 toolLevel = 2,\
1665 toolType = \"pick\",\
1666 desc = \"The pickaxe looks good for breaking iron.\",\
1667 },\
1668 [\"an iron pickaxe\"] = {\
1669 aliases = { \"pickaxe\", \"pick\", \"iron pick\", \"iron pickaxe\" },\
1670 tool = true,\
1671 toolLevel = 3,\
1672 toolType = \"pick\",\
1673 desc = \"The pickaxe looks strong enough to break diamond.\",\
1674 },\
1675 [\"a diamond pickaxe\"] = {\
1676 aliases = { \"pickaxe\", \"pick\", \"diamond pick\", \"diamond pickaxe\" },\
1677 tool = true,\
1678 toolLevel = 4,\
1679 toolType = \"pick\",\
1680 desc = \"Best. Pickaxe. Ever.\",\
1681 },\
1682 [\"a wooden sword\"] = {\
1683 aliases = { \"sword\", \"wooden sword\", \"wood sword\" },\
1684 tool = true,\
1685 toolLevel = 1,\
1686 toolType = \"sword\",\
1687 desc = \"Flimsy, but better than nothing.\",\
1688 },\
1689 [\"a stone sword\"] = {\
1690 aliases = { \"sword\", \"stone sword\" },\
1691 tool = true,\
1692 toolLevel = 2,\
1693 toolType = \"sword\",\
1694 desc = \"A pretty good sword.\",\
1695 },\
1696 [\"an iron sword\"] = {\
1697 aliases = { \"sword\", \"iron sword\" },\
1698 tool = true,\
1699 toolLevel = 3,\
1700 toolType = \"sword\",\
1701 desc = \"This sword can slay any enemy.\",\
1702 },\
1703 [\"a diamond sword\"] = {\
1704 aliases = { \"sword\", \"diamond sword\" },\
1705 tool = true,\
1706 toolLevel = 4,\
1707 toolType = \"sword\",\
1708 desc = \"Best. Sword. Ever.\",\
1709 },\
1710 [\"a wooden shovel\"] = {\
1711 aliases = { \"shovel\", \"wooden shovel\", \"wood shovel\" },\
1712 tool = true,\
1713 toolLevel = 1,\
1714 toolType = \"shovel\",\
1715 desc = \"Good for digging holes.\",\
1716 },\
1717 [\"a stone shovel\"] = {\
1718 aliases = { \"shovel\", \"stone shovel\" },\
1719 tool = true,\
1720 toolLevel = 2,\
1721 toolType = \"shovel\",\
1722 desc = \"Good for digging holes.\",\
1723 },\
1724 [\"an iron shovel\"] = {\
1725 aliases = { \"shovel\", \"iron shovel\" },\
1726 tool = true,\
1727 toolLevel = 3,\
1728 toolType = \"shovel\",\
1729 desc = \"Good for digging holes.\",\
1730 },\
1731 [\"a diamond shovel\"] = {\
1732 aliases = { \"shovel\", \"diamond shovel\" },\
1733 tool = true,\
1734 toolLevel = 4,\
1735 toolType = \"shovel\",\
1736 desc = \"Good for digging holes.\",\
1737 },\
1738 [\"some coal\"] = {\
1739 aliases = { \"coal\" },\
1740 ore = true,\
1741 toolLevel = 1,\
1742 toolType = \"pick\",\
1743 desc = \"That coal looks useful for building torches, if only you had a pickaxe to mine it.\",\
1744 },\
1745 [\"some dirt\"] = {\
1746 aliases = { \"dirt\" },\
1747 material = true,\
1748 desc = \"Why not build a mud hut?\",\
1749 },\
1750 [\"some stone\"] = {\
1751 aliases = { \"stone\", \"cobblestone\" },\
1752 material = true,\
1753 ore = true,\
1754 infinite = true,\
1755 toolLevel = 1,\
1756 toolType = \"pick\",\
1757 desc = \"Stone is useful for building things, and making stone pickaxes.\",\
1758 },\
1759 [\"some iron\"] = {\
1760 aliases = { \"iron\" },\
1761 material = true,\
1762 ore = true,\
1763 toolLevel = 2,\
1764 toolType = \"pick\",\
1765 desc = \"That iron looks mighty strong, you'll need a stone pickaxe to mine it.\",\
1766 },\
1767 [\"some diamond\"] = {\
1768 aliases = { \"diamond\", \"diamonds\" },\
1769 material = true,\
1770 ore = true,\
1771 toolLevel = 3,\
1772 toolType = \"pick\",\
1773 desc = \"Sparkly, rare, and impossible to mine without an iron pickaxe.\",\
1774 },\
1775 [\"some torches\"] = {\
1776 aliases = { \"torches\", \"torch\" },\
1777 desc = \"These won't run out for a while.\",\
1778 },\
1779 [\"a torch\"] = {\
1780 aliases = { \"torch\" },\
1781 desc = \"Fire, fire, burn so bright, won't you light my cave tonight?\",\
1782 },\
1783 [\"some wool\"] = {\
1784 aliases = { \"wool\" },\
1785 material = true,\
1786 desc = \"Soft and good for building.\",\
1787 },\
1788 [\"some pork\"] = {\
1789 aliases = { \"pork\", \"porkchops\" },\
1790 food = true,\
1791 desc = \"Delicious and nutricious.\",\
1792 },\
1793 [\"some chicken\"] = {\
1794 aliases = { \"chicken\" },\
1795 food = true,\
1796 desc = \"Finger licking good.\",\
1797 },\
1798}\
1799\
1800local tAnimals = {\
1801 \"a pig\", \"a cow\", \"a sheep\", \"a chicken\",\
1802}\
1803\
1804local tMonsters = {\
1805 \"a creeper\", \"a skeleton\", \"a zombie\", \"a spider\"\
1806}\
1807\
1808local tRecipes = {\
1809 [\"some planks\"] = { \"some wood\" },\
1810 [\"some sticks\"] = { \"some planks\" },\
1811 [\"a crafting table\"] = { \"some planks\" },\
1812 [\"a furnace\"] = { \"some stone\" },\
1813 [\"some torches\"] = { \"some sticks\", \"some coal\" },\
1814\
1815 [\"a wooden pickaxe\"] = { \"some planks\", \"some sticks\" },\
1816 [\"a stone pickaxe\"] = { \"some stone\", \"some sticks\" },\
1817 [\"an iron pickaxe\"] = { \"some iron\", \"some sticks\" },\
1818 [\"a diamond pickaxe\"] = { \"some diamond\", \"some sticks\" },\
1819\
1820 [\"a wooden sword\"] = { \"some planks\", \"some sticks\" },\
1821 [\"a stone sword\"] = { \"some stone\", \"some sticks\" },\
1822 [\"an iron sword\"] = { \"some iron\", \"some sticks\" },\
1823 [\"a diamond sword\"] = { \"some diamond\", \"some sticks\" },\
1824\
1825 [\"a wooden shovel\"] = { \"some planks\", \"some sticks\" },\
1826 [\"a stone shovel\"] = { \"some stone\", \"some sticks\" },\
1827 [\"an iron shovel\"] = { \"some iron\", \"some sticks\" },\
1828 [\"a diamond shovel\"] = { \"some diamond\", \"some sticks\" },\
1829}\
1830\
1831local tGoWest = {\
1832 \"(life is peaceful there)\",\
1833 \"(lots of open air)\",\
1834 \"(to begin life anew)\",\
1835 \"(this is what we'll do)\",\
1836 \"(sun in winter time)\",\
1837 \"(we will do just fine)\",\
1838 \"(where the skies are blue)\",\
1839 \"(this and more we'll do)\",\
1840}\
1841local nGoWest = 0\
1842\
1843local bRunning = true\
1844local tMap = { { {}, }, }\
1845local x,y,z = 0,0,0\
1846local inventory = {\
1847 [\"no tea\"] = items[\"no tea\"],\
1848}\
1849\
1850local nTurn = 0\
1851local nTimeInRoom = 0\
1852local bInjured = false\
1853\
1854local tDayCycle = {\
1855 \"It is daytime.\",\
1856 \"It is daytime.\",\
1857 \"It is daytime.\",\
1858 \"It is daytime.\",\
1859 \"It is daytime.\",\
1860 \"It is daytime.\",\
1861 \"It is daytime.\",\
1862 \"It is daytime.\",\
1863 \"The sun is setting.\",\
1864 \"It is night.\",\
1865 \"It is night.\",\
1866 \"It is night.\",\
1867 \"It is night.\",\
1868 \"It is night.\",\
1869 \"The sun is rising.\",\
1870}\
1871\
1872local function getTimeOfDay()\
1873 return math.fmod( math.floor(nTurn/3), #tDayCycle ) + 1\
1874end\
1875\
1876local function isSunny()\
1877 return (getTimeOfDay() < 10)\
1878end\
1879\
1880local function getRoom( x, y, z, dontCreate )\
1881 tMap[x] = tMap[x] or {}\
1882 tMap[x][y] = tMap[x][y] or {}\
1883 if not tMap[x][y][z] and dontCreate ~= true then\
1884 local room = {\
1885 items = {},\
1886 exits = {},\
1887 nMonsters = 0,\
1888 }\
1889 tMap[x][y][z] = room\
1890\
1891 if y == 0 then\
1892 -- Room is above ground\
1893\
1894 -- Pick biome\
1895 room.nBiome = math.random( 1, #tBiomes )\
1896 room.trees = hasTrees( room.nBiome )\
1897\
1898 -- Add animals\
1899 if math.random(1,3) == 1 then\
1900 for n = 1,math.random(1,2) do\
1901 local sAnimal = tAnimals[ math.random( 1, #tAnimals ) ]\
1902 room.items[ sAnimal ] = items[ sAnimal ]\
1903 end\
1904 end\
1905\
1906 -- Add surface ore\
1907 if math.random(1,5) == 1 or hasStone( room.nBiome ) then\
1908 room.items[ \"some stone\" ] = items[ \"some stone\" ]\
1909 end\
1910 if math.random(1,8) == 1 then\
1911 room.items[ \"some coal\" ] = items[ \"some coal\" ]\
1912 end\
1913 if math.random(1,8) == 1 and hasRivers( room.nBiome ) then\
1914 room.items[ \"a river\" ] = items[ \"a river\" ]\
1915 end\
1916\
1917 -- Add exits\
1918 room.exits = {\
1919 [\"north\"] = true,\
1920 [\"south\"] = true,\
1921 [\"east\"] = true,\
1922 [\"west\"] = true,\
1923 }\
1924 if math.random(1,8) == 1 then\
1925 room.exits[\"down\"] = true\
1926 room.items[\"a cave entrance\"] = items[\"a cave entrance\"]\
1927 end\
1928\
1929 else\
1930 -- Room is underground\
1931 -- Add exits\
1932 local function tryExit( sDir, sOpp, x, y, z )\
1933 local adj = getRoom( x, y, z, true )\
1934 if adj then\
1935 if adj.exits[sOpp] then\
1936 room.exits[sDir] = true\
1937 end\
1938 else\
1939 if math.random(1,3) == 1 then\
1940 room.exits[sDir] = true\
1941 end\
1942 end\
1943 end\
1944\
1945 if y == -1 then\
1946 local above = getRoom( x, y + 1, z )\
1947 if above.exits[\"down\"] then\
1948 room.exits[\"up\"] = true\
1949 room.items[\"an exit to the surface\"] = items[\"an exit to the surface\"]\
1950 end\
1951 else\
1952 tryExit( \"up\", \"down\", x, y + 1, z )\
1953 end\
1954\
1955 if y > -3 then\
1956 tryExit( \"down\", \"up\", x, y - 1, z )\
1957 end\
1958\
1959 tryExit( \"east\", \"west\", x - 1, y, z )\
1960 tryExit( \"west\", \"east\", x + 1, y, z )\
1961 tryExit( \"north\", \"south\", x, y, z + 1 )\
1962 tryExit( \"south\", \"north\", x, y, z - 1 )\
1963\
1964 -- Add ores\
1965 room.items[ \"some stone\" ] = items[ \"some stone\" ]\
1966 if math.random(1,3) == 1 then\
1967 room.items[ \"some coal\" ] = items[ \"some coal\" ]\
1968 end\
1969 if math.random(1,8) == 1 then\
1970 room.items[ \"some iron\" ] = items[ \"some iron\" ]\
1971 end\
1972 if y == -3 and math.random(1,15) == 1 then\
1973 room.items[ \"some diamond\" ] = items[ \"some diamond\" ]\
1974 end\
1975\
1976 -- Turn out the lights\
1977 room.dark = true\
1978 end\
1979 end\
1980 return tMap[x][y][z]\
1981end\
1982\
1983local function itemize( t )\
1984 local item = next( t )\
1985 if item == nil then\
1986 return \"nothing\"\
1987 end\
1988\
1989 local text = \"\"\
1990 while item do\
1991 text = text .. item\
1992\
1993 local nextItem = next( t, item )\
1994 if nextItem ~= nil then\
1995 local nextNextItem = next( t, nextItem )\
1996 if nextNextItem == nil then\
1997 text = text .. \" and \"\
1998 else\
1999 text = text .. \", \"\
2000 end\
2001 end\
2002 item = nextItem\
2003 end\
2004 return text\
2005end\
2006\
2007local function findItem( _tList, _sQuery )\
2008 for sItem, tItem in pairs( _tList ) do\
2009 if sItem == _sQuery then\
2010 return sItem\
2011 end\
2012 if tItem.aliases ~= nil then\
2013 for n, sAlias in pairs( tItem.aliases ) do\
2014 if sAlias == _sQuery then\
2015 return sItem\
2016 end\
2017 end\
2018 end\
2019 end\
2020 return nil\
2021end\
2022\
2023local tMatches = {\
2024 [\"wait\"] = {\
2025 \"wait\",\
2026 },\
2027 [\"look\"] = {\
2028 \"look at the ([%a ]+)\",\
2029 \"look at ([%a ]+)\",\
2030 \"look\",\
2031 \"inspect ([%a ]+)\",\
2032 \"inspect the ([%a ]+)\",\
2033 \"inspect\",\
2034 },\
2035 [\"inventory\"] = {\
2036 \"check self\",\
2037 \"check inventory\",\
2038 \"inventory\",\
2039 \"i\",\
2040 },\
2041 [\"go\"] = {\
2042 \"go (%a+)\",\
2043 \"travel (%a+)\",\
2044 \"walk (%a+)\",\
2045 \"run (%a+)\",\
2046 \"go\",\
2047 },\
2048 [\"dig\"] = {\
2049 \"dig (%a+) using ([%a ]+)\",\
2050 \"dig (%a+) with ([%a ]+)\",\
2051 \"dig (%a+)\",\
2052 \"dig\",\
2053 },\
2054 [\"take\"] = {\
2055 \"pick up the ([%a ]+)\",\
2056 \"pick up ([%a ]+)\",\
2057 \"pickup ([%a ]+)\",\
2058 \"take the ([%a ]+)\",\
2059 \"take ([%a ]+)\",\
2060 \"take\",\
2061 },\
2062 [\"drop\"] = {\
2063 \"put down the ([%a ]+)\",\
2064 \"put down ([%a ]+)\",\
2065 \"drop the ([%a ]+)\",\
2066 \"drop ([%a ]+)\",\
2067 \"drop\",\
2068 },\
2069 [\"place\"] = {\
2070 \"place the ([%a ]+)\",\
2071 \"place ([%a ]+)\",\
2072 \"place\",\
2073 },\
2074 [\"cbreak\"] = {\
2075 \"punch the ([%a ]+)\",\
2076 \"punch ([%a ]+)\",\
2077 \"punch\",\
2078 \"break the ([%a ]+) with the ([%a ]+)\",\
2079 \"break ([%a ]+) with ([%a ]+) \",\
2080 \"break the ([%a ]+)\",\
2081 \"break ([%a ]+)\",\
2082 \"break\",\
2083 },\
2084 [\"mine\"] = {\
2085 \"mine the ([%a ]+) with the ([%a ]+)\",\
2086 \"mine ([%a ]+) with ([%a ]+)\",\
2087 \"mine ([%a ]+)\",\
2088 \"mine\",\
2089 },\
2090 [\"attack\"] = {\
2091 \"attack the ([%a ]+) with the ([%a ]+)\",\
2092 \"attack ([%a ]+) with ([%a ]+)\",\
2093 \"attack ([%a ]+)\",\
2094 \"attack\",\
2095 \"kill the ([%a ]+) with the ([%a ]+)\",\
2096 \"kill ([%a ]+) with ([%a ]+)\",\
2097 \"kill ([%a ]+)\",\
2098 \"kill\",\
2099 \"hit the ([%a ]+) with the ([%a ]+)\",\
2100 \"hit ([%a ]+) with ([%a ]+)\",\
2101 \"hit ([%a ]+)\",\
2102 \"hit\",\
2103 },\
2104 [\"craft\"] = {\
2105 \"craft a ([%a ]+)\",\
2106 \"craft some ([%a ]+)\",\
2107 \"craft ([%a ]+)\",\
2108 \"craft\",\
2109 \"make a ([%a ]+)\",\
2110 \"make some ([%a ]+)\",\
2111 \"make ([%a ]+)\",\
2112 \"make\",\
2113 },\
2114 [\"build\"] = {\
2115 \"build ([%a ]+) out of ([%a ]+)\",\
2116 \"build ([%a ]+) from ([%a ]+)\",\
2117 \"build ([%a ]+)\",\
2118 \"build\",\
2119 },\
2120 [\"eat\"] = {\
2121 \"eat a ([%a ]+)\",\
2122 \"eat the ([%a ]+)\",\
2123 \"eat ([%a ]+)\",\
2124 \"eat\",\
2125 },\
2126 [\"help\"] = {\
2127 \"help me\",\
2128 \"help\",\
2129 },\
2130 [\"exit\"] = {\
2131 \"exit\",\
2132 \"quit\",\
2133 \"goodbye\",\
2134 \"good bye\",\
2135 \"bye\",\
2136 \"farewell\",\
2137 },\
2138}\
2139\
2140local commands = {}\
2141local function doCommand( text )\
2142 if text == \"\" then\
2143 commands[ \"noinput\" ]()\
2144 return\
2145 end\
2146\
2147 for sCommand, t in pairs( tMatches ) do\
2148 for n, sMatch in pairs( t ) do\
2149 local tCaptures = { string.match( text, \"^\" .. sMatch .. \"$\" ) }\
2150 if #tCaptures ~= 0 then\
2151 local fnCommand = commands[ sCommand ]\
2152 if #tCaptures == 1 and tCaptures[1] == sMatch then\
2153 fnCommand()\
2154 else\
2155 fnCommand( table.unpack( tCaptures ) )\
2156 end\
2157 return\
2158 end\
2159 end\
2160 end\
2161 commands[ \"badinput\" ]()\
2162end\
2163\
2164function commands.wait()\
2165 print( \"Time passes...\" )\
2166end\
2167\
2168function commands.look( _sTarget )\
2169 local room = getRoom( x,y,z )\
2170 if room.dark then\
2171 print( \"It is pitch dark.\" )\
2172 return\
2173 end\
2174\
2175 if _sTarget == nil then\
2176 -- Look at the world\
2177 if y == 0 then\
2178 io.write( \"You are standing \" .. tBiomes[room.nBiome] .. \". \" )\
2179 print( tDayCycle[ getTimeOfDay() ] )\
2180 else\
2181 io.write( \"You are underground. \" )\
2182 if next( room.exits ) ~= nil then\
2183 print( \"You can travel \"..itemize( room.exits )..\".\" )\
2184 else\
2185 print()\
2186 end\
2187 end\
2188 if next( room.items ) ~= nil then\
2189 print( \"There is \" .. itemize( room.items ) .. \" here.\" )\
2190 end\
2191 if room.trees then\
2192 print( \"There are trees here.\" )\
2193 end\
2194\
2195 else\
2196 -- Look at stuff\
2197 if room.trees and (_sTarget == \"tree\" or _sTarget == \"trees\") then\
2198 print( \"The trees look easy to break.\" )\
2199 elseif _sTarget == \"self\" or _sTarget == \"myself\" then\
2200 print( \"Very handsome.\" )\
2201 else\
2202 local tItem = nil\
2203 local sItem = findItem( room.items, _sTarget )\
2204 if sItem then\
2205 tItem = room.items[sItem]\
2206 else\
2207 sItem = findItem( inventory, _sTarget )\
2208 if sItem then\
2209 tItem = inventory[sItem]\
2210 end\
2211 end\
2212\
2213 if tItem then\
2214 print( tItem.desc or (\"You see nothing special about \"..sItem..\".\") )\
2215 else\
2216 print( \"You don't see any \".._sTarget..\" here.\" )\
2217 end\
2218 end\
2219 end\
2220end\
2221\
2222function commands.go( _sDir )\
2223 local room = getRoom( x,y,z )\
2224 if _sDir == nil then\
2225 print( \"Go where?\" )\
2226 return\
2227 end\
2228\
2229 if nGoWest ~= nil then\
2230 if _sDir == \"west\" then\
2231 nGoWest = nGoWest + 1\
2232 if nGoWest > #tGoWest then\
2233 nGoWest = 1\
2234 end\
2235 print( tGoWest[ nGoWest ] )\
2236 else\
2237 if nGoWest > 0 or nTurn > 6 then\
2238 nGoWest = nil\
2239 end\
2240 end\
2241 end\
2242\
2243 if room.exits[_sDir] == nil then\
2244 print( \"You can't go that way.\" )\
2245 return\
2246 end\
2247\
2248 if _sDir == \"north\" then\
2249 z = z + 1\
2250 elseif _sDir == \"south\" then\
2251 z = z - 1\
2252 elseif _sDir == \"east\" then\
2253 x = x - 1\
2254 elseif _sDir == \"west\" then\
2255 x = x + 1\
2256 elseif _sDir == \"up\" then\
2257 y = y + 1\
2258 elseif _sDir == \"down\" then\
2259 y = y - 1\
2260 else\
2261 print( \"I don't understand that direction.\" )\
2262 return\
2263 end\
2264\
2265 nTimeInRoom = 0\
2266 doCommand( \"look\" )\
2267end\
2268\
2269function commands.dig( _sDir, _sTool )\
2270 local room = getRoom( x,y,z )\
2271 if _sDir == nil then\
2272 print( \"Dig where?\" )\
2273 return\
2274 end\
2275\
2276 local sTool = nil\
2277 local tTool = nil\
2278 if _sTool ~= nil then\
2279 sTool = findItem( inventory, _sTool )\
2280 if not sTool then\
2281 print( \"You're not carrying a \".._sTool..\".\" )\
2282 return\
2283 end\
2284 tTool = inventory[ sTool ]\
2285 end\
2286\
2287 local bActuallyDigging = (room.exits[ _sDir ] ~= true)\
2288 if bActuallyDigging then\
2289 if sTool == nil or tTool.toolType ~= \"pick\" then\
2290 print( \"You need to use a pickaxe to dig through stone.\" )\
2291 return\
2292 end\
2293 end\
2294\
2295 if _sDir == \"north\" then\
2296 room.exits[\"north\"] = true\
2297 z = z + 1\
2298 getRoom( x, y, z ).exits[\"south\"] = true\
2299\
2300 elseif _sDir == \"south\" then\
2301 room.exits[\"south\"] = true\
2302 z = z - 1\
2303 getRoom( x, y, z ).exits[\"north\"] = true\
2304\
2305 elseif _sDir == \"east\" then\
2306 room.exits[\"east\"] = true\
2307 x = x - 1\
2308 getRoom( x, y, z ).exits[\"west\"] = true\
2309\
2310 elseif _sDir == \"west\" then\
2311 room.exits[\"west\"] = true\
2312 x = x + 1\
2313 getRoom( x, y, z ).exits[\"east\"] = true\
2314\
2315 elseif _sDir == \"up\" then\
2316 if y == 0 then\
2317 print( \"You can't dig that way.\" )\
2318 return\
2319 end\
2320\
2321 room.exits[\"up\"] = true\
2322 if y == -1 then\
2323 room.items[ \"an exit to the surface\" ] = items[ \"an exit to the surface\" ]\
2324 end\
2325 y = y + 1\
2326\
2327 room = getRoom( x, y, z )\
2328 room.exits[\"down\"] = true\
2329 if y == 0 then\
2330 room.items[ \"a cave entrance\" ] = items[ \"a cave entrance\" ]\
2331 end\
2332\
2333 elseif _sDir == \"down\" then\
2334 if y <= -3 then\
2335 print( \"You hit bedrock.\" )\
2336 return\
2337 end\
2338\
2339 room.exits[\"down\"] = true\
2340 if y == 0 then\
2341 room.items[ \"a cave entrance\" ] = items[ \"a cave entrance\" ]\
2342 end\
2343 y = y - 1\
2344\
2345 room = getRoom( x, y, z )\
2346 room.exits[\"up\"] = true\
2347 if y == -1 then\
2348 room.items[ \"an exit to the surface\" ] = items[ \"an exit to the surface\" ]\
2349 end\
2350\
2351 else\
2352 print( \"I don't understand that direction.\" )\
2353 return\
2354 end\
2355\
2356 --\
2357 if bActuallyDigging then\
2358 if _sDir == \"down\" and y == -1 or\
2359 _sDir == \"up\" and y == 0 then\
2360 inventory[ \"some dirt\" ] = items[ \"some dirt\" ]\
2361 inventory[ \"some stone\" ] = items[ \"some stone\" ]\
2362 print( \"You dig \".._sDir..\" using \"..sTool..\" and collect some dirt and stone.\" )\
2363 else\
2364 inventory[ \"some stone\" ] = items[ \"some stone\" ]\
2365 print( \"You dig \".._sDir..\" using \"..sTool..\" and collect some stone.\" )\
2366 end\
2367 end\
2368\
2369 nTimeInRoom = 0\
2370 doCommand( \"look\" )\
2371end\
2372\
2373function commands.inventory()\
2374 print( \"You are carrying \" .. itemize( inventory ) .. \".\" )\
2375end\
2376\
2377function commands.drop( _sItem )\
2378 if _sItem == nil then\
2379 print( \"Drop what?\" )\
2380 return\
2381 end\
2382\
2383 local room = getRoom( x,y,z )\
2384 local sItem = findItem( inventory, _sItem )\
2385 if sItem then\
2386 local tItem = inventory[ sItem ]\
2387 if tItem.droppable == false then\
2388 print( \"You can't drop that.\" )\
2389 else\
2390 room.items[ sItem ] = tItem\
2391 inventory[ sItem ] = nil\
2392 print( \"Dropped.\" )\
2393 end\
2394 else\
2395 print( \"You don't have a \".._sItem..\".\" )\
2396 end\
2397end\
2398\
2399function commands.place( _sItem )\
2400 if _sItem == nil then\
2401 print( \"Place what?\" )\
2402 return\
2403 end\
2404\
2405 if _sItem == \"torch\" or _sItem == \"a torch\" then\
2406 local room = getRoom( x,y,z )\
2407 if inventory[\"some torches\"] or inventory[\"a torch\"] then\
2408 inventory[\"a torch\"] = nil\
2409 room.items[\"a torch\"] = items[\"a torch\"]\
2410 if room.dark then\
2411 print( \"The cave lights up under the torchflame.\" )\
2412 room.dark = false\
2413 elseif y == 0 and not isSunny() then\
2414 print( \"The night gets a little brighter.\" )\
2415 else\
2416 print( \"Placed.\" )\
2417 end\
2418 else\
2419 print( \"You don't have torches.\" )\
2420 end\
2421 return\
2422 end\
2423\
2424 commands.drop( _sItem )\
2425end\
2426\
2427function commands.take( _sItem )\
2428 if _sItem == nil then\
2429 print( \"Take what?\" )\
2430 return\
2431 end\
2432\
2433 local room = getRoom( x,y,z )\
2434 local sItem = findItem( room.items, _sItem )\
2435 if sItem then\
2436 local tItem = room.items[ sItem ]\
2437 if tItem.heavy == true then\
2438 print( \"You can't carry \"..sItem..\".\" )\
2439 elseif tItem.ore == true then\
2440 print( \"You need to mine this ore.\" )\
2441 else\
2442 if tItem.infinite ~= true then\
2443 room.items[ sItem ] = nil\
2444 end\
2445 inventory[ sItem ] = tItem\
2446\
2447 if inventory[\"some torches\"] and inventory[\"a torch\"] then\
2448 inventory[\"a torch\"] = nil\
2449 end\
2450 if sItem == \"a torch\" and y < 0 then\
2451 room.dark = true\
2452 print( \"The cave plunges into darkness.\" )\
2453 else\
2454 print( \"Taken.\" )\
2455 end\
2456 end\
2457 else\
2458 print( \"You don't see a \".._sItem..\" here.\" )\
2459 end\
2460end\
2461\
2462function commands.mine( _sItem, _sTool )\
2463 if _sItem == nil then\
2464 print( \"Mine what?\" )\
2465 return\
2466 end\
2467 if _sTool == nil then\
2468 print( \"Mine \".._sItem..\" with what?\" )\
2469 return\
2470 end\
2471 commands.cbreak( _sItem, _sTool )\
2472end\
2473\
2474function commands.attack( _sItem, _sTool )\
2475 if _sItem == nil then\
2476 print( \"Attack what?\" )\
2477 return\
2478 end\
2479 commands.cbreak( _sItem, _sTool )\
2480end\
2481\
2482function commands.cbreak( _sItem, _sTool )\
2483 if _sItem == nil then\
2484 print( \"Break what?\" )\
2485 return\
2486 end\
2487\
2488 local sTool = nil\
2489 if _sTool ~= nil then\
2490 sTool = findItem( inventory, _sTool )\
2491 if sTool == nil then\
2492 print( \"You're not carrying a \".._sTool..\".\" )\
2493 return\
2494 end\
2495 end\
2496\
2497 local room = getRoom( x,y,z )\
2498 if _sItem == \"tree\" or _sItem == \"trees\" or _sItem == \"a tree\" then\
2499 print( \"The tree breaks into blocks of wood, which you pick up.\" )\
2500 inventory[ \"some wood\" ] = items[ \"some wood\" ]\
2501 return\
2502 elseif _sItem == \"self\" or _sItem == \"myself\" then\
2503 if term.isColour() then\
2504 term.setTextColour( colours.red )\
2505 end\
2506 print( \"You have died.\" )\
2507 print( \"Score: &e0\" )\
2508 term.setTextColour( colours.white )\
2509 bRunning = false\
2510 return\
2511 end\
2512\
2513 local sItem = findItem( room.items, _sItem )\
2514 if sItem then\
2515 local tItem = room.items[ sItem ]\
2516 if tItem.ore == true then\
2517 -- Breaking ore\
2518 if not sTool then\
2519 print( \"You need a tool to break this ore.\" )\
2520 return\
2521 end\
2522 local tTool = inventory[ sTool ]\
2523 if tTool.tool then\
2524 if tTool.toolLevel < tItem.toolLevel then\
2525 print( sTool ..\" is not strong enough to break this ore.\" )\
2526 elseif tTool.toolType ~= tItem.toolType then\
2527 print( \"You need a different kind of tool to break this ore.\" )\
2528 else\
2529 print( \"The ore breaks, dropping \"..sItem..\", which you pick up.\" )\
2530 inventory[ sItem ] = items[ sItem ]\
2531 if tItem.infinite ~= true then\
2532 room.items[ sItem ] = nil\
2533 end\
2534 end\
2535 else\
2536 print( \"You can't break \"..sItem..\" with \"..sTool..\".\")\
2537 end\
2538\
2539 elseif tItem.creature == true then\
2540 -- Fighting monsters (or pigs)\
2541 local toolLevel = 0\
2542 local tTool = nil\
2543 if sTool then\
2544 tTool = inventory[ sTool ]\
2545 if tTool.toolType == \"sword\" then\
2546 toolLevel = tTool.toolLevel\
2547 end\
2548 end\
2549\
2550 local tChances = { 0.2, 0.4, 0.55, 0.8, 1 }\
2551 if math.random() <= tChances[ toolLevel + 1 ] then\
2552 room.items[ sItem ] = nil\
2553 print( \"The \"..tItem.aliases[1]..\" dies.\" )\
2554\
2555 if tItem.drops then\
2556 for n, sDrop in pairs( tItem.drops ) do\
2557 if not room.items[sDrop] then\
2558 print( \"The \"..tItem.aliases[1]..\" dropped \"..sDrop..\".\" )\
2559 room.items[sDrop] = items[sDrop]\
2560 end\
2561 end\
2562 end\
2563\
2564 if tItem.monster then\
2565 room.nMonsters = room.nMonsters - 1\
2566 end\
2567 else\
2568 print( \"The \"..tItem.aliases[1]..\" is injured by your blow.\" )\
2569 end\
2570\
2571 if tItem.hitDrops then\
2572 for n, sDrop in pairs( tItem.hitDrops ) do\
2573 if not room.items[sDrop] then\
2574 print( \"The \"..tItem.aliases[1]..\" dropped \"..sDrop..\".\" )\
2575 room.items[sDrop] = items[sDrop]\
2576 end\
2577 end\
2578 end\
2579\
2580 else\
2581 print( \"You can't break \"..sItem..\".\" )\
2582 end\
2583 else\
2584 print( \"You don't see a \".._sItem..\" here.\" )\
2585 end\
2586end\
2587\
2588function commands.craft( _sItem )\
2589 if _sItem == nil then\
2590 print( \"Craft what?\" )\
2591 return\
2592 end\
2593\
2594 if _sItem == \"computer\" or _sItem == \"a computer\" then\
2595 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.\" )\
2596 if term.isColour() then\
2597 term.setTextColour( colours.red )\
2598 end\
2599 print( \"You have died.\" )\
2600 print( \"Score: &e0\" )\
2601 term.setTextColour( colours.white )\
2602 bRunning = false\
2603 return\
2604 end\
2605\
2606 local room = getRoom( x,y,z )\
2607 local sItem = findItem( items, _sItem )\
2608 local tRecipe = (sItem and tRecipes[ sItem ]) or nil\
2609 if tRecipe then\
2610 for n,sReq in ipairs( tRecipe ) do\
2611 if inventory[sReq] == nil then\
2612 print( \"You don't have the items you need to craft \"..sItem..\".\" )\
2613 return\
2614 end\
2615 end\
2616\
2617 for n,sReq in ipairs( tRecipe ) do\
2618 inventory[sReq] = nil\
2619 end\
2620 inventory[ sItem ] = items[ sItem ]\
2621 if inventory[\"some torches\"] and inventory[\"a torch\"] then\
2622 inventory[\"a torch\"] = nil\
2623 end\
2624 print( \"Crafted.\" )\
2625 else\
2626 print( \"You don't know how to make \"..(sItem or _sItem)..\".\" )\
2627 end\
2628end\
2629\
2630function commands.build( _sThing, _sMaterial )\
2631 if _sThing == nil then\
2632 print( \"Build what?\" )\
2633 return\
2634 end\
2635\
2636 local sMaterial = nil\
2637 if _sMaterial == nil then\
2638 for sItem, tItem in pairs( inventory ) do\
2639 if tItem.material then\
2640 sMaterial = sItem\
2641 break\
2642 end\
2643 end\
2644 if sMaterial == nil then\
2645 print( \"You don't have any building materials.\" )\
2646 return\
2647 end\
2648 else\
2649 sMaterial = findItem( inventory, _sMaterial )\
2650 if not sMaterial then\
2651 print( \"You don't have any \".._sMaterial )\
2652 return\
2653 end\
2654\
2655 if inventory[sMaterial].material ~= true then\
2656 print( sMaterial..\" is not a good building material.\" )\
2657 return\
2658 end\
2659 end\
2660\
2661 local alias = nil\
2662 if string.sub(_sThing, 1, 1) == \"a\" then\
2663 alias = string.match( _sThing, \"a ([%a ]+)\" )\
2664 end\
2665\
2666 local room = getRoom( x,y,z )\
2667 inventory[sMaterial] = nil\
2668 room.items[ _sThing ] = {\
2669 heavy = true,\
2670 aliases = { alias },\
2671 desc = \"As you look at your creation (made from \"..sMaterial..\"), you feel a swelling sense of pride.\",\
2672 }\
2673\
2674 print( \"Your construction is complete.\" )\
2675end\
2676\
2677function commands.help()\
2678 local sText =\
2679 \"Welcome to adventure, the greatest text adventure game on CraftOS. \" ..\
2680 \"To get around the world, type actions, and the adventure will \" ..\
2681 \"be read back to you. The actions availiable to you are go, look, inspect, inventory, \" ..\
2682 \"take, drop, place, punch, attack, mine, dig, craft, build, eat and exit.\"\
2683 print( sText )\
2684end\
2685\
2686function commands.eat( _sItem )\
2687 if _sItem == nil then\
2688 print( \"Eat what?\" )\
2689 return\
2690 end\
2691\
2692 local sItem = findItem( inventory, _sItem )\
2693 if not sItem then\
2694 print( \"You don't have any \".._sItem..\".\" )\
2695 return\
2696 end\
2697\
2698 local tItem = inventory[sItem]\
2699 if tItem.food then\
2700 print( \"That was delicious!\" )\
2701 inventory[sItem] = nil\
2702\
2703 if bInjured then\
2704 print( \"You are no longer injured.\" )\
2705 bInjured = false\
2706 end\
2707 else\
2708 print( \"You can't eat \"..sItem..\".\" )\
2709 end\
2710end\
2711\
2712function commands.exit()\
2713 bRunning = false\
2714end\
2715\
2716function commands.badinput()\
2717 local tResponses = {\
2718 \"I don't understand.\",\
2719 \"I don't understand you.\",\
2720 \"You can't do that.\",\
2721 \"Nope.\",\
2722 \"Huh?\",\
2723 \"Say again?\",\
2724 \"That's crazy talk.\",\
2725 \"Speak clearly.\",\
2726 \"I'll think about it.\",\
2727 \"Let me get back to you on that one.\",\
2728 \"That doesn't make any sense.\",\
2729 \"What?\",\
2730 }\
2731 print( tResponses[ math.random(1,#tResponses) ] )\
2732end\
2733\
2734function commands.noinput()\
2735 local tResponses = {\
2736 \"Speak up.\",\
2737 \"Enunciate.\",\
2738 \"Project your voice.\",\
2739 \"Don't be shy.\",\
2740 \"Use your words.\",\
2741 }\
2742 print( tResponses[ math.random(1,#tResponses) ] )\
2743end\
2744\
2745local function simulate()\
2746 local bNewMonstersThisRoom = false\
2747\
2748 -- Spawn monsters in nearby rooms\
2749 for sx = -2,2 do\
2750 for sy = -1,1 do\
2751 for sz = -2,2 do\
2752 local h = y + sy\
2753 if h >= -3 and h <= 0 then\
2754 local room = getRoom( x + sx, h, z + sz )\
2755\
2756 -- Spawn monsters\
2757 if room.nMonsters < 2 and\
2758 ((h == 0 and not isSunny() and not room.items[\"a torch\"]) or room.dark) and\
2759 math.random(1,6) == 1 then\
2760\
2761 local sMonster = tMonsters[ math.random(1,#tMonsters) ]\
2762 if room.items[ sMonster ] == nil then\
2763 room.items[ sMonster ] = items[ sMonster ]\
2764 room.nMonsters = room.nMonsters + 1\
2765\
2766 if sx == 0 and sy == 0 and sz == 0 and not room.dark then\
2767 print( \"From the shadows, \"..sMonster..\" appears.\" )\
2768 bNewMonstersThisRoom = true\
2769 end\
2770 end\
2771 end\
2772\
2773 -- Burn monsters\
2774 if h == 0 and isSunny() then\
2775 for n,sMonster in ipairs( tMonsters ) do\
2776 if room.items[sMonster] and items[sMonster].nocturnal then\
2777 room.items[sMonster] = nil\
2778 if sx == 0 and sy == 0 and sz == 0 and not room.dark then\
2779 print( \"With the sun high in the sky, the \"..items[sMonster].aliases[1]..\" bursts into flame and dies.\" )\
2780 end\
2781 room.nMonsters = room.nMonsters - 1\
2782 end\
2783 end\
2784 end\
2785 end\
2786 end\
2787 end\
2788 end\
2789\
2790 -- Make monsters attack\
2791 local room = getRoom( x, y, z )\
2792 if nTimeInRoom >= 2 and not bNewMonstersThisRoom then\
2793 for n,sMonster in ipairs( tMonsters ) do\
2794 if room.items[sMonster] then\
2795 if math.random(1,4) == 1 and\
2796 not (y == 0 and isSunny() and (sMonster == \"a spider\")) then\
2797 if sMonster == \"a creeper\" then\
2798 if room.dark then\
2799 print( \"A creeper explodes.\" )\
2800 else\
2801 print( \"The creeper explodes.\" )\
2802 end\
2803 room.items[sMonster] = nil\
2804 room.nMonsters = room.nMonsters - 1\
2805 else\
2806 if room.dark then\
2807 print( \"A \"..items[sMonster].aliases[1]..\" attacks you.\" )\
2808 else\
2809 print( \"The \"..items[sMonster].aliases[1]..\" attacks you.\" )\
2810 end\
2811 end\
2812\
2813 if bInjured then\
2814 if term.isColour() then\
2815 term.setTextColour( colours.red )\
2816 end\
2817 print( \"You have died.\" )\
2818 print( \"Score: &e0\" )\
2819 term.setTextColour( colours.white )\
2820 bRunning = false\
2821 return\
2822 else\
2823 bInjured = true\
2824 end\
2825\
2826 break\
2827 end\
2828 end\
2829 end\
2830 end\
2831\
2832 -- Always print this\
2833 if bInjured then\
2834 if term.isColour() then\
2835 term.setTextColour( colours.red )\
2836 end\
2837 print( \"You are injured.\" )\
2838 term.setTextColour( colours.white )\
2839 end\
2840\
2841 -- Advance time\
2842 nTurn = nTurn + 1\
2843 nTimeInRoom = nTimeInRoom + 1\
2844end\
2845\
2846doCommand( \"look\" )\
2847simulate()\
2848\
2849local tCommandHistory = {}\
2850while bRunning do\
2851 if term.isColour() then\
2852 term.setTextColour( colours.yellow )\
2853 end\
2854 write( \"? \" )\
2855 term.setTextColour( colours.white )\
2856\
2857 local sRawLine = read( nil, tCommandHistory )\
2858 table.insert( tCommandHistory, sRawLine )\
2859\
2860 local sLine = nil\
2861 for match in string.gmatch(sRawLine, \"%a+\") do\
2862 if sLine then\
2863 sLine = sLine .. \" \" .. string.lower(match)\
2864 else\
2865 sLine = string.lower(match)\
2866 end\
2867 end\
2868\
2869 doCommand( sLine or \"\" )\
2870 if bRunning then\
2871 simulate()\
2872 end\
2873end",
2874 [ "programs/pocket/equip.lua" ] = "local ok, err = pocket.equipBack()\
2875if not ok then\
2876 printError( err )\
2877else\
2878 print( \"Item equipped\" )\
2879end",
2880 [ "help/eject.txt" ] = "eject ejects the contents of an attached disk drive.\
2881\
2882ex:\
2883\"eject left\" ejects the contents of the disk drive to the left of the computer.",
2884 [ "programs/copy.lua" ] = "\
2885local tArgs = { ... }\
2886if #tArgs < 2 then\
2887 print( \"Usage: cp <source> <destination>\" )\
2888 return\
2889end\
2890\
2891local sSource = shell.resolve( tArgs[1] )\
2892local sDest = shell.resolve( tArgs[2] )\
2893local tFiles = fs.find( sSource )\
2894if #tFiles > 0 then\
2895 for n,sFile in ipairs( tFiles ) do\
2896 if fs.isDir( sDest ) then\
2897 fs.copy( sFile, fs.combine( sDest, fs.getName(sFile) ) )\
2898 elseif #tFiles == 1 then\
2899 if fs.exists( sDest ) then\
2900 printError( \"Destination exists\" )\
2901 else\
2902 fs.copy( sFile, sDest )\
2903 end\
2904 else\
2905 printError( \"Cannot overwrite file multiple times\" )\
2906 return\
2907 end\
2908 end\
2909else\
2910 printError( \"No matching files\" )\
2911end",
2912 [ "programs/fun/advanced/paint.lua" ] = "-- Paint created by nitrogenfingers (edited by dan200)\
2913-- http://www.youtube.com/user/NitrogenFingers\
2914\
2915------------\
2916-- Fields --\
2917------------\
2918\
2919-- The width and height of the terminal\
2920local w,h = term.getSize()\
2921\
2922-- The selected colours on the left and right mouse button, and the colour of the canvas\
2923local leftColour, rightColour = colours.white, nil\
2924local canvasColour = colours.black\
2925\
2926-- The values stored in the canvas\
2927local canvas = {}\
2928\
2929-- The menu options\
2930local mChoices = { \"Save\",\"Exit\" }\
2931\
2932-- The message displayed in the footer bar\
2933local fMessage = \"Press Ctrl to access menu\"\
2934\
2935-------------------------\
2936-- Initialisation --\
2937-------------------------\
2938\
2939-- Determine if we can even run this\
2940if not term.isColour() then\
2941 print(\"Requires an Advanced Computer\")\
2942 return\
2943end\
2944\
2945-- Determines if the file exists, and can be edited on this computer\
2946local tArgs = {...}\
2947if #tArgs == 0 then\
2948 print(\"Usage: paint <path>\")\
2949 return\
2950end\
2951local sPath = shell.resolve(tArgs[1])\
2952local bReadOnly = fs.isReadOnly(sPath)\
2953if fs.exists(sPath) and fs.isDir(sPath) then\
2954 print(\"Cannot edit a directory.\")\
2955 return\
2956end\
2957\
2958-- Create .nfp files by default\
2959if not fs.exists( sPath ) and not string.find( sPath, \"%.\" ) then\
2960 local sExtension = settings.get(\"paint.default_extension\", \"\" )\
2961 if sExtension ~= \"\" and type( sExtension ) == \"string\" then\
2962 sPath = sPath .. \".\" .. sExtension\
2963 end\
2964end\
2965\
2966\
2967---------------\
2968-- Functions --\
2969---------------\
2970\
2971local function getCanvasPixel( x, y )\
2972 if canvas[y] then\
2973 return canvas[y][x]\
2974 end\
2975 return nil\
2976end\
2977\
2978--[[\
2979 Converts a colour value to a text character\
2980 params: colour = the number to convert to a hex value\
2981 returns: a string representing the chosen colour\
2982]]\
2983local function getCharOf( colour )\
2984 -- Incorrect values always convert to nil\
2985 if type(colour) == \"number\" then\
2986 local value = math.floor( math.log(colour) / math.log(2) ) + 1\
2987 if value >= 1 and value <= 16 then\
2988 return string.sub( \"0123456789abcdef\", value, value )\
2989 end\
2990 end\
2991 return \" \"\
2992end\
2993\
2994--[[\
2995 Converts a text character to colour value\
2996 params: char = the char (from string.byte) to convert to number\
2997 returns: the colour number of the hex value\
2998]]\
2999local tColourLookup = {}\
3000for n=1,16 do\
3001 tColourLookup[ string.byte( \"0123456789abcdef\",n,n ) ] = 2^(n-1)\
3002end\
3003local function getColourOf( char )\
3004 -- Values not in the hex table are transparent (canvas coloured)\
3005 return tColourLookup[char]\
3006end\
3007\
3008--[[\
3009 Loads the file into the canvas\
3010 params: path = the path of the file to open\
3011 returns: nil\
3012]]\
3013local function load(path)\
3014 -- Load the file\
3015 if fs.exists(path) then\
3016 local file = fs.open(sPath, \"r\")\
3017 local sLine = file.readLine()\
3018 while sLine do\
3019 local line = {}\
3020 for x=1,w-2 do\
3021 line[x] = getColourOf( string.byte(sLine,x,x) )\
3022 end\
3023 table.insert( canvas, line )\
3024 sLine = file.readLine()\
3025 end\
3026 file.close()\
3027 end\
3028end\
3029\
3030--[[\
3031 Saves the current canvas to file\
3032 params: path = the path of the file to save\
3033 returns: true if save was successful, false otherwise\
3034]]\
3035local function save(path)\
3036 -- Open file\
3037 local sDir = string.sub(sPath, 1, #sPath - #fs.getName(sPath))\
3038 if not fs.exists(sDir) then\
3039 fs.makeDir(sDir)\
3040 end\
3041\
3042 local file, err = fs.open( path, \"w\" )\
3043 if not file then\
3044 return false, err\
3045 end\
3046\
3047 -- Encode (and trim)\
3048 local tLines = {}\
3049 local nLastLine = 0\
3050 for y=1,h-1 do\
3051 local sLine = \"\"\
3052 local nLastChar = 0\
3053 for x=1,w-2 do\
3054 local c = getCharOf( getCanvasPixel( x, y ) )\
3055 sLine = sLine .. c\
3056 if c ~= \" \" then\
3057 nLastChar = x\
3058 end\
3059 end\
3060 sLine = string.sub( sLine, 1, nLastChar )\
3061 tLines[y] = sLine\
3062 if string.len( sLine ) > 0 then\
3063 nLastLine = y\
3064 end\
3065 end\
3066\
3067 -- Save out\
3068 for n=1,nLastLine do\
3069 file.writeLine( tLines[ n ] )\
3070 end\
3071 file.close()\
3072 return true\
3073end\
3074\
3075--[[\
3076 Draws colour picker sidebar, the pallette and the footer\
3077 returns: nil\
3078]]\
3079local function drawInterface()\
3080 -- Footer\
3081 term.setCursorPos(1, h)\
3082 term.setBackgroundColour(colours.black)\
3083 term.setTextColour(colours.yellow)\
3084 term.clearLine()\
3085 term.write(fMessage)\
3086\
3087 -- Colour Picker\
3088 for i=1,16 do\
3089 term.setCursorPos(w-1, i)\
3090 term.setBackgroundColour( 2^(i-1) )\
3091 term.write(\" \")\
3092 end\
3093\
3094 term.setCursorPos(w-1, 17)\
3095 term.setBackgroundColour( canvasColour )\
3096 term.setTextColour( colours.grey )\
3097 term.write(\"\\127\\127\")\
3098\
3099 -- Left and Right Selected Colours\
3100 for i=18,18 do\
3101 term.setCursorPos(w-1, i)\
3102 if leftColour ~= nil then\
3103 term.setBackgroundColour( leftColour )\
3104 term.write(\" \")\
3105 else\
3106 term.setBackgroundColour( canvasColour )\
3107 term.setTextColour( colours.grey )\
3108 term.write(\"\\127\")\
3109 end\
3110 if rightColour ~= nil then\
3111 term.setBackgroundColour( rightColour )\
3112 term.write(\" \")\
3113 else\
3114 term.setBackgroundColour( canvasColour )\
3115 term.setTextColour( colours.grey )\
3116 term.write(\"\\127\")\
3117 end\
3118 end\
3119\
3120 -- Padding\
3121 term.setBackgroundColour( canvasColour )\
3122 for i=20,h-1 do\
3123 term.setCursorPos(w-1, i)\
3124 term.write(\" \")\
3125 end\
3126end\
3127\
3128--[[\
3129 Converts a single pixel of a single line of the canvas and draws it\
3130 returns: nil\
3131]]\
3132local function drawCanvasPixel( x, y )\
3133 local pixel = getCanvasPixel( x, y )\
3134 if pixel then\
3135 term.setBackgroundColour( pixel or canvasColour )\
3136 term.setCursorPos(x, y)\
3137 term.write(\" \")\
3138 else\
3139 term.setBackgroundColour( canvasColour )\
3140 term.setTextColour( colours.grey )\
3141 term.setCursorPos(x, y)\
3142 term.write(\"\\127\")\
3143 end\
3144end\
3145\
3146--[[\
3147 Converts each colour in a single line of the canvas and draws it\
3148 returns: nil\
3149]]\
3150local function drawCanvasLine( y )\
3151 for x = 1, w-2 do\
3152 drawCanvasPixel( x, y )\
3153 end\
3154end\
3155\
3156--[[\
3157 Converts each colour in the canvas and draws it\
3158 returns: nil\
3159]]\
3160local function drawCanvas()\
3161 for y = 1, h-1 do\
3162 drawCanvasLine( y )\
3163 end\
3164end\
3165\
3166--[[\
3167 Draws menu options and handles input from within the menu.\
3168 returns: true if the program is to be exited; false otherwise\
3169]]\
3170local function accessMenu()\
3171 -- Selected menu option\
3172 local selection = 1\
3173\
3174 term.setBackgroundColour(colours.black)\
3175 while true do\
3176 -- Draw the menu\
3177 term.setCursorPos(1,h)\
3178 term.clearLine()\
3179 term.setTextColour(colours.white)\
3180 for k,v in pairs(mChoices) do\
3181 if selection==k then\
3182 term.setTextColour(colours.yellow)\
3183 local ox,_ = term.getCursorPos()\
3184 term.write(\"[\"..string.rep(\" \",#v)..\"]\")\
3185 term.setCursorPos(ox+1,h)\
3186 term.setTextColour(colours.white)\
3187 term.write(v)\
3188 term.setCursorPos(term.getCursorPos()+1,h)\
3189 else\
3190 term.write(\" \"..v..\" \")\
3191 end\
3192 end\
3193\
3194 -- Handle input in the menu\
3195 local id,key = os.pullEvent(\"key\")\
3196 if id == \"key\" then\
3197 -- S and E are shortcuts\
3198 if key == keys.s then\
3199 selection = 1\
3200 key = keys.enter\
3201 elseif key == keys.e then\
3202 selection = 2\
3203 key = keys.enter\
3204 end\
3205\
3206 if key == keys.right then\
3207 -- Move right\
3208 selection = selection + 1\
3209 if selection > #mChoices then\
3210 selection = 1\
3211 end\
3212\
3213 elseif key == keys.left and selection > 1 then\
3214 -- Move left\
3215 selection = selection - 1\
3216 if selection < 1 then\
3217 selection = #mChoices\
3218 end\
3219\
3220 elseif key == keys.enter then\
3221 -- Select an option\
3222 if mChoices[selection]==\"Save\" then\
3223 if bReadOnly then\
3224 fMessage = \"Access denied\"\
3225 return false\
3226 end\
3227 local success, err = save(sPath)\
3228 if success then\
3229 fMessage = \"Saved to \"..sPath\
3230 else\
3231 if err then\
3232 fMessage = \"Error saving to \"..err\
3233 else\
3234 fMessage = \"Error saving to \"..sPath\
3235 end\
3236 end\
3237 return false\
3238 elseif mChoices[selection]==\"Exit\" then\
3239 return true\
3240 end\
3241 elseif key == keys.leftCtrl or keys == keys.rightCtrl then\
3242 -- Cancel the menu\
3243 return false\
3244 end\
3245 end\
3246 end\
3247end\
3248\
3249--[[\
3250 Runs the main thread of execution. Draws the canvas and interface, and handles\
3251 mouse and key events.\
3252 returns: nil\
3253]]\
3254local function handleEvents()\
3255 local programActive = true\
3256 while programActive do\
3257 local id,p1,p2,p3 = os.pullEvent()\
3258 if id==\"mouse_click\" or id==\"mouse_drag\" then\
3259 if p2 >= w-1 and p3 >= 1 and p3 <= 17 then\
3260 if id ~= \"mouse_drag\" then\
3261 -- Selecting an items in the colour picker\
3262 if p3 <= 16 then\
3263 if p1==1 then\
3264 leftColour = 2^(p3-1)\
3265 else\
3266 rightColour = 2^(p3-1)\
3267 end\
3268 else\
3269 if p1==1 then\
3270 leftColour = nil\
3271 else\
3272 rightColour = nil\
3273 end\
3274 end\
3275 --drawCanvas()\
3276 drawInterface()\
3277 end\
3278 elseif p2 < w-1 and p3 <= h-1 then\
3279 -- Clicking on the canvas\
3280 local paintColour = nil\
3281 if p1==1 then\
3282 paintColour = leftColour\
3283 elseif p1==2 then\
3284 paintColour = rightColour\
3285 end\
3286 if not canvas[p3] then\
3287 canvas[p3] = {}\
3288 end\
3289 canvas[p3][p2] = paintColour\
3290\
3291 drawCanvasPixel( p2, p3 )\
3292 end\
3293 elseif id==\"key\" then\
3294 if p1==keys.leftCtrl or p1==keys.rightCtrl then\
3295 programActive = not accessMenu()\
3296 drawInterface()\
3297 end\
3298 elseif id==\"term_resize\" then\
3299 w,h = term.getSize()\
3300 drawCanvas()\
3301 drawInterface()\
3302 end\
3303 end\
3304end\
3305\
3306-- Init\
3307load(sPath)\
3308drawCanvas()\
3309drawInterface()\
3310\
3311-- Main loop\
3312handleEvents()\
3313\
3314-- Shutdown\
3315term.setBackgroundColour(colours.black)\
3316term.setTextColour(colours.white)\
3317term.clear()\
3318term.setCursorPos(1,1)",
3319 [ "help/cd.txt" ] = "cd changes the directory you're in.\
3320\
3321ex:\
3322\"cd rom\" will move to \"rom\" folder.\
3323\"cd ..\" will move up one folder.\
3324\"cd /\" will move to the root.",
3325 [ "programs/fun/advanced/levels/8.dat" ] = "4\
3326777777 7777\
33277287b7 7867\
3328788787 7887\
332977878777877\
3330 7888eb8887\
3331 77877787877\
3332 7887 787887\
3333 7487 7e7807\
3334 7777 777777",
3335 [ "apis/paintutils.lua" ] = "\
3336local function drawPixelInternal( xPos, yPos )\
3337 term.setCursorPos( xPos, yPos )\
3338 term.write(\" \")\
3339end\
3340\
3341local tColourLookup = {}\
3342for n=1,16 do\
3343 tColourLookup[ string.byte( \"0123456789abcdef\",n,n ) ] = 2^(n-1)\
3344end\
3345\
3346local function parseLine( tImageArg, sLine )\
3347 local tLine = {}\
3348 for x=1,sLine:len() do\
3349 tLine[x] = tColourLookup[ string.byte(sLine,x,x) ] or 0\
3350 end\
3351 table.insert( tImageArg, tLine )\
3352end\
3353\
3354function parseImage( sRawData )\
3355 if type( sRawData ) ~= \"string\" then\
3356 error( \"bad argument #1 (expected string, got \" .. type( sRawData ) .. \")\" )\
3357 end\
3358 local tImage = {}\
3359 for sLine in ( sRawData .. \"\\n\" ):gmatch( \"(.-)\\n\" ) do -- read each line like original file handling did\
3360 parseLine( tImage, sLine )\
3361 end\
3362 return tImage\
3363end\
3364\
3365function loadImage( sPath )\
3366 if type( sPath ) ~= \"string\" then\
3367 error( \"bad argument #1 (expected string, got \" .. type( sPath ) .. \")\", 2 )\
3368 end\
3369\
3370 if fs.exists( sPath ) then\
3371 local file = io.open( sPath, \"r\" )\
3372 local sContent = file:read(\"*a\")\
3373 file:close()\
3374 return parseImage( sContent ) -- delegate image parse to parseImage\
3375 end\
3376 return nil\
3377end\
3378\
3379function drawPixel( xPos, yPos, nColour )\
3380 if type( xPos ) ~= \"number\" then error( \"bad argument #1 (expected number, got \" .. type( xPos ) .. \")\", 2 ) end\
3381 if type( yPos ) ~= \"number\" then error( \"bad argument #2 (expected number, got \" .. type( yPos ) .. \")\", 2 ) end\
3382 if nColour ~= nil and type( nColour ) ~= \"number\" then error( \"bad argument #3 (expected number, got \" .. type( nColour ) .. \")\", 2 ) end\
3383 if nColour then\
3384 term.setBackgroundColor( nColour )\
3385 end\
3386 drawPixelInternal( xPos, yPos )\
3387end\
3388\
3389function drawLine( startX, startY, endX, endY, nColour )\
3390 if type( startX ) ~= \"number\" then error( \"bad argument #1 (expected number, got \" .. type( startX ) .. \")\", 2 ) end\
3391 if type( startY ) ~= \"number\" then error( \"bad argument #2 (expected number, got \" .. type( startY ) .. \")\", 2 ) end\
3392 if type( endX ) ~= \"number\" then error( \"bad argument #3 (expected number, got \" .. type( endX ) .. \")\", 2 ) end\
3393 if type( endY ) ~= \"number\" then error( \"bad argument #4 (expected number, got \" .. type( endY ) .. \")\", 2 ) end\
3394 if nColour ~= nil and type( nColour ) ~= \"number\" then error( \"bad argument #5 (expected number, got \" .. type( nColour ) .. \")\", 2 ) end\
3395\
3396 startX = math.floor(startX)\
3397 startY = math.floor(startY)\
3398 endX = math.floor(endX)\
3399 endY = math.floor(endY)\
3400\
3401 if nColour then\
3402 term.setBackgroundColor( nColour )\
3403 end\
3404 if startX == endX and startY == endY then\
3405 drawPixelInternal( startX, startY )\
3406 return\
3407 end\
3408\
3409 local minX = math.min( startX, endX )\
3410 local maxX, minY, maxY\
3411 if minX == startX then\
3412 minY = startY\
3413 maxX = endX\
3414 maxY = endY\
3415 else\
3416 minY = endY\
3417 maxX = startX\
3418 maxY = startY\
3419 end\
3420\
3421 -- TODO: clip to screen rectangle?\
3422\
3423 local xDiff = maxX - minX\
3424 local yDiff = maxY - minY\
3425\
3426 if xDiff > math.abs(yDiff) then\
3427 local y = minY\
3428 local dy = yDiff / xDiff\
3429 for x=minX,maxX do\
3430 drawPixelInternal( x, math.floor( y + 0.5 ) )\
3431 y = y + dy\
3432 end\
3433 else\
3434 local x = minX\
3435 local dx = xDiff / yDiff\
3436 if maxY >= minY then\
3437 for y=minY,maxY do\
3438 drawPixelInternal( math.floor( x + 0.5 ), y )\
3439 x = x + dx\
3440 end\
3441 else\
3442 for y=minY,maxY,-1 do\
3443 drawPixelInternal( math.floor( x + 0.5 ), y )\
3444 x = x - dx\
3445 end\
3446 end\
3447 end\
3448end\
3449\
3450function drawBox( startX, startY, endX, endY, nColour )\
3451 if type( startX ) ~= \"number\" then error( \"bad argument #1 (expected number, got \" .. type( startX ) .. \")\", 2 ) end\
3452 if type( startY ) ~= \"number\" then error( \"bad argument #2 (expected number, got \" .. type( startY ) .. \")\", 2 ) end\
3453 if type( endX ) ~= \"number\" then error( \"bad argument #3 (expected number, got \" .. type( endX ) .. \")\", 2 ) end\
3454 if type( endY ) ~= \"number\" then error( \"bad argument #4 (expected number, got \" .. type( endY ) .. \")\", 2 ) end\
3455 if nColour ~= nil and type( nColour ) ~= \"number\" then error( \"bad argument #5 (expected number, got \" .. type( nColour ) .. \")\", 2 ) end\
3456\
3457 startX = math.floor(startX)\
3458 startY = math.floor(startY)\
3459 endX = math.floor(endX)\
3460 endY = math.floor(endY)\
3461\
3462 if nColour then\
3463 term.setBackgroundColor( nColour )\
3464 end\
3465 if startX == endX and startY == endY then\
3466 drawPixelInternal( startX, startY )\
3467 return\
3468 end\
3469\
3470 local minX = math.min( startX, endX )\
3471 local maxX, minY, maxY\
3472 if minX == startX then\
3473 minY = startY\
3474 maxX = endX\
3475 maxY = endY\
3476 else\
3477 minY = endY\
3478 maxX = startX\
3479 maxY = startY\
3480 end\
3481\
3482 for x=minX,maxX do\
3483 drawPixelInternal( x, minY )\
3484 drawPixelInternal( x, maxY )\
3485 end\
3486\
3487 if (maxY - minY) >= 2 then\
3488 for y=(minY+1),(maxY-1) do\
3489 drawPixelInternal( minX, y )\
3490 drawPixelInternal( maxX, y )\
3491 end\
3492 end\
3493end\
3494\
3495function drawFilledBox( startX, startY, endX, endY, nColour )\
3496 if type( startX ) ~= \"number\" then error( \"bad argument #1 (expected number, got \" .. type( startX ) .. \")\", 2 ) end\
3497 if type( startY ) ~= \"number\" then error( \"bad argument #2 (expected number, got \" .. type( startY ) .. \")\", 2 ) end\
3498 if type( endX ) ~= \"number\" then error( \"bad argument #3 (expected number, got \" .. type( endX ) .. \")\", 2 ) end\
3499 if type( endY ) ~= \"number\" then error( \"bad argument #4 (expected number, got \" .. type( endY ) .. \")\", 2 ) end\
3500 if nColour ~= nil and type( nColour ) ~= \"number\" then error( \"bad argument #5 (expected number, got \" .. type( nColour ) .. \")\", 2 ) end\
3501\
3502 startX = math.floor(startX)\
3503 startY = math.floor(startY)\
3504 endX = math.floor(endX)\
3505 endY = math.floor(endY)\
3506\
3507 if nColour then\
3508 term.setBackgroundColor( nColour )\
3509 end\
3510 if startX == endX and startY == endY then\
3511 drawPixelInternal( startX, startY )\
3512 return\
3513 end\
3514\
3515 local minX = math.min( startX, endX )\
3516 local maxX, minY, maxY\
3517 if minX == startX then\
3518 minY = startY\
3519 maxX = endX\
3520 maxY = endY\
3521 else\
3522 minY = endY\
3523 maxX = startX\
3524 maxY = startY\
3525 end\
3526\
3527 for x=minX,maxX do\
3528 for y=minY,maxY do\
3529 drawPixelInternal( x, y )\
3530 end\
3531 end\
3532end\
3533\
3534function drawImage( tImage, xPos, yPos )\
3535 if type( tImage ) ~= \"table\" then error( \"bad argument #1 (expected table, got \" .. type( tImage ) .. \")\", 2 ) end\
3536 if type( xPos ) ~= \"number\" then error( \"bad argument #2 (expected number, got \" .. type( xPos ) .. \")\", 2 ) end\
3537 if type( yPos ) ~= \"number\" then error( \"bad argument #3 (expected number, got \" .. type( yPos ) .. \")\", 2 ) end\
3538 for y=1,#tImage do\
3539 local tLine = tImage[y]\
3540 for x=1,#tLine do\
3541 if tLine[x] > 0 then\
3542 term.setBackgroundColor( tLine[x] )\
3543 drawPixelInternal( x + xPos - 1, y + yPos - 1 )\
3544 end\
3545 end\
3546 end\
3547end",
3548 [ "help/id.txt" ] = "id prints the unique identifier of this computer, or a Disk in an attached Disk Drive.\
3549\
3550ex:\
3551\"id\" will print this Computers ID and label\
3552\"id left\" will print the ID and label of the disk in the Disk Drive on the left",
3553 [ "programs/http/wget.lua" ] = "\
3554local function printUsage()\
3555 print( \"Usage:\" )\
3556 print( \"wget <url> [filename]\" )\
3557end\
3558\
3559local tArgs = { ... }\
3560if #tArgs < 1 then\
3561 printUsage()\
3562 return\
3563end\
3564\
3565if not http then\
3566 printError( \"wget requires http API\" )\
3567 printError( \"Set http_enable to true in ComputerCraft.cfg\" )\
3568 return\
3569end\
3570\
3571local function getFilename( sUrl )\
3572 sUrl = sUrl:gsub( \"[#?].*\" , \"\" ):gsub( \"/+$\" , \"\" )\
3573 return sUrl:match( \"/([^/]+)$\" )\
3574end\
3575\
3576local function get( sUrl )\
3577 write( \"Connecting to \" .. sUrl .. \"... \" )\
3578\
3579 local response = http.get( sUrl , nil , true )\
3580 if not response then\
3581 print( \"Failed.\" )\
3582 return nil\
3583 end\
3584\
3585 print( \"Success.\" )\
3586\
3587 local sResponse = response.readAll()\
3588 response.close()\
3589 return sResponse\
3590end\
3591\
3592-- Determine file to download\
3593local sUrl = tArgs[1]\
3594\
3595--Check if the URL is valid\
3596local ok, err = http.checkURL( sUrl )\
3597if not ok then\
3598 printError( err or \"Invalid URL.\" )\
3599 return\
3600end\
3601\
3602local sFile = tArgs[2] or getFilename( sUrl )\
3603local sPath = shell.resolve( sFile )\
3604if fs.exists( sPath ) then\
3605 print( \"File already exists\" )\
3606 return\
3607end\
3608\
3609-- Do the get\
3610local res = get( sUrl )\
3611if res then\
3612 local file = fs.open( sPath, \"wb\" )\
3613 file.write( res )\
3614 file.close()\
3615\
3616 print( \"Downloaded as \"..sFile )\
3617end",
3618 [ "programs/command/commands.lua" ] = "\
3619if not commands then\
3620 printError( \"Requires a Command Computer.\" )\
3621 return\
3622end\
3623\
3624local tCommands = commands.list()\
3625table.sort( tCommands )\
3626\
3627if term.isColor() then\
3628 term.setTextColor( colors.green )\
3629end\
3630print( \"Available commands:\" )\
3631term.setTextColor( colors.white )\
3632\
3633textutils.pagedTabulate( tCommands )",
3634 [ "autorun/emu.lua" ] = "-- Setup completion functions\
3635local function completeMultipleChoice(text, options, addSpaces)\
3636 local tResults = {}\
3637 for n = 1, #options do\
3638 local sOption = options[n]\
3639 if #sOption + (addSpaces and 1 or 0) > #text and sOption:sub(1, #text) == text then\
3640 local sResult = sOption:sub(#text + 1)\
3641 if addSpaces then\
3642 table.insert(tResults, sResult .. \" \")\
3643 else\
3644 table.insert(tResults, sResult)\
3645 end\
3646 end\
3647 end\
3648 return tResults\
3649end\
3650\
3651local commands = { \"close\", \"open\", \"data\", \"config\" }\
3652shell.setCompletionFunction(\"rom/programs/emu.lua\", function(shell, index, text, previous)\
3653 if index == 1 then\
3654 return completeMultipleChoice(text, commands, true)\
3655 end\
3656end)",
3657 [ "help/string.txt" ] = "string is a standard Lua5.1 API.\
3658Refer to http://www.lua.org/manual/5.1/ for more information.",
3659 [ "help/turtle.txt" ] = "turtle is an api availiable on Turtles, which controls their movement.\
3660Functions in the Turtle API:\
3661turtle.forward()\
3662turtle.back()\
3663turtle.up()\
3664turtle.down()\
3665turtle.turnLeft()\
3666turtle.turnRight()\
3667turtle.select( slotNum )\
3668turtle.getSelectedSlot()\
3669turtle.getItemCount( [slotNum] )\
3670turtle.getItemSpace( [slotNum] )\
3671turtle.getItemDetail( [slotNum] )\
3672turtle.equipLeft()\
3673turtle.equipRight()\
3674turtle.dig( [toolSide] )\
3675turtle.digUp( [toolSide] )\
3676turtle.digDown( [toolSide] )\
3677turtle.place()\
3678turtle.placeUp()\
3679turtle.placeDown()\
3680turtle.attack( [toolSide] )\
3681turtle.attackUp( [toolSide] )\
3682turtle.attackDown( [toolSide] )\
3683turtle.detect()\
3684turtle.detectUp()\
3685turtle.detectDown()\
3686turtle.compare()\
3687turtle.compareUp()\
3688turtle.compareDown()\
3689turtle.inspect()\
3690turtle.inspectUp()\
3691turtle.inspectDown()\
3692turtle.compareTo( slotNum )\
3693turtle.transferTo( slotNum, [quantity] )\
3694turtle.drop( [quantity] )\
3695turtle.dropUp( [quantity] )\
3696turtle.dropDown( [quantity] )\
3697turtle.suck( [quantity] )\
3698turtle.suckUp( [quantity] )\
3699turtle.suckDown( [quantity] )\
3700turtle.getFuelLevel()\
3701turtle.getFuelLimit()\
3702turtle.refuel( [quantity] )\
3703turtle.craft( [quantity] ) (requires Crafty Turtle)\
3704\
3705Events fired by the Turtle API:\
3706\"turtle_inventory\" when any of the items in the inventory are changed. Use comparison operations to inspect the changes.",
3707 [ "apis/help.lua" ] = "\
3708local sPath = \"/rom/help\"\
3709\
3710function path()\
3711 return sPath\
3712end\
3713\
3714function setPath( _sPath )\
3715 if type( _sPath ) ~= \"string\" then\
3716 error( \"bad argument #1 (expected string, got \" .. type( _sPath ) .. \")\", 2 )\
3717 end\
3718 sPath = _sPath\
3719end\
3720\
3721function lookup( _sTopic )\
3722 if type( _sTopic ) ~= \"string\" then\
3723 error( \"bad argument #1 (expected string, got \" .. type( _sTopic ) .. \")\", 2 )\
3724 end\
3725 -- Look on the path variable\
3726 for sPath in string.gmatch(sPath, \"[^:]+\") do\
3727 sPath = fs.combine( sPath, _sTopic )\
3728 if fs.exists( sPath ) and not fs.isDir( sPath ) then\
3729 return sPath\
3730 elseif fs.exists( sPath..\".txt\" ) and not fs.isDir( sPath..\".txt\" ) then\
3731 return sPath..\".txt\"\
3732 end\
3733 end\
3734\
3735 -- Not found\
3736 return nil\
3737end\
3738\
3739function topics()\
3740 -- Add index\
3741 local tItems = {\
3742 [ \"index\" ] = true\
3743 }\
3744\
3745 -- Add topics from the path\
3746 for sPath in string.gmatch(sPath, \"[^:]+\") do\
3747 if fs.isDir( sPath ) then\
3748 local tList = fs.list( sPath )\
3749 for n,sFile in pairs( tList ) do\
3750 if string.sub( sFile, 1, 1 ) ~= \".\" then\
3751 if not fs.isDir( fs.combine( sPath, sFile ) ) then\
3752 if #sFile > 4 and sFile:sub(-4) == \".txt\" then\
3753 sFile = sFile:sub(1,-5)\
3754 end\
3755 tItems[ sFile ] = true\
3756 end\
3757 end\
3758 end\
3759 end\
3760 end\
3761\
3762 -- Sort and return\
3763 local tItemList = {}\
3764 for sItem, b in pairs( tItems ) do\
3765 table.insert( tItemList, sItem )\
3766 end\
3767 table.sort( tItemList )\
3768 return tItemList\
3769end\
3770\
3771function completeTopic( sText )\
3772 if type( sText ) ~= \"string\" then\
3773 error( \"bad argument #1 (expected string, got \" .. type( sText ) .. \")\", 2 )\
3774 end\
3775 local tTopics = topics()\
3776 local tResults = {}\
3777 for n=1,#tTopics do\
3778 local sTopic = tTopics[n]\
3779 if #sTopic > #sText and string.sub( sTopic, 1, #sText ) == sText then\
3780 table.insert( tResults, string.sub( sTopic, #sText + 1 ) )\
3781 end\
3782 end\
3783 return tResults\
3784end",
3785 [ "help/settings.txt" ] = "Functions in the Settings API:\
3786settings.get( name, [default] )\
3787settings.set( name, value )\
3788settings.unset( name )\
3789settings.load( path )\
3790settings.save( path )\
3791settings.clear()\
3792settings.getNames()\
3793\
3794Default Settings:\
3795shell.autocomplete - enables auto-completion in the Shell.\
3796lua.autocomplete - enables auto-completion in the Lua program.\
3797edit.autocomplete - enables auto-completion in the Edit program.\
3798edit.default_extension - sets the default file extension for files created with the Edit program\
3799paint.default_extension - sets the default file extension for files created with the Paint program\
3800bios.use_multishell - enables Multishell on Advanced Computers, Turtles, Pocket Computers and Command Computers.\
3801shell.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.\
3802shell.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.\
3803list.show_hidden - determines, whether the List program will list hidden files or not.",
3804 [ "help/colours.txt" ] = "Functions in the colours api\
3805(used for redstone.setBundledOutput):\
3806colours.combine( colour1, colour2, colour3, ...)\
3807colours.subtract( colours, colour1, colour2, ...)\
3808colours.test( colours, colour )\
3809colours.rgb8( r, g, b )\
3810\
3811Colour constants in the colours api, in ascending bit order:\
3812colours.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.",
3813 [ "help/os.txt" ] = "Functions in the os (Operating System) API:\
3814os.version()\
3815os.getComputerID()\
3816os.getComputerLabel()\
3817os.setComputerLabel()\
3818os.run( environment, programpath, arguments )\
3819os.loadAPI( path )\
3820os.unloadAPI( name )\
3821os.pullEvent( [filter] )\
3822os.queueEvent( event, arguments )\
3823os.clock()\
3824os.startTimer( timeout )\
3825os.cancelTimer( token )\
3826os.sleep( timeout )\
3827os.time( [source] )\
3828os.day( [source] )\
3829os.epoch( [source] )\
3830os.setAlarm( time )\
3831os.cancelAlarm( token )\
3832os.shutdown()\
3833os.reboot()\
3834\
3835Events emitted by the os API:\
3836\"timer\" when a timeout started by os.startTimer() completes. Argument is the token returned by os.startTimer().\
3837\"alarm\" when a time passed to os.setAlarm() is reached. Argument is the token returned by os.setAlarm().\
3838Type \"help events\" to learn about the event system.",
3839 [ "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.\
3840\
3841ex:\
3842\"unequip left\" will remove the item on the left side of the turtle\
3843\"unequip\" on a Pocket Computer will remove the item from the Pocket Computer",
3844 [ "modules/main/.ignoreme" ] = "--[[\
3845Alright then, don't ignore me. This file is to ensure the existence of the \"modules/main\" folder.\
3846You can use this folder to add modules who can be loaded with require() to your Resourcepack.\
3847]]",
3848 [ "apis/command/commands.lua" ] = "\
3849if not commands then\
3850 error( \"Cannot load command API on normal computer\", 2 )\
3851end\
3852native = commands.native or commands\
3853\
3854local function collapseArgs( bJSONIsNBT, ... )\
3855 local args = table.pack(...)\
3856 for i = 1, #args do\
3857 local arg = args[i]\
3858 if type(arg) == \"boolean\" or type(arg) == \"number\" or type(arg) == \"string\" then\
3859 args[i] = tostring(arg)\
3860 elseif type(arg) == \"table\" then\
3861 args[i] = textutils.serialiseJSON( arg, bJSONIsNBT )\
3862 else\
3863 error( \"Expected string, number, boolean or table\", 3 )\
3864 end\
3865 end\
3866\
3867 return table.concat(args, \" \")\
3868end\
3869\
3870-- Put native functions into the environment\
3871local env = _ENV\
3872for k,v in pairs( native ) do\
3873 env[k] = v\
3874end\
3875\
3876-- Create wrapper functions for all the commands\
3877local tAsync = {}\
3878local tNonNBTJSONCommands = {\
3879 [ \"tellraw\" ] = true,\
3880 [ \"title\" ] = true\
3881}\
3882local tCommands = native.list()\
3883for n,sCommandName in ipairs(tCommands) do\
3884 if env[ sCommandName ] == nil then\
3885 local bJSONIsNBT = (tNonNBTJSONCommands[ sCommandName ] == nil)\
3886 env[ sCommandName ] = function( ... )\
3887 local sCommand = collapseArgs( bJSONIsNBT, sCommandName, ... )\
3888 return native.exec( sCommand )\
3889 end\
3890 tAsync[ sCommandName ] = function( ... )\
3891 local sCommand = collapseArgs( bJSONIsNBT, sCommandName, ... )\
3892 return native.execAsync( sCommand )\
3893 end\
3894 end\
3895end\
3896env.async = tAsync",
3897 [ "help/reboot.txt" ] = "reboot will turn the computer off and on again.\
3898You can also hold Ctrl+R at any time to quickly reboot.",
3899 [ "apis/textutils.lua" ] = "\
3900function slowWrite( sText, nRate )\
3901 if nRate ~= nil and type( nRate ) ~= \"number\" then\
3902 error( \"bad argument #2 (expected number, got \" .. type( nRate ) .. \")\", 2 )\
3903 end\
3904 nRate = nRate or 20\
3905 if nRate < 0 then\
3906 error( \"Rate must be positive\", 2 )\
3907 end\
3908 local nSleep = 1 / nRate\
3909\
3910 sText = tostring( sText )\
3911 local x,y = term.getCursorPos()\
3912 local len = string.len( sText )\
3913\
3914 for n=1,len do\
3915 term.setCursorPos( x, y )\
3916 sleep( nSleep )\
3917 local nLines = write( string.sub( sText, 1, n ) )\
3918 local newX, newY = term.getCursorPos()\
3919 y = newY - nLines\
3920 end\
3921end\
3922\
3923function slowPrint( sText, nRate )\
3924 slowWrite( sText, nRate )\
3925 print()\
3926end\
3927\
3928function formatTime( nTime, bTwentyFourHour )\
3929 if type( nTime ) ~= \"number\" then\
3930 error( \"bad argument #1 (expected number, got \" .. type( nTime ) .. \")\", 2 )\
3931 end\
3932 if bTwentyFourHour ~= nil and type( bTwentyFourHour ) ~= \"boolean\" then\
3933 error( \"bad argument #2 (expected boolean, got \" .. type( bTwentyFourHour ) .. \")\", 2 )\
3934 end\
3935 local sTOD = nil\
3936 if not bTwentyFourHour then\
3937 if nTime >= 12 then\
3938 sTOD = \"PM\"\
3939 else\
3940 sTOD = \"AM\"\
3941 end\
3942 if nTime >= 13 then\
3943 nTime = nTime - 12\
3944 end\
3945 end\
3946\
3947 local nHour = math.floor(nTime)\
3948 local nMinute = math.floor((nTime - nHour)*60)\
3949 if sTOD then\
3950 return string.format( \"%d:%02d %s\", nHour, nMinute, sTOD )\
3951 else\
3952 return string.format( \"%d:%02d\", nHour, nMinute )\
3953 end\
3954end\
3955\
3956local function makePagedScroll( _term, _nFreeLines )\
3957 local nativeScroll = _term.scroll\
3958 local nFreeLines = _nFreeLines or 0\
3959 return function( _n )\
3960 for n=1,_n do\
3961 nativeScroll( 1 )\
3962\
3963 if nFreeLines <= 0 then\
3964 local w,h = _term.getSize()\
3965 _term.setCursorPos( 1, h )\
3966 _term.write( \"Press any key to continue\" )\
3967 os.pullEvent( \"key\" )\
3968 _term.clearLine()\
3969 _term.setCursorPos( 1, h )\
3970 else\
3971 nFreeLines = nFreeLines - 1\
3972 end\
3973 end\
3974 end\
3975end\
3976\
3977function pagedPrint( _sText, _nFreeLines )\
3978 if _nFreeLines ~= nil and type( _nFreeLines ) ~= \"number\" then\
3979 error( \"bad argument #2 (expected number, got \" .. type( _nFreeLines ) .. \")\", 2 )\
3980 end\
3981 -- Setup a redirector\
3982 local oldTerm = term.current()\
3983 local newTerm = {}\
3984 for k,v in pairs( oldTerm ) do\
3985 newTerm[k] = v\
3986 end\
3987 newTerm.scroll = makePagedScroll( oldTerm, _nFreeLines )\
3988 term.redirect( newTerm )\
3989\
3990 -- Print the text\
3991 local result\
3992 local ok, err = pcall( function()\
3993 if _sText ~= nil then\
3994 result = print( _sText )\
3995 else\
3996 result = print()\
3997 end\
3998 end )\
3999\
4000 -- Removed the redirector\
4001 term.redirect( oldTerm )\
4002\
4003 -- Propogate errors\
4004 if not ok then\
4005 error( err, 0 )\
4006 end\
4007 return result\
4008end\
4009\
4010local function tabulateCommon( bPaged, ... )\
4011 local tAll = { ... }\
4012 for k,v in ipairs( tAll ) do\
4013 if type( v ) ~= \"number\" and type( v ) ~= \"table\" then\
4014 error( \"bad argument #\"..k..\" (expected number or table, got \" .. type( v ) .. \")\", 3 )\
4015 end\
4016 end\
4017\
4018 local w,h = term.getSize()\
4019 local nMaxLen = w / 8\
4020 for n, t in ipairs( tAll ) do\
4021 if type(t) == \"table\" then\
4022 for nu, sItem in pairs(t) do\
4023 if type( sItem ) ~= \"string\" then\
4024 error( \"bad argument #\"..n..\".\"..nu..\" (expected string, got \" .. type( sItem ) .. \")\", 3 )\
4025 end\
4026 nMaxLen = math.max( string.len( sItem ) + 1, nMaxLen )\
4027 end\
4028 end\
4029 end\
4030 local nCols = math.floor( w / nMaxLen )\
4031 local nLines = 0\
4032 local function newLine()\
4033 if bPaged and nLines >= (h-3) then\
4034 pagedPrint()\
4035 else\
4036 print()\
4037 end\
4038 nLines = nLines + 1\
4039 end\
4040\
4041 local function drawCols( _t )\
4042 local nCol = 1\
4043 for n, s in ipairs( _t ) do\
4044 if nCol > nCols then\
4045 nCol = 1\
4046 newLine()\
4047 end\
4048\
4049 local cx, cy = term.getCursorPos()\
4050 cx = 1 + ((nCol - 1) * nMaxLen)\
4051 term.setCursorPos( cx, cy )\
4052 term.write( s )\
4053\
4054 nCol = nCol + 1\
4055 end\
4056 print()\
4057 end\
4058 for n, t in ipairs( tAll ) do\
4059 if type(t) == \"table\" then\
4060 if #t > 0 then\
4061 drawCols( t )\
4062 end\
4063 elseif type(t) == \"number\" then\
4064 term.setTextColor( t )\
4065 end\
4066 end\
4067end\
4068\
4069function tabulate( ... )\
4070 tabulateCommon( false, ... )\
4071end\
4072\
4073function pagedTabulate( ... )\
4074 tabulateCommon( true, ... )\
4075end\
4076\
4077local g_tLuaKeywords = {\
4078 [ \"and\" ] = true,\
4079 [ \"break\" ] = true,\
4080 [ \"do\" ] = true,\
4081 [ \"else\" ] = true,\
4082 [ \"elseif\" ] = true,\
4083 [ \"end\" ] = true,\
4084 [ \"false\" ] = true,\
4085 [ \"for\" ] = true,\
4086 [ \"function\" ] = true,\
4087 [ \"if\" ] = true,\
4088 [ \"in\" ] = true,\
4089 [ \"local\" ] = true,\
4090 [ \"nil\" ] = true,\
4091 [ \"not\" ] = true,\
4092 [ \"or\" ] = true,\
4093 [ \"repeat\" ] = true,\
4094 [ \"return\" ] = true,\
4095 [ \"then\" ] = true,\
4096 [ \"true\" ] = true,\
4097 [ \"until\" ] = true,\
4098 [ \"while\" ] = true,\
4099}\
4100\
4101local function serializeImpl( t, tTracking, sIndent )\
4102 local sType = type(t)\
4103 if sType == \"table\" then\
4104 if tTracking[t] ~= nil then\
4105 error( \"Cannot serialize table with recursive entries\", 0 )\
4106 end\
4107 tTracking[t] = true\
4108\
4109 if next(t) == nil then\
4110 -- Empty tables are simple\
4111 return \"{}\"\
4112 else\
4113 -- Other tables take more work\
4114 local sResult = \"{\\n\"\
4115 local sSubIndent = sIndent .. \" \"\
4116 local tSeen = {}\
4117 for k,v in ipairs(t) do\
4118 tSeen[k] = true\
4119 sResult = sResult .. sSubIndent .. serializeImpl( v, tTracking, sSubIndent ) .. \",\\n\"\
4120 end\
4121 for k,v in pairs(t) do\
4122 if not tSeen[k] then\
4123 local sEntry\
4124 if type(k) == \"string\" and not g_tLuaKeywords[k] and string.match( k, \"^[%a_][%a%d_]*$\" ) then\
4125 sEntry = k .. \" = \" .. serializeImpl( v, tTracking, sSubIndent ) .. \",\\n\"\
4126 else\
4127 sEntry = \"[ \" .. serializeImpl( k, tTracking, sSubIndent ) .. \" ] = \" .. serializeImpl( v, tTracking, sSubIndent ) .. \",\\n\"\
4128 end\
4129 sResult = sResult .. sSubIndent .. sEntry\
4130 end\
4131 end\
4132 sResult = sResult .. sIndent .. \"}\"\
4133 return sResult\
4134 end\
4135\
4136 elseif sType == \"string\" then\
4137 return string.format( \"%q\", t )\
4138\
4139 elseif sType == \"number\" or sType == \"boolean\" or sType == \"nil\" then\
4140 return tostring(t)\
4141\
4142 else\
4143 error( \"Cannot serialize type \"..sType, 0 )\
4144\
4145 end\
4146end\
4147\
4148empty_json_array = {}\
4149\
4150local function serializeJSONImpl( t, tTracking, bNBTStyle )\
4151 local sType = type(t)\
4152 if t == empty_json_array then\
4153 return \"[]\"\
4154\
4155 elseif sType == \"table\" then\
4156 if tTracking[t] ~= nil then\
4157 error( \"Cannot serialize table with recursive entries\", 0 )\
4158 end\
4159 tTracking[t] = true\
4160\
4161 if next(t) == nil then\
4162 -- Empty tables are simple\
4163 return \"{}\"\
4164 else\
4165 -- Other tables take more work\
4166 local sObjectResult = \"{\"\
4167 local sArrayResult = \"[\"\
4168 local nObjectSize = 0\
4169 local nArraySize = 0\
4170 for k,v in pairs(t) do\
4171 if type(k) == \"string\" then\
4172 local sEntry\
4173 if bNBTStyle then\
4174 sEntry = tostring(k) .. \":\" .. serializeJSONImpl( v, tTracking, bNBTStyle )\
4175 else\
4176 sEntry = string.format( \"%q\", k ) .. \":\" .. serializeJSONImpl( v, tTracking, bNBTStyle )\
4177 end\
4178 if nObjectSize == 0 then\
4179 sObjectResult = sObjectResult .. sEntry\
4180 else\
4181 sObjectResult = sObjectResult .. \",\" .. sEntry\
4182 end\
4183 nObjectSize = nObjectSize + 1\
4184 end\
4185 end\
4186 for n,v in ipairs(t) do\
4187 local sEntry = serializeJSONImpl( v, tTracking, bNBTStyle )\
4188 if nArraySize == 0 then\
4189 sArrayResult = sArrayResult .. sEntry\
4190 else\
4191 sArrayResult = sArrayResult .. \",\" .. sEntry\
4192 end\
4193 nArraySize = nArraySize + 1\
4194 end\
4195 sObjectResult = sObjectResult .. \"}\"\
4196 sArrayResult = sArrayResult .. \"]\"\
4197 if nObjectSize > 0 or nArraySize == 0 then\
4198 return sObjectResult\
4199 else\
4200 return sArrayResult\
4201 end\
4202 end\
4203\
4204 elseif sType == \"string\" then\
4205 return string.format( \"%q\", t )\
4206\
4207 elseif sType == \"number\" or sType == \"boolean\" then\
4208 return tostring(t)\
4209\
4210 else\
4211 error( \"Cannot serialize type \"..sType, 0 )\
4212\
4213 end\
4214end\
4215\
4216function serialize( t )\
4217 local tTracking = {}\
4218 return serializeImpl( t, tTracking, \"\" )\
4219end\
4220\
4221function unserialize( s )\
4222 if type( s ) ~= \"string\" then\
4223 error( \"bad argument #1 (expected string, got \" .. type( s ) .. \")\", 2 )\
4224 end\
4225 local func = load( \"return \"..s, \"unserialize\", \"t\", {} )\
4226 if func then\
4227 local ok, result = pcall( func )\
4228 if ok then\
4229 return result\
4230 end\
4231 end\
4232 return nil\
4233end\
4234\
4235function serializeJSON( t, bNBTStyle )\
4236 if type( t ) ~= \"table\" and type( t ) ~= \"string\" and type( t ) ~= \"number\" and type( t ) ~= \"boolean\" then\
4237 error( \"bad argument #1 (expected table/string/number/boolean, got \" .. type( t ) .. \")\", 2 )\
4238 end\
4239 if bNBTStyle ~= nil and type( bNBTStyle ) ~= \"boolean\" then\
4240 error( \"bad argument #2 (expected boolean, got \" .. type( bNBTStyle ) .. \")\", 2 )\
4241 end\
4242 local tTracking = {}\
4243 return serializeJSONImpl( t, tTracking, bNBTStyle or false )\
4244end\
4245\
4246function urlEncode( str )\
4247 if type( str ) ~= \"string\" then\
4248 error( \"bad argument #1 (expected string, got \" .. type( str ) .. \")\", 2 )\
4249 end\
4250 if str then\
4251 str = string.gsub(str, \"\\n\", \"\\r\\n\")\
4252 str = string.gsub(str, \"([^A-Za-z0-9 %-%_%.])\", function(c)\
4253 local n = string.byte(c)\
4254 if n < 128 then\
4255 -- ASCII\
4256 return string.format(\"%%%02X\", n)\
4257 else\
4258 -- Non-ASCII (encode as UTF-8)\
4259 return\
4260 string.format(\"%%%02X\", 192 + bit32.band( bit32.arshift(n,6), 31 ) ) ..\
4261 string.format(\"%%%02X\", 128 + bit32.band( n, 63 ) )\
4262 end\
4263 end )\
4264 str = string.gsub(str, \" \", \"+\")\
4265 end\
4266 return str\
4267end\
4268\
4269local tEmpty = {}\
4270function complete( sSearchText, tSearchTable )\
4271 if type( sSearchText ) ~= \"string\" then\
4272 error( \"bad argument #1 (expected string, got \" .. type( sSearchText ) .. \")\", 2 )\
4273 end\
4274 if tSearchTable ~= nil and type( tSearchTable ) ~= \"table\" then\
4275 error( \"bad argument #2 (expected table, got \" .. type( tSearchTable ) .. \")\", 2 )\
4276 end\
4277\
4278 if g_tLuaKeywords[sSearchText] then return tEmpty end\
4279 local nStart = 1\
4280 local nDot = string.find( sSearchText, \".\", nStart, true )\
4281 local tTable = tSearchTable or _ENV\
4282 while nDot do\
4283 local sPart = string.sub( sSearchText, nStart, nDot - 1 )\
4284 local value = tTable[ sPart ]\
4285 if type( value ) == \"table\" then\
4286 tTable = value\
4287 nStart = nDot + 1\
4288 nDot = string.find( sSearchText, \".\", nStart, true )\
4289 else\
4290 return tEmpty\
4291 end\
4292 end\
4293 local nColon = string.find( sSearchText, \":\", nStart, true )\
4294 if nColon then\
4295 local sPart = string.sub( sSearchText, nStart, nColon - 1 )\
4296 local value = tTable[ sPart ]\
4297 if type( value ) == \"table\" then\
4298 tTable = value\
4299 nStart = nColon + 1\
4300 else\
4301 return tEmpty\
4302 end\
4303 end\
4304\
4305 local sPart = string.sub( sSearchText, nStart )\
4306 local nPartLength = string.len( sPart )\
4307\
4308 local tResults = {}\
4309 local tSeen = {}\
4310 while tTable do\
4311 for k,v in pairs( tTable ) do\
4312 if not tSeen[k] and type(k) == \"string\" then\
4313 if string.find( k, sPart, 1, true ) == 1 then\
4314 if not g_tLuaKeywords[k] and string.match( k, \"^[%a_][%a%d_]*$\" ) then\
4315 local sResult = string.sub( k, nPartLength + 1 )\
4316 if nColon then\
4317 if type(v) == \"function\" then\
4318 table.insert( tResults, sResult .. \"(\" )\
4319 elseif type(v) == \"table\" then\
4320 local tMetatable = getmetatable( v )\
4321 if tMetatable and ( type( tMetatable.__call ) == \"function\" or type( tMetatable.__call ) == \"table\" ) then\
4322 table.insert( tResults, sResult .. \"(\" )\
4323 end\
4324 end\
4325 else\
4326 if type(v) == \"function\" then\
4327 sResult = sResult .. \"(\"\
4328 elseif type(v) == \"table\" and next(v) ~= nil then\
4329 sResult = sResult .. \".\"\
4330 end\
4331 table.insert( tResults, sResult )\
4332 end\
4333 end\
4334 end\
4335 end\
4336 tSeen[k] = true\
4337 end\
4338 local tMetatable = getmetatable( tTable )\
4339 if tMetatable and type( tMetatable.__index ) == \"table\" then\
4340 tTable = tMetatable.__index\
4341 else\
4342 tTable = nil\
4343 end\
4344 end\
4345\
4346 table.sort( tResults )\
4347 return tResults\
4348end\
4349\
4350-- GB versions\
4351serialise = serialize\
4352unserialise = unserialize\
4353serialiseJSON = serializeJSON",
4354 [ "help/bundled.txt" ] = "To set bundled outputs:\
4355c = colors.combine( colors.red, colors.blue )\
4356rs.setBundledOutput( \"left\", c )\
4357\
4358c = colors.combine( c, colors.green )\
4359rs.setBundledOutput( \"left\", c )\
4360\
4361c = colors.subtract( c, colors.blue )\
4362rs.setBundledOutput( \"left\", c )\
4363\
4364To get bundled inputs:\
4365c = rs.getBundledInput( \"right\" )\
4366red = colors.test( c, colors.red )\
4367\
4368Type \"help colors\" for the list of wire colors.",
4369 [ "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.\
4370\
4371ex:\
4372\"go forward\" moves the turtle 1 space forward.\
4373\"go forward 3\" moves the turtle 3 spaces forward.\
4374\"go forward 3 up left 2\" moves the turtle 3 spaces forward, 1 spaces up, then left 180 degrees.",
4375 [ "help/monitor.txt" ] = "monitor will connect to an attached Monitor peripheral, and run a program on its display.\
4376Type \"help monitors\" for help using monitors as peripherals in lua programs.\
4377\
4378ex:\
4379\"monitor left hello\" will run the \"hello\" program on the monitor to the left of the computer.\
4380\"monitor top edit foo\" will run the edit program on the top monitor, editing the file \"foo\".",
4381 [ "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.",
4382 [ "help/falling.txt" ] = "\"From Russia with Fun\" comes a fun, new, suspiciously-familiar falling block game for CraftOS. Only on Pocket Computers!",
4383 [ "programs/drive.lua" ] = "local tArgs = { ... }\
4384\
4385-- Get where a directory is mounted\
4386local sPath = shell.dir()\
4387if tArgs[1] ~= nil then\
4388 sPath = shell.resolve( tArgs[1] )\
4389end\
4390\
4391if fs.exists( sPath ) then\
4392 write( fs.getDrive( sPath ) .. \" (\" )\
4393 local nSpace = fs.getFreeSpace( sPath )\
4394 if nSpace >= 1000 * 1000 then\
4395 print( (math.floor( nSpace / (100 * 1000) ) / 10) .. \"MB remaining)\" )\
4396 elseif nSpace >= 1000 then\
4397 print( (math.floor( nSpace / 100 ) / 10) .. \"KB remaining)\" )\
4398 else\
4399 print( nSpace .. \"B remaining)\" )\
4400 end\
4401else\
4402 print( \"No such path\" )\
4403end",
4404 [ "programs/mkdir.lua" ] = "local tArgs = { ... }\
4405if #tArgs < 1 then\
4406 print( \"Usage: mkdir <path>\" )\
4407 return\
4408end\
4409\
4410local sNewDir = shell.resolve( tArgs[1] )\
4411\
4412if fs.exists( sNewDir ) and not fs.isDir(sNewDir) then\
4413 printError( \"Destination exists\" )\
4414 return\
4415end\
4416\
4417fs.makeDir( sNewDir )\
4418",
4419 [ "programs/eject.lua" ] = "\
4420-- Get arguments\
4421local tArgs = { ... }\
4422if #tArgs == 0 then\
4423 print( \"Usage: eject <drive>\" )\
4424 return\
4425end\
4426\
4427local sDrive = tArgs[1]\
4428\
4429-- Check the disk exists\
4430local bPresent = disk.isPresent( sDrive )\
4431if not bPresent then\
4432 print( \"Nothing in \"..sDrive..\" drive\" )\
4433 return\
4434end\
4435\
4436disk.eject( sDrive )",
4437 [ "programs/turtle/turn.lua" ] = "local tArgs = { ... }\
4438if #tArgs < 1 then\
4439 print( \"Usage: turn <direction> <turns>\" )\
4440 return\
4441end\
4442\
4443local tHandlers = {\
4444 [\"lt\"] = turtle.turnLeft,\
4445 [\"left\"] = turtle.turnLeft,\
4446 [\"rt\"] = turtle.turnRight,\
4447 [\"right\"] = turtle.turnRight,\
4448}\
4449\
4450local nArg = 1\
4451while nArg <= #tArgs do\
4452 local sDirection = tArgs[nArg]\
4453 local nDistance = 1\
4454 if nArg < #tArgs then\
4455 local num = tonumber( tArgs[nArg + 1] )\
4456 if num then\
4457 nDistance = num\
4458 nArg = nArg + 1\
4459 end\
4460 end\
4461 nArg = nArg + 1\
4462\
4463 local fnHandler = tHandlers[string.lower(sDirection)]\
4464 if fnHandler then\
4465 for n=1,nDistance do\
4466 fnHandler( nArg )\
4467 end\
4468 else\
4469 print( \"No such direction: \"..sDirection )\
4470 print( \"Try: left, right\" )\
4471 return\
4472 end\
4473end",
4474 [ "help/rename.txt" ] = "rename renames a file or directory.\
4475\
4476ex:\
4477\"rename foo bar\" renames the file \"foo\" to \"bar\".",
4478 [ "apis/colors.lua" ] = "-- Colors\
4479white = 1\
4480orange = 2\
4481magenta = 4\
4482lightBlue = 8\
4483yellow = 16\
4484lime = 32\
4485pink = 64\
4486gray = 128\
4487lightGray = 256\
4488cyan = 512\
4489purple = 1024\
4490blue = 2048\
4491brown = 4096\
4492green = 8192\
4493red = 16384\
4494black = 32768\
4495\
4496function combine( ... )\
4497 local r = 0\
4498 for n,c in ipairs( { ... } ) do\
4499 if type( c ) ~= \"number\" then\
4500 error( \"bad argument #\"..n..\" (expected number, got \" .. type( c ) .. \")\", 2 )\
4501 end\
4502 r = bit32.bor(r,c)\
4503 end\
4504 return r\
4505end\
4506\
4507function subtract( colors, ... )\
4508 if type( colors ) ~= \"number\" then\
4509 error( \"bad argument #1 (expected number, got \" .. type( colors ) .. \")\", 2 )\
4510 end\
4511 local r = colors\
4512 for n,c in ipairs( { ... } ) do\
4513 if type( c ) ~= \"number\" then\
4514 error( \"bad argument #\"..tostring( n+1 )..\" (expected number, got \" .. type( c ) .. \")\", 2 )\
4515 end\
4516 r = bit32.band(r, bit32.bnot(c))\
4517 end\
4518 return r\
4519end\
4520\
4521function test( colors, color )\
4522 if type( colors ) ~= \"number\" then\
4523 error( \"bad argument #1 (expected number, got \" .. type( colors ) .. \")\", 2 )\
4524 end\
4525 if type( color ) ~= \"number\" then\
4526 error( \"bad argument #2 (expected number, got \" .. type( color ) .. \")\", 2 )\
4527 end\
4528 return bit32.band(colors, color) == color\
4529end\
4530\
4531function packRGB( r, g, b )\
4532 if type( r ) ~= \"number\" then\
4533 error( \"bad argument #1 (expected number, got \" .. type( r ) .. \")\", 2 )\
4534 end\
4535 if type( g ) ~= \"number\" then\
4536 error( \"bad argument #2 (expected number, got \" .. type( g ) .. \")\", 2 )\
4537 end\
4538 if type( b ) ~= \"number\" then\
4539 error( \"bad argument #3 (expected number, got \" .. type( b ) .. \")\", 2 )\
4540 end\
4541 return\
4542 bit32.band( r * 255, 0xFF ) * 2^16 +\
4543 bit32.band( g * 255, 0xFF ) * 2^8 +\
4544 bit32.band( b * 255, 0xFF )\
4545end\
4546\
4547function unpackRGB( rgb )\
4548 if type( rgb ) ~= \"number\" then\
4549 error( \"bad argument #1 (expected number, got \" .. type( rgb ) .. \")\", 2 )\
4550 end\
4551 return\
4552 bit32.band( bit32.rshift( rgb, 16 ), 0xFF ) / 255,\
4553 bit32.band( bit32.rshift( rgb, 8 ), 0xFF ) / 255,\
4554 bit32.band( rgb, 0xFF ) / 255\
4555end\
4556\
4557function rgb8( r, g, b )\
4558 if g == nil and b == nil then\
4559 return unpackRGB( r )\
4560 else\
4561 return packRGB( r, g, b )\
4562 end\
4563end",
4564 [ "help/coroutine.txt" ] = "coroutine is a standard Lua5.1 API.\
4565Refer to http://www.lua.org/manual/5.1/ for more information.",
4566 [ "apis/gps.lua" ] = "CHANNEL_GPS = 65534\
4567\
4568local function trilaterate( A, B, C )\
4569 local a2b = B.vPosition - A.vPosition\
4570 local a2c = C.vPosition - A.vPosition\
4571\
4572 if math.abs( a2b:normalize():dot( a2c:normalize() ) ) > 0.999 then\
4573 return nil\
4574 end\
4575\
4576 local d = a2b:length()\
4577 local ex = a2b:normalize( )\
4578 local i = ex:dot( a2c )\
4579 local ey = (a2c - (ex * i)):normalize()\
4580 local j = ey:dot( a2c )\
4581 local ez = ex:cross( ey )\
4582\
4583 local r1 = A.nDistance\
4584 local r2 = B.nDistance\
4585 local r3 = C.nDistance\
4586\
4587 local x = (r1*r1 - r2*r2 + d*d) / (2*d)\
4588 local y = (r1*r1 - r3*r3 - x*x + (x-i)*(x-i) + j*j) / (2*j)\
4589\
4590 local result = A.vPosition + (ex * x) + (ey * y)\
4591\
4592 local zSquared = r1*r1 - x*x - y*y\
4593 if zSquared > 0 then\
4594 local z = math.sqrt( zSquared )\
4595 local result1 = result + (ez * z)\
4596 local result2 = result - (ez * z)\
4597\
4598 local rounded1, rounded2 = result1:round( 0.01 ), result2:round( 0.01 )\
4599 if rounded1.x ~= rounded2.x or rounded1.y ~= rounded2.y or rounded1.z ~= rounded2.z then\
4600 return rounded1, rounded2\
4601 else\
4602 return rounded1\
4603 end\
4604 end\
4605 return result:round( 0.01 )\
4606\
4607end\
4608\
4609local function narrow( p1, p2, fix )\
4610 local dist1 = math.abs( (p1 - fix.vPosition):length() - fix.nDistance )\
4611 local dist2 = math.abs( (p2 - fix.vPosition):length() - fix.nDistance )\
4612\
4613 if math.abs(dist1 - dist2) < 0.01 then\
4614 return p1, p2\
4615 elseif dist1 < dist2 then\
4616 return p1:round( 0.01 )\
4617 else\
4618 return p2:round( 0.01 )\
4619 end\
4620end\
4621\
4622function locate( _nTimeout, _bDebug )\
4623 if _nTimeout ~= nil and type( _nTimeout ) ~= \"number\" then\
4624 error( \"bad argument #1 (expected number, got \" .. type( _nTimeout ) .. \")\", 2 )\
4625 end\
4626 if _bDebug ~= nil and type( _bDebug ) ~= \"boolean\" then\
4627 error( \"bad argument #2 (expected boolean, got \" .. type( _bDebug) .. \")\", 2 )\
4628 end\
4629 -- Let command computers use their magic fourth-wall-breaking special abilities\
4630 if commands then\
4631 return commands.getBlockPosition()\
4632 end\
4633\
4634 -- Find a modem\
4635 local sModemSide = nil\
4636 for n,sSide in ipairs( rs.getSides() ) do\
4637 if peripheral.getType( sSide ) == \"modem\" and peripheral.call( sSide, \"isWireless\" ) then\
4638 sModemSide = sSide\
4639 break\
4640 end\
4641 end\
4642\
4643 if sModemSide == nil then\
4644 if _bDebug then\
4645 print( \"No wireless modem attached\" )\
4646 end\
4647 return nil\
4648 end\
4649\
4650 if _bDebug then\
4651 print( \"Finding position...\" )\
4652 end\
4653\
4654 -- Open a channel\
4655 local modem = peripheral.wrap( sModemSide )\
4656 local bCloseChannel = false\
4657 if not modem.isOpen( os.getComputerID() ) then\
4658 modem.open( os.getComputerID() )\
4659 bCloseChannel = true\
4660 end\
4661\
4662 -- Send a ping to listening GPS hosts\
4663 modem.transmit( CHANNEL_GPS, os.getComputerID(), \"PING\" )\
4664\
4665 -- Wait for the responses\
4666 local tFixes = {}\
4667 local pos1, pos2 = nil, nil\
4668 local timeout = os.startTimer( _nTimeout or 2 )\
4669 while true do\
4670 local e, p1, p2, p3, p4, p5 = os.pullEvent()\
4671 if e == \"modem_message\" then\
4672 -- We received a reply from a modem\
4673 local sSide, sChannel, sReplyChannel, tMessage, nDistance = p1, p2, p3, p4, p5\
4674 if sSide == sModemSide and sChannel == os.getComputerID() and sReplyChannel == CHANNEL_GPS and nDistance then\
4675 -- Received the correct message from the correct modem: use it to determine position\
4676 if type(tMessage) == \"table\" and #tMessage == 3 and tonumber(tMessage[1]) and tonumber(tMessage[2]) and tonumber(tMessage[3]) then\
4677 local tFix = { vPosition = vector.new( tMessage[1], tMessage[2], tMessage[3] ), nDistance = nDistance }\
4678 if _bDebug then\
4679 print( tFix.nDistance..\" metres from \"..tostring( tFix.vPosition ) )\
4680 end\
4681 if tFix.nDistance == 0 then\
4682 pos1, pos2 = tFix.vPosition, nil\
4683 else\
4684 table.insert( tFixes, tFix )\
4685 if #tFixes >= 3 then\
4686 if not pos1 then\
4687 pos1, pos2 = trilaterate( tFixes[1], tFixes[2], tFixes[#tFixes] )\
4688 else\
4689 pos1, pos2 = narrow( pos1, pos2, tFixes[#tFixes] )\
4690 end\
4691 end\
4692 end\
4693 if pos1 and not pos2 then\
4694 break\
4695 end\
4696 end\
4697 end\
4698\
4699 elseif e == \"timer\" then\
4700 -- We received a timeout\
4701 local timer = p1\
4702 if timer == timeout then\
4703 break\
4704 end\
4705\
4706 end\
4707 end\
4708\
4709 -- Close the channel, if we opened one\
4710 if bCloseChannel then\
4711 modem.close( os.getComputerID() )\
4712 end\
4713\
4714 -- Return the response\
4715 if pos1 and pos2 then\
4716 if _bDebug then\
4717 print( \"Ambiguous position\" )\
4718 print( \"Could be \"..pos1.x..\",\"..pos1.y..\",\"..pos1.z..\" or \"..pos2.x..\",\"..pos2.y..\",\"..pos2.z )\
4719 end\
4720 return nil\
4721 elseif pos1 then\
4722 if _bDebug then\
4723 print( \"Position is \"..pos1.x..\",\"..pos1.y..\",\"..pos1.z )\
4724 end\
4725 return pos1.x, pos1.y, pos1.z\
4726 else\
4727 if _bDebug then\
4728 print( \"Could not determine position\" )\
4729 end\
4730 return nil\
4731 end\
4732end",
4733 [ "help/exit.txt" ] = "exit will exit the current shell.",
4734 [ "programs/edit.lua" ] = "-- Get file to edit\
4735local tArgs = { ... }\
4736if #tArgs == 0 then\
4737 print( \"Usage: edit <path>\" )\
4738 return\
4739end\
4740\
4741-- Error checking\
4742local sPath = shell.resolve( tArgs[1] )\
4743local bReadOnly = fs.isReadOnly( sPath )\
4744if fs.exists( sPath ) and fs.isDir( sPath ) then\
4745 print( \"Cannot edit a directory.\" )\
4746 return\
4747end\
4748\
4749-- Create .lua files by default\
4750if not fs.exists( sPath ) and not string.find( sPath, \"%.\" ) then\
4751 local sExtension = settings.get(\"edit.default_extension\", \"\" )\
4752 if sExtension ~= \"\" and type( sExtension ) == \"string\" then\
4753 sPath = sPath .. \".\" .. sExtension\
4754 end\
4755end\
4756\
4757local x,y = 1,1\
4758local w,h = term.getSize()\
4759local scrollX, scrollY = 0,0\
4760\
4761local tLines = {}\
4762local bRunning = true\
4763\
4764-- Colours\
4765local highlightColour, keywordColour, commentColour, textColour, bgColour, stringColour\
4766if term.isColour() then\
4767 bgColour = colours.black\
4768 textColour = colours.white\
4769 highlightColour = colours.yellow\
4770 keywordColour = colours.yellow\
4771 commentColour = colours.green\
4772 stringColour = colours.red\
4773else\
4774 bgColour = colours.black\
4775 textColour = colours.white\
4776 highlightColour = colours.white\
4777 keywordColour = colours.white\
4778 commentColour = colours.white\
4779 stringColour = colours.white\
4780end\
4781\
4782-- Menus\
4783local bMenu = false\
4784local nMenuItem = 1\
4785local tMenuItems = {}\
4786if not bReadOnly then\
4787 table.insert( tMenuItems, \"Save\" )\
4788end\
4789if shell.openTab then\
4790 table.insert( tMenuItems, \"Run\" )\
4791end\
4792if peripheral.find( \"printer\" ) then\
4793 table.insert( tMenuItems, \"Print\" )\
4794end\
4795table.insert( tMenuItems, \"Exit\" )\
4796\
4797local sStatus = \"Press Ctrl to access menu\"\
4798if string.len( sStatus ) > w - 5 then\
4799 sStatus = \"Press Ctrl for menu\"\
4800end\
4801\
4802local function load( _sPath )\
4803 tLines = {}\
4804 if fs.exists( _sPath ) then\
4805 local file = io.open( _sPath, \"r\" )\
4806 local sLine = file:read()\
4807 while sLine do\
4808 table.insert( tLines, sLine )\
4809 sLine = file:read()\
4810 end\
4811 file:close()\
4812 end\
4813\
4814 if #tLines == 0 then\
4815 table.insert( tLines, \"\" )\
4816 end\
4817end\
4818\
4819local function save( _sPath )\
4820 -- Create intervening folder\
4821 local sDir = _sPath:sub(1, _sPath:len() - fs.getName(_sPath):len() )\
4822 if not fs.exists( sDir ) then\
4823 fs.makeDir( sDir )\
4824 end\
4825\
4826 -- Save\
4827 local file, fileerr\
4828 local function innerSave()\
4829 file, fileerr = fs.open( _sPath, \"w\" )\
4830 if file then\
4831 for n, sLine in ipairs( tLines ) do\
4832 file.write( sLine .. \"\\n\" )\
4833 end\
4834 else\
4835 error( \"Failed to open \".._sPath )\
4836 end\
4837 end\
4838\
4839 local ok, err = pcall( innerSave )\
4840 if file then\
4841 file.close()\
4842 end\
4843 return ok, err, fileerr\
4844end\
4845\
4846local tKeywords = {\
4847 [\"and\"] = true,\
4848 [\"break\"] = true,\
4849 [\"do\"] = true,\
4850 [\"else\"] = true,\
4851 [\"elseif\"] = true,\
4852 [\"end\"] = true,\
4853 [\"false\"] = true,\
4854 [\"for\"] = true,\
4855 [\"function\"] = true,\
4856 [\"if\"] = true,\
4857 [\"in\"] = true,\
4858 [\"local\"] = true,\
4859 [\"nil\"] = true,\
4860 [\"not\"] = true,\
4861 [\"or\"] = true,\
4862 [\"repeat\"] = true,\
4863 [\"return\"] = true,\
4864 [\"then\"] = true,\
4865 [\"true\"] = true,\
4866 [\"until\"]= true,\
4867 [\"while\"] = true,\
4868}\
4869\
4870local function tryWrite( sLine, regex, colour )\
4871 local match = string.match( sLine, regex )\
4872 if match then\
4873 if type(colour) == \"number\" then\
4874 term.setTextColour( colour )\
4875 else\
4876 term.setTextColour( colour(match) )\
4877 end\
4878 term.write( match )\
4879 term.setTextColour( textColour )\
4880 return string.sub( sLine, string.len(match) + 1 )\
4881 end\
4882 return nil\
4883end\
4884\
4885local function writeHighlighted( sLine )\
4886 while string.len(sLine) > 0 do\
4887 sLine =\
4888 tryWrite( sLine, \"^%-%-%[%[.-%]%]\", commentColour ) or\
4889 tryWrite( sLine, \"^%-%-.*\", commentColour ) or\
4890 tryWrite( sLine, \"^\\\"\\\"\", stringColour ) or\
4891 tryWrite( sLine, \"^\\\".-[^\\\\]\\\"\", stringColour ) or\
4892 tryWrite( sLine, \"^\\'\\'\", stringColour ) or\
4893 tryWrite( sLine, \"^\\'.-[^\\\\]\\'\", stringColour ) or\
4894 tryWrite( sLine, \"^%[%[.-%]%]\", stringColour ) or\
4895 tryWrite( sLine, \"^[%w_]+\", function( match )\
4896 if tKeywords[ match ] then\
4897 return keywordColour\
4898 end\
4899 return textColour\
4900 end ) or\
4901 tryWrite( sLine, \"^[^%w_]\", textColour )\
4902 end\
4903end\
4904\
4905local tCompletions\
4906local nCompletion\
4907\
4908local tCompleteEnv = _ENV\
4909local function complete( sLine )\
4910 if settings.get( \"edit.autocomplete\" ) then\
4911 local nStartPos = string.find( sLine, \"[a-zA-Z0-9_%.:]+$\" )\
4912 if nStartPos then\
4913 sLine = string.sub( sLine, nStartPos )\
4914 end\
4915 if #sLine > 0 then\
4916 return textutils.complete( sLine, tCompleteEnv )\
4917 end\
4918 end\
4919 return nil\
4920end\
4921\
4922local function recomplete()\
4923 local sLine = tLines[y]\
4924 if not bMenu and not bReadOnly and x == string.len(sLine) + 1 then\
4925 tCompletions = complete( sLine )\
4926 if tCompletions and #tCompletions > 0 then\
4927 nCompletion = 1\
4928 else\
4929 nCompletion = nil\
4930 end\
4931 else\
4932 tCompletions = nil\
4933 nCompletion = nil\
4934 end\
4935end\
4936\
4937local function writeCompletion( sLine )\
4938 if nCompletion then\
4939 local sCompletion = tCompletions[ nCompletion ]\
4940 term.setTextColor( colours.white )\
4941 term.setBackgroundColor( colours.grey )\
4942 term.write( sCompletion )\
4943 term.setTextColor( textColour )\
4944 term.setBackgroundColor( bgColour )\
4945 end\
4946end\
4947\
4948local function redrawText()\
4949 local cursorX, cursorY = x, y\
4950 for y=1,h-1 do\
4951 term.setCursorPos( 1 - scrollX, y )\
4952 term.clearLine()\
4953\
4954 local sLine = tLines[ y + scrollY ]\
4955 if sLine ~= nil then\
4956 writeHighlighted( sLine )\
4957 if cursorY == y and cursorX == #sLine + 1 then\
4958 writeCompletion()\
4959 end\
4960 end\
4961 end\
4962 term.setCursorPos( x - scrollX, y - scrollY )\
4963end\
4964\
4965local function redrawLine(_nY)\
4966 local sLine = tLines[_nY]\
4967 if sLine then\
4968 term.setCursorPos( 1 - scrollX, _nY - scrollY )\
4969 term.clearLine()\
4970 writeHighlighted( sLine )\
4971 if _nY == y and x == #sLine + 1 then\
4972 writeCompletion()\
4973 end\
4974 term.setCursorPos( x - scrollX, _nY - scrollY )\
4975 end\
4976end\
4977\
4978local function redrawMenu()\
4979 -- Clear line\
4980 term.setCursorPos( 1, h )\
4981 term.clearLine()\
4982\
4983 -- Draw line numbers\
4984 term.setCursorPos( w - string.len( \"Ln \"..y ) + 1, h )\
4985 term.setTextColour( highlightColour )\
4986 term.write( \"Ln \" )\
4987 term.setTextColour( textColour )\
4988 term.write( y )\
4989\
4990 term.setCursorPos( 1, h )\
4991 if bMenu then\
4992 -- Draw menu\
4993 term.setTextColour( textColour )\
4994 for nItem,sItem in pairs( tMenuItems ) do\
4995 if nItem == nMenuItem then\
4996 term.setTextColour( highlightColour )\
4997 term.write( \"[\" )\
4998 term.setTextColour( textColour )\
4999 term.write( sItem )\
5000 term.setTextColour( highlightColour )\
5001 term.write( \"]\" )\
5002 term.setTextColour( textColour )\
5003 else\
5004 term.write( \" \"..sItem..\" \" )\
5005 end\
5006 end\
5007 else\
5008 -- Draw status\
5009 term.setTextColour( highlightColour )\
5010 term.write( sStatus )\
5011 term.setTextColour( textColour )\
5012 end\
5013\
5014 -- Reset cursor\
5015 term.setCursorPos( x - scrollX, y - scrollY )\
5016end\
5017\
5018local tMenuFuncs = {\
5019 Save = function()\
5020 if bReadOnly then\
5021 sStatus = \"Access denied\"\
5022 else\
5023 local ok, err, fileerr = save( sPath )\
5024 if ok then\
5025 sStatus=\"Saved to \"..sPath\
5026 else\
5027 if fileerr then\
5028 sStatus=\"Error saving to \"..fileerr\
5029 else\
5030 sStatus=\"Error saving to \"..sPath\
5031 end\
5032 end\
5033 end\
5034 redrawMenu()\
5035 end,\
5036 Print = function()\
5037 local printer = peripheral.find( \"printer\" )\
5038 if not printer then\
5039 sStatus = \"No printer attached\"\
5040 return\
5041 end\
5042\
5043 local nPage = 0\
5044 local sName = fs.getName( sPath )\
5045 if printer.getInkLevel() < 1 then\
5046 sStatus = \"Printer out of ink\"\
5047 return\
5048 elseif printer.getPaperLevel() < 1 then\
5049 sStatus = \"Printer out of paper\"\
5050 return\
5051 end\
5052\
5053 local screenTerminal = term.current()\
5054 local printerTerminal = {\
5055 getCursorPos = printer.getCursorPos,\
5056 setCursorPos = printer.setCursorPos,\
5057 getSize = printer.getPageSize,\
5058 write = printer.write,\
5059 }\
5060 printerTerminal.scroll = function()\
5061 if nPage == 1 then\
5062 printer.setPageTitle( sName..\" (page \"..nPage..\")\" )\
5063 end\
5064\
5065 while not printer.newPage() do\
5066 if printer.getInkLevel() < 1 then\
5067 sStatus = \"Printer out of ink, please refill\"\
5068 elseif printer.getPaperLevel() < 1 then\
5069 sStatus = \"Printer out of paper, please refill\"\
5070 else\
5071 sStatus = \"Printer output tray full, please empty\"\
5072 end\
5073\
5074 term.redirect( screenTerminal )\
5075 redrawMenu()\
5076 term.redirect( printerTerminal )\
5077\
5078 local timer = os.startTimer(0.5)\
5079 sleep(0.5)\
5080 end\
5081\
5082 nPage = nPage + 1\
5083 if nPage == 1 then\
5084 printer.setPageTitle( sName )\
5085 else\
5086 printer.setPageTitle( sName..\" (page \"..nPage..\")\" )\
5087 end\
5088 end\
5089\
5090 bMenu = false\
5091 term.redirect( printerTerminal )\
5092 local ok, error = pcall( function()\
5093 term.scroll()\
5094 for n, sLine in ipairs( tLines ) do\
5095 print( sLine )\
5096 end\
5097 end )\
5098 term.redirect( screenTerminal )\
5099 if not ok then\
5100 print( error )\
5101 end\
5102\
5103 while not printer.endPage() do\
5104 sStatus = \"Printer output tray full, please empty\"\
5105 redrawMenu()\
5106 sleep( 0.5 )\
5107 end\
5108 bMenu = true\
5109\
5110 if nPage > 1 then\
5111 sStatus = \"Printed \"..nPage..\" Pages\"\
5112 else\
5113 sStatus = \"Printed 1 Page\"\
5114 end\
5115 redrawMenu()\
5116 end,\
5117 Exit = function()\
5118 bRunning = false\
5119 end,\
5120 Run = function()\
5121 local sTempPath = \"/.temp\"\
5122 local ok, err = save( sTempPath )\
5123 if ok then\
5124 local nTask = shell.openTab( sTempPath )\
5125 if nTask then\
5126 shell.switchTab( nTask )\
5127 else\
5128 sStatus=\"Error starting Task\"\
5129 end\
5130 fs.delete( sTempPath )\
5131 else\
5132 sStatus=\"Error saving to \"..sTempPath\
5133 end\
5134 redrawMenu()\
5135 end\
5136}\
5137\
5138local function doMenuItem( _n )\
5139 tMenuFuncs[tMenuItems[_n]]()\
5140 if bMenu then\
5141 bMenu = false\
5142 term.setCursorBlink( true )\
5143 end\
5144 redrawMenu()\
5145end\
5146\
5147local function setCursor( newX, newY )\
5148 local oldX, oldY = x, y\
5149 x, y = newX, newY\
5150 local screenX = x - scrollX\
5151 local screenY = y - scrollY\
5152\
5153 local bRedraw = false\
5154 if screenX < 1 then\
5155 scrollX = x - 1\
5156 screenX = 1\
5157 bRedraw = true\
5158 elseif screenX > w then\
5159 scrollX = x - w\
5160 screenX = w\
5161 bRedraw = true\
5162 end\
5163\
5164 if screenY < 1 then\
5165 scrollY = y - 1\
5166 screenY = 1\
5167 bRedraw = true\
5168 elseif screenY > h-1 then\
5169 scrollY = y - (h-1)\
5170 screenY = h-1\
5171 bRedraw = true\
5172 end\
5173\
5174 recomplete()\
5175 if bRedraw then\
5176 redrawText()\
5177 elseif y ~= oldY then\
5178 redrawLine( oldY )\
5179 redrawLine( y )\
5180 else\
5181 redrawLine( y )\
5182 end\
5183 term.setCursorPos( screenX, screenY )\
5184\
5185 redrawMenu()\
5186end\
5187\
5188-- Actual program functionality begins\
5189load(sPath)\
5190\
5191term.setBackgroundColour( bgColour )\
5192term.clear()\
5193term.setCursorPos(x,y)\
5194term.setCursorBlink( true )\
5195\
5196recomplete()\
5197redrawText()\
5198redrawMenu()\
5199\
5200local function acceptCompletion()\
5201 if nCompletion then\
5202 -- Append the completion\
5203 local sCompletion = tCompletions[ nCompletion ]\
5204 tLines[y] = tLines[y] .. sCompletion\
5205 setCursor( x + string.len( sCompletion ), y )\
5206 end\
5207end\
5208\
5209-- Handle input\
5210while bRunning do\
5211 local sEvent, param, param2, param3 = os.pullEvent()\
5212 if sEvent == \"key\" then\
5213 local oldX, oldY = x, y\
5214 if param == keys.up then\
5215 -- Up\
5216 if not bMenu then\
5217 if nCompletion then\
5218 -- Cycle completions\
5219 nCompletion = nCompletion - 1\
5220 if nCompletion < 1 then\
5221 nCompletion = #tCompletions\
5222 end\
5223 redrawLine(y)\
5224\
5225 elseif y > 1 then\
5226 -- Move cursor up\
5227 setCursor(\
5228 math.min( x, string.len( tLines[y - 1] ) + 1 ),\
5229 y - 1\
5230 )\
5231 end\
5232 end\
5233\
5234 elseif param == keys.down then\
5235 -- Down\
5236 if not bMenu then\
5237 -- Move cursor down\
5238 if nCompletion then\
5239 -- Cycle completions\
5240 nCompletion = nCompletion + 1\
5241 if nCompletion > #tCompletions then\
5242 nCompletion = 1\
5243 end\
5244 redrawLine(y)\
5245\
5246 elseif y < #tLines then\
5247 -- Move cursor down\
5248 setCursor(\
5249 math.min( x, string.len( tLines[y + 1] ) + 1 ),\
5250 y + 1\
5251 )\
5252 end\
5253 end\
5254\
5255 elseif param == keys.tab then\
5256 -- Tab\
5257 if not bMenu and not bReadOnly then\
5258 if nCompletion and x == string.len(tLines[y]) + 1 then\
5259 -- Accept autocomplete\
5260 acceptCompletion()\
5261 else\
5262 -- Indent line\
5263 local sLine = tLines[y]\
5264 tLines[y] = string.sub(sLine,1,x-1) .. \" \" .. string.sub(sLine,x)\
5265 setCursor( x + 4, y )\
5266 end\
5267 end\
5268\
5269 elseif param == keys.pageUp then\
5270 -- Page Up\
5271 if not bMenu then\
5272 -- Move up a page\
5273 local newY\
5274 if y - (h - 1) >= 1 then\
5275 newY = y - (h - 1)\
5276 else\
5277 newY = 1\
5278 end\
5279 setCursor(\
5280 math.min( x, string.len( tLines[newY] ) + 1 ),\
5281 newY\
5282 )\
5283 end\
5284\
5285 elseif param == keys.pageDown then\
5286 -- Page Down\
5287 if not bMenu then\
5288 -- Move down a page\
5289 local newY\
5290 if y + (h - 1) <= #tLines then\
5291 newY = y + (h - 1)\
5292 else\
5293 newY = #tLines\
5294 end\
5295 local newX = math.min( x, string.len( tLines[newY] ) + 1 )\
5296 setCursor( newX, newY )\
5297 end\
5298\
5299 elseif param == keys.home then\
5300 -- Home\
5301 if not bMenu then\
5302 -- Move cursor to the beginning\
5303 if x > 1 then\
5304 setCursor(1,y)\
5305 end\
5306 end\
5307\
5308 elseif param == keys[\"end\"] then\
5309 -- End\
5310 if not bMenu then\
5311 -- Move cursor to the end\
5312 local nLimit = string.len( tLines[y] ) + 1\
5313 if x < nLimit then\
5314 setCursor( nLimit, y )\
5315 end\
5316 end\
5317\
5318 elseif param == keys.left then\
5319 -- Left\
5320 if not bMenu then\
5321 if x > 1 then\
5322 -- Move cursor left\
5323 setCursor( x - 1, y )\
5324 elseif x==1 and y>1 then\
5325 setCursor( string.len( tLines[y-1] ) + 1, y - 1 )\
5326 end\
5327 else\
5328 -- Move menu left\
5329 nMenuItem = nMenuItem - 1\
5330 if nMenuItem < 1 then\
5331 nMenuItem = #tMenuItems\
5332 end\
5333 redrawMenu()\
5334 end\
5335\
5336 elseif param == keys.right then\
5337 -- Right\
5338 if not bMenu then\
5339 local nLimit = string.len( tLines[y] ) + 1\
5340 if x < nLimit then\
5341 -- Move cursor right\
5342 setCursor( x + 1, y )\
5343 elseif nCompletion and x == string.len(tLines[y]) + 1 then\
5344 -- Accept autocomplete\
5345 acceptCompletion()\
5346 elseif x==nLimit and y<#tLines then\
5347 -- Go to next line\
5348 setCursor( 1, y + 1 )\
5349 end\
5350 else\
5351 -- Move menu right\
5352 nMenuItem = nMenuItem + 1\
5353 if nMenuItem > #tMenuItems then\
5354 nMenuItem = 1\
5355 end\
5356 redrawMenu()\
5357 end\
5358\
5359 elseif param == keys.delete then\
5360 -- Delete\
5361 if not bMenu and not bReadOnly then\
5362 local nLimit = string.len( tLines[y] ) + 1\
5363 if x < nLimit then\
5364 local sLine = tLines[y]\
5365 tLines[y] = string.sub(sLine,1,x-1) .. string.sub(sLine,x+1)\
5366 recomplete()\
5367 redrawLine(y)\
5368 elseif y<#tLines then\
5369 tLines[y] = tLines[y] .. tLines[y+1]\
5370 table.remove( tLines, y+1 )\
5371 recomplete()\
5372 redrawText()\
5373 end\
5374 end\
5375\
5376 elseif param == keys.backspace then\
5377 -- Backspace\
5378 if not bMenu and not bReadOnly then\
5379 if x > 1 then\
5380 -- Remove character\
5381 local sLine = tLines[y]\
5382 if x > 4 and string.sub(sLine,x-4,x-1) == \" \" and not string.sub(sLine, 1, x - 1):find(\"%S\") then\
5383 tLines[y] = string.sub(sLine,1,x-5) .. string.sub(sLine,x)\
5384 setCursor( x - 4, y )\
5385 else\
5386 tLines[y] = string.sub(sLine,1,x-2) .. string.sub(sLine,x)\
5387 setCursor( x - 1, y )\
5388 end\
5389 elseif y > 1 then\
5390 -- Remove newline\
5391 local sPrevLen = string.len( tLines[y-1] )\
5392 tLines[y-1] = tLines[y-1] .. tLines[y]\
5393 table.remove( tLines, y )\
5394 setCursor( sPrevLen + 1, y - 1 )\
5395 redrawText()\
5396 end\
5397 end\
5398\
5399 elseif param == keys.enter then\
5400 -- Enter\
5401 if not bMenu and not bReadOnly then\
5402 -- Newline\
5403 local sLine = tLines[y]\
5404 local _,spaces=string.find(sLine,\"^[ ]+\")\
5405 if not spaces then\
5406 spaces=0\
5407 end\
5408 tLines[y] = string.sub(sLine,1,x-1)\
5409 table.insert( tLines, y+1, string.rep(' ',spaces)..string.sub(sLine,x) )\
5410 setCursor( spaces + 1, y + 1 )\
5411 redrawText()\
5412\
5413 elseif bMenu then\
5414 -- Menu selection\
5415 doMenuItem( nMenuItem )\
5416\
5417 end\
5418\
5419 elseif param == keys.leftCtrl or param == keys.rightCtrl or param == keys.rightAlt then\
5420 -- Menu toggle\
5421 bMenu = not bMenu\
5422 if bMenu then\
5423 term.setCursorBlink( false )\
5424 else\
5425 term.setCursorBlink( true )\
5426 end\
5427 redrawMenu()\
5428\
5429 end\
5430\
5431 elseif sEvent == \"char\" then\
5432 if not bMenu and not bReadOnly then\
5433 -- Input text\
5434 local sLine = tLines[y]\
5435 tLines[y] = string.sub(sLine,1,x-1) .. param .. string.sub(sLine,x)\
5436 setCursor( x + 1, y )\
5437\
5438 elseif bMenu then\
5439 -- Select menu items\
5440 for n,sMenuItem in ipairs( tMenuItems ) do\
5441 if string.lower(string.sub(sMenuItem,1,1)) == string.lower(param) then\
5442 doMenuItem( n )\
5443 break\
5444 end\
5445 end\
5446 end\
5447\
5448 elseif sEvent == \"paste\" then\
5449 if not bReadOnly then\
5450 -- Close menu if open\
5451 if bMenu then\
5452 bMenu = false\
5453 term.setCursorBlink( true )\
5454 redrawMenu()\
5455 end\
5456 -- Input text\
5457 local sLine = tLines[y]\
5458 tLines[y] = string.sub(sLine,1,x-1) .. param .. string.sub(sLine,x)\
5459 setCursor( x + string.len( param ), y )\
5460 end\
5461\
5462 elseif sEvent == \"mouse_click\" then\
5463 if not bMenu then\
5464 if param == 1 then\
5465 -- Left click\
5466 local cx,cy = param2, param3\
5467 if cy < h then\
5468 local newY = math.min( math.max( scrollY + cy, 1 ), #tLines )\
5469 local newX = math.min( math.max( scrollX + cx, 1 ), string.len( tLines[newY] ) + 1 )\
5470 setCursor( newX, newY )\
5471 end\
5472 end\
5473 end\
5474\
5475 elseif sEvent == \"mouse_scroll\" then\
5476 if not bMenu then\
5477 if param == -1 then\
5478 -- Scroll up\
5479 if scrollY > 0 then\
5480 -- Move cursor up\
5481 scrollY = scrollY - 1\
5482 redrawText()\
5483 end\
5484\
5485 elseif param == 1 then\
5486 -- Scroll down\
5487 local nMaxScroll = #tLines - (h-1)\
5488 if scrollY < nMaxScroll then\
5489 -- Move cursor down\
5490 scrollY = scrollY + 1\
5491 redrawText()\
5492 end\
5493\
5494 end\
5495 end\
5496\
5497 elseif sEvent == \"term_resize\" then\
5498 w,h = term.getSize()\
5499 setCursor( x, y )\
5500 redrawMenu()\
5501 redrawText()\
5502\
5503 end\
5504end\
5505\
5506-- Cleanup\
5507term.clear()\
5508term.setCursorBlink( false )\
5509term.setCursorPos( 1, 1 )",
5510 [ "help/mkdir.txt" ] = "mkdir creates a directory in the current location.\
5511\
5512ex:\
5513\"mkdir foo\" creates a directory named \"foo\".\
5514\"mkdir ../foo\" creates a directory named \"foo\" in the directory above the current directory.",
5515 [ "apis/peripheral.lua" ] = "local native = peripheral\
5516\
5517function getNames()\
5518 local tResults = {}\
5519 for n,sSide in ipairs( rs.getSides() ) do\
5520 if native.isPresent( sSide ) then\
5521 table.insert( tResults, sSide )\
5522 if native.getType( sSide ) == \"modem\" and not native.call( sSide, \"isWireless\" ) then\
5523 local tRemote = native.call( sSide, \"getNamesRemote\" )\
5524 for n,sName in ipairs( tRemote ) do\
5525 table.insert( tResults, sName )\
5526 end\
5527 end\
5528 end\
5529 end\
5530 return tResults\
5531end\
5532\
5533function isPresent( _sSide )\
5534 if type( _sSide ) ~= \"string\" then\
5535 error( \"bad argument #1 (expected string, got \" .. type( _sSide ) .. \")\", 2 )\
5536 end\
5537 if native.isPresent( _sSide ) then\
5538 return true\
5539 end\
5540 for n,sSide in ipairs( rs.getSides() ) do\
5541 if native.getType( sSide ) == \"modem\" and not native.call( sSide, \"isWireless\" ) then\
5542 if native.call( sSide, \"isPresentRemote\", _sSide ) then\
5543 return true\
5544 end\
5545 end\
5546 end\
5547 return false\
5548end\
5549\
5550function getType( _sSide )\
5551 if type( _sSide ) ~= \"string\" then\
5552 error( \"bad argument #1 (expected string, got \" .. type( _sSide ) .. \")\", 2 )\
5553 end\
5554 if native.isPresent( _sSide ) then\
5555 return native.getType( _sSide )\
5556 end\
5557 for n,sSide in ipairs( rs.getSides() ) do\
5558 if native.getType( sSide ) == \"modem\" and not native.call( sSide, \"isWireless\" ) then\
5559 if native.call( sSide, \"isPresentRemote\", _sSide ) then\
5560 return native.call( sSide, \"getTypeRemote\", _sSide )\
5561 end\
5562 end\
5563 end\
5564 return nil\
5565end\
5566\
5567function getMethods( _sSide )\
5568 if type( _sSide ) ~= \"string\" then\
5569 error( \"bad argument #1 (expected string, got \" .. type( _sSide ) .. \")\", 2 )\
5570 end\
5571 if native.isPresent( _sSide ) then\
5572 return native.getMethods( _sSide )\
5573 end\
5574 for n,sSide in ipairs( rs.getSides() ) do\
5575 if native.getType( sSide ) == \"modem\" and not native.call( sSide, \"isWireless\" ) then\
5576 if native.call( sSide, \"isPresentRemote\", _sSide ) then\
5577 return native.call( sSide, \"getMethodsRemote\", _sSide )\
5578 end\
5579 end\
5580 end\
5581 return nil\
5582end\
5583\
5584function call( _sSide, _sMethod, ... )\
5585 if type( _sSide ) ~= \"string\" then\
5586 error( \"bad argument #1 (expected string, got \" .. type( _sSide ) .. \")\", 2 )\
5587 end\
5588 if type( _sSide ) ~= \"string\" then\
5589 error( \"bad argument #2 (expected string, got \" .. type( _sMethod ) .. \")\", 2 )\
5590 end\
5591 if native.isPresent( _sSide ) then\
5592 return native.call( _sSide, _sMethod, ... )\
5593 end\
5594 for n,sSide in ipairs( rs.getSides() ) do\
5595 if native.getType( sSide ) == \"modem\" and not native.call( sSide, \"isWireless\" ) then\
5596 if native.call( sSide, \"isPresentRemote\", _sSide ) then\
5597 return native.call( sSide, \"callRemote\", _sSide, _sMethod, ... )\
5598 end\
5599 end\
5600 end\
5601 return nil\
5602end\
5603\
5604function wrap( _sSide )\
5605 if type( _sSide ) ~= \"string\" then\
5606 error( \"bad argument #1 (expected string, got \" .. type( _sSide ) .. \")\", 2 )\
5607 end\
5608 if peripheral.isPresent( _sSide ) then\
5609 local tMethods = peripheral.getMethods( _sSide )\
5610 local tResult = {}\
5611 for n,sMethod in ipairs( tMethods ) do\
5612 tResult[sMethod] = function( ... )\
5613 return peripheral.call( _sSide, sMethod, ... )\
5614 end\
5615 end\
5616 return tResult\
5617 end\
5618 return nil\
5619end\
5620\
5621function find( sType, fnFilter )\
5622 if type( sType ) ~= \"string\" then\
5623 error( \"bad argument #1 (expected string, got \" .. type( sType ) .. \")\", 2 )\
5624 end\
5625 if fnFilter ~= nil and type( fnFilter ) ~= \"function\" then\
5626 error( \"bad argument #2 (expected function, got \" .. type( fnFilter ) .. \")\", 2 )\
5627 end\
5628 local tResults = {}\
5629 for n,sName in ipairs( peripheral.getNames() ) do\
5630 if peripheral.getType( sName ) == sType then\
5631 local wrapped = peripheral.wrap( sName )\
5632 if fnFilter == nil or fnFilter( sName, wrapped ) then\
5633 table.insert( tResults, wrapped )\
5634 end\
5635 end\
5636 end\
5637 return table.unpack( tResults )\
5638end",
5639 [ "help/programming.txt" ] = "To learn the lua programming language, visit http://lua-users.org/wiki/TutorialDirectory.\
5640\
5641To experiment with lua in CraftOS, run the \"lua\" program and start typing code.\
5642To 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.\
5643\
5644To terminate a program stuck in a loop, hold Ctrl+T for 1 second.\
5645To quickly shutdown a computer, hold Ctrl+S for 1 second.\
5646To quickly reboot a computer, hold Ctrl+R for 1 second.\
5647\
5648To learn about the programming APIs availiable, type \"apis\" or \"help apis\".\
5649If you get stuck, visit the forums at http://www.computercraft.info/ for advice and tutorials.",
5650 [ "help/fg.txt" ] = "fg is a program for Advanced Computers which opens a new tab in the foreground.\
5651\
5652ex:\
5653\"fg\" will open a foreground tab running the shell\
5654\"fg worm\" will open a foreground tab running the \"worm\" program",
5655 [ "apis/colours.lua" ] = "-- Colours (for lovers of british spelling)\
5656local colours = _ENV\
5657for k,v in pairs(colors) do\
5658 colours[k] = v\
5659end\
5660\
5661colours.grey = colors.gray\
5662colours.gray = nil\
5663\
5664colours.lightGrey = colors.lightGray\
5665colours.lightGray = nil",
5666 [ "apis/turtle/turtle.lua" ] = "\
5667if not turtle then\
5668 error( \"Cannot load turtle API on computer\", 2 )\
5669end\
5670native = turtle.native or turtle\
5671\
5672local function addCraftMethod( object )\
5673 if peripheral.getType( \"left\" ) == \"workbench\" then\
5674 object.craft = function( ... )\
5675 return peripheral.call( \"left\", \"craft\", ... )\
5676 end\
5677 elseif peripheral.getType( \"right\" ) == \"workbench\" then\
5678 object.craft = function( ... )\
5679 return peripheral.call( \"right\", \"craft\", ... )\
5680 end\
5681 else\
5682 object.craft = nil\
5683 end\
5684end\
5685\
5686-- Put commands into environment table\
5687local env = _ENV\
5688for k,v in pairs( native ) do\
5689 if k == \"equipLeft\" or k == \"equipRight\" then\
5690 env[k] = function( ... )\
5691 local result, err = v( ... )\
5692 addCraftMethod( turtle )\
5693 return result, err\
5694 end\
5695 else\
5696 env[k] = v\
5697 end\
5698end\
5699addCraftMethod( env )",
5700 [ "programs/set.lua" ] = "\
5701local tArgs = { ... }\
5702if #tArgs == 0 then\
5703 -- \"set\"\
5704 local x,y = term.getCursorPos()\
5705 local tSettings = {}\
5706 for n,sName in ipairs( settings.getNames() ) do\
5707 tSettings[n] = textutils.serialize(sName) .. \" is \" .. textutils.serialize(settings.get(sName))\
5708 end\
5709 textutils.pagedPrint(table.concat(tSettings,\"\\n\"),y-3)\
5710\
5711elseif #tArgs == 1 then\
5712 -- \"set foo\"\
5713 local sName = tArgs[1]\
5714 print( textutils.serialize(sName) .. \" is \" .. textutils.serialize(settings.get(sName)) )\
5715\
5716else\
5717 -- \"set foo bar\"\
5718 local sName = tArgs[1]\
5719 local sValue = tArgs[2]\
5720 local value\
5721 if sValue == \"true\" then\
5722 value = true\
5723 elseif sValue == \"false\" then\
5724 value = false\
5725 elseif sValue == \"nil\" then\
5726 value = nil\
5727 elseif tonumber(sValue) then\
5728 value = tonumber(sValue)\
5729 else\
5730 value = sValue\
5731 end\
5732\
5733 local oldValue = settings.get( sValue )\
5734 if value ~= nil then\
5735 settings.set( sName, value )\
5736 print( textutils.serialize(sName) .. \" set to \" .. textutils.serialize(value) )\
5737 else\
5738 settings.unset( sName )\
5739 print( textutils.serialize(sName) .. \" unset\" )\
5740 end\
5741 if value ~= oldValue then\
5742 settings.save( \".settings\" )\
5743 end\
5744end",
5745 [ "help/parallel.txt" ] = "Functions in the Parallel API:\
5746parallel.waitForAny( function1, function2, ... )\
5747parallel.waitForAll( function1, function2, ... )\
5748These methods provide an easy way to run multiple lua functions simultaneously.",
5749 [ "help/wget.txt" ] = "wget is a program for downloading files from the internet. This is useful for downloading programs created by other players.\
5750If 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.\
5751The HTTP API must be enabled in ComputerCraft.cfg to use this program.\
5752ex:\
5753\"wget http://pastebin.com/raw/CxaWmPrX test\" will download the file from the URL http://pastebin.com/raw/CxaWmPrX, and save it as \"test\".\
5754\"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\"\
5755\"wget http://example.org/\" will download the file from the URL http://example.org and save it as \"example.org\"",
5756 [ "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.\
5757\
5758ex:\
5759\"edit hello\" opens a file called \"hello\" for editing.",
5760 [ "programs/exit.lua" ] = "shell.exit()",
5761 [ "help/rednet.txt" ] = "The rednet API provides a simple computer networking model using modems.\
5762\
5763Functions in the rednet API:\
5764rednet.open( side )\
5765rednet.close( [side] )\
5766rednet.isOpen( [side] )\
5767rednet.send( receiverID, message, [protocol] ) -- Send to a specific computer\
5768rednet.broadcast( message, [protocol] ) -- Send to all computers\
5769rednet.receive( [protocol], [timeout] ) -- Returns: senderID, message, protocol\
5770rednet.host( protocol, hostname )\
5771rednet.unhost( protocol )\
5772rednet.lookup( protocol, [hostname] ) -- Returns: ID\
5773\
5774Events fired by the rednet API:\
5775\"rednet_message\" when a message is received. Arguments are senderID, message, protocol\
5776Type \"help events\" to learn about the event system.\
5777\
5778Rednet 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.",
5779 [ "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.\
5780\
5781ex:\
5782\"turn left\" turns the turtle 90 degrees left.\
5783\"turn right 2\" turns the turtle 180 degrees right.\
5784\"turn left 2 right\" turns left 180 degrees, then right 90 degrees.",
5785 [ "programs/fun/advanced/levels/4.dat" ] = "2\
5786 77777777\
5787777778888887\
5788788888777787\
57897b77787 787\
5790787 787 787\
57917b77787 787\
57927888887 787\
57937777707 707\
5794 777 777",
5795 [ "programs/fun/advanced/levels/0.dat" ] = "0\
579677 77\
5797718888887\
5798 8 8\
5799 8 8\
5800 8 8\
5801788888897\
580277 77",
5803 [ "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\".\
5804\
5805Methods exposed by Workbenches:\
5806craft( channel )",
5807 [ "programs/fun/advanced/levels/9.dat" ] = "2\
5808 777 777\
5809 777877778777\
5810 788838888887\
58117778bbbbbbbb8777\
58127888b888888b8897\
58137878be8888eb8787\
58147588b888888b8887\
58157778bbbbbbbb8777\
5816 788888818887\
5817 777877778777\
5818 777 777",
5819 [ "startup.lua" ] = "\
5820-- Setup paths\
5821local sPath = \".:/rom/programs\"\
5822if term.isColor() then\
5823 sPath = sPath..\":/rom/programs/advanced\"\
5824end\
5825if turtle then\
5826 sPath = sPath..\":/rom/programs/turtle\"\
5827else\
5828 sPath = sPath..\":/rom/programs/rednet:/rom/programs/fun\"\
5829 if term.isColor() then\
5830 sPath = sPath..\":/rom/programs/fun/advanced\"\
5831 end\
5832end\
5833if pocket then\
5834 sPath = sPath..\":/rom/programs/pocket\"\
5835end\
5836if commands then\
5837 sPath = sPath..\":/rom/programs/command\"\
5838end\
5839if http then\
5840 sPath = sPath..\":/rom/programs/http\"\
5841end\
5842shell.setPath( sPath )\
5843help.setPath( \"/rom/help\" )\
5844\
5845-- Setup aliases\
5846shell.setAlias( \"ls\", \"list\" )\
5847shell.setAlias( \"dir\", \"list\" )\
5848shell.setAlias( \"cp\", \"copy\" )\
5849shell.setAlias( \"mv\", \"move\" )\
5850shell.setAlias( \"rm\", \"delete\" )\
5851shell.setAlias( \"clr\", \"clear\" )\
5852shell.setAlias( \"rs\", \"redstone\" )\
5853shell.setAlias( \"sh\", \"shell\" )\
5854if term.isColor() then\
5855 shell.setAlias( \"background\", \"bg\" )\
5856 shell.setAlias( \"foreground\", \"fg\" )\
5857end\
5858\
5859-- Setup completion functions\
5860local function completeMultipleChoice( sText, tOptions, bAddSpaces )\
5861 local tResults = {}\
5862 for n=1,#tOptions do\
5863 local sOption = tOptions[n]\
5864 if #sOption + (bAddSpaces and 1 or 0) > #sText and string.sub( sOption, 1, #sText ) == sText then\
5865 local sResult = string.sub( sOption, #sText + 1 )\
5866 if bAddSpaces then\
5867 table.insert( tResults, sResult .. \" \" )\
5868 else\
5869 table.insert( tResults, sResult )\
5870 end\
5871 end\
5872 end\
5873 return tResults\
5874end\
5875local function completePeripheralName( sText, bAddSpaces )\
5876 return completeMultipleChoice( sText, peripheral.getNames(), bAddSpaces )\
5877end\
5878local tRedstoneSides = redstone.getSides()\
5879local function completeSide( sText, bAddSpaces )\
5880 return completeMultipleChoice( sText, tRedstoneSides, bAddSpaces )\
5881end\
5882local function completeFile( shell, nIndex, sText, tPreviousText )\
5883 if nIndex == 1 then\
5884 return fs.complete( sText, shell.dir(), true, false )\
5885 end\
5886end\
5887local function completeDir( shell, nIndex, sText, tPreviousText )\
5888 if nIndex == 1 then\
5889 return fs.complete( sText, shell.dir(), false, true )\
5890 end\
5891end\
5892local function completeEither( shell, nIndex, sText, tPreviousText )\
5893 if nIndex == 1 then\
5894 return fs.complete( sText, shell.dir(), true, true )\
5895 end\
5896end\
5897local function completeEitherEither( shell, nIndex, sText, tPreviousText )\
5898 if nIndex == 1 then\
5899 local tResults = fs.complete( sText, shell.dir(), true, true )\
5900 for n=1,#tResults do\
5901 local sResult = tResults[n]\
5902 if string.sub( sResult, #sResult, #sResult ) ~= \"/\" then\
5903 tResults[n] = sResult .. \" \"\
5904 end\
5905 end\
5906 return tResults\
5907 elseif nIndex == 2 then\
5908 return fs.complete( sText, shell.dir(), true, true )\
5909 end\
5910end\
5911local function completeProgram( shell, nIndex, sText, tPreviousText )\
5912 if nIndex == 1 then\
5913 return shell.completeProgram( sText )\
5914 end\
5915end\
5916local function completeHelp( shell, nIndex, sText, tPreviousText )\
5917 if nIndex == 1 then\
5918 return help.completeTopic( sText )\
5919 end\
5920end\
5921local function completeAlias( shell, nIndex, sText, tPreviousText )\
5922 if nIndex == 2 then\
5923 return shell.completeProgram( sText )\
5924 end\
5925end\
5926local function completePeripheral( shell, nIndex, sText, tPreviousText )\
5927 if nIndex == 1 then\
5928 return completePeripheralName( sText )\
5929 end\
5930end\
5931local tGPSOptions = { \"host\", \"host \", \"locate\" }\
5932local function completeGPS( shell, nIndex, sText, tPreviousText )\
5933 if nIndex == 1 then\
5934 return completeMultipleChoice( sText, tGPSOptions )\
5935 end\
5936end\
5937local tLabelOptions = { \"get\", \"get \", \"set \", \"clear\", \"clear \" }\
5938local function completeLabel( shell, nIndex, sText, tPreviousText )\
5939 if nIndex == 1 then\
5940 return completeMultipleChoice( sText, tLabelOptions )\
5941 elseif nIndex == 2 then\
5942 return completePeripheralName( sText )\
5943 end\
5944end\
5945local function completeMonitor( shell, nIndex, sText, tPreviousText )\
5946 if nIndex == 1 then\
5947 return completePeripheralName( sText, true )\
5948 elseif nIndex == 2 then\
5949 return shell.completeProgram( sText )\
5950 end\
5951end\
5952local tRedstoneOptions = { \"probe\", \"set \", \"pulse \" }\
5953local function completeRedstone( shell, nIndex, sText, tPreviousText )\
5954 if nIndex == 1 then\
5955 return completeMultipleChoice( sText, tRedstoneOptions )\
5956 elseif nIndex == 2 then\
5957 return completeSide( sText )\
5958 end\
5959end\
5960local tDJOptions = { \"play\", \"play \", \"stop \" }\
5961local function completeDJ( shell, nIndex, sText, tPreviousText )\
5962 if nIndex == 1 then\
5963 return completeMultipleChoice( sText, tDJOptions )\
5964 elseif nIndex == 2 then\
5965 return completePeripheralName( sText )\
5966 end\
5967end\
5968local tPastebinOptions = { \"put \", \"get \", \"run \" }\
5969local function completePastebin( shell, nIndex, sText, tPreviousText )\
5970 if nIndex == 1 then\
5971 return completeMultipleChoice( sText, tPastebinOptions )\
5972 elseif nIndex == 2 then\
5973 if tPreviousText[2] == \"put\" then\
5974 return fs.complete( sText, shell.dir(), true, false )\
5975 end\
5976 end\
5977end\
5978local tChatOptions = { \"host \", \"join \" }\
5979local function completeChat( shell, nIndex, sText, tPreviousText )\
5980 if nIndex == 1 then\
5981 return completeMultipleChoice( sText, tChatOptions )\
5982 end\
5983end\
5984local function completeSet( shell, nIndex, sText, tPreviousText )\
5985 if nIndex == 1 then\
5986 return completeMultipleChoice( sText, settings.getNames(), true )\
5987 end\
5988end\
5989local tCommands\
5990if commands then\
5991 tCommands = commands.list()\
5992end\
5993local function completeExec( shell, nIndex, sText, tPreviousText )\
5994 if nIndex == 1 and commands then\
5995 return completeMultipleChoice( sText, tCommands, true )\
5996 end\
5997end\
5998shell.setCompletionFunction( \"rom/programs/alias.lua\", completeAlias )\
5999shell.setCompletionFunction( \"rom/programs/cd.lua\", completeDir )\
6000shell.setCompletionFunction( \"rom/programs/copy.lua\", completeEitherEither )\
6001shell.setCompletionFunction( \"rom/programs/delete.lua\", completeEither )\
6002shell.setCompletionFunction( \"rom/programs/drive.lua\", completeDir )\
6003shell.setCompletionFunction( \"rom/programs/edit.lua\", completeFile )\
6004shell.setCompletionFunction( \"rom/programs/eject.lua\", completePeripheral )\
6005shell.setCompletionFunction( \"rom/programs/gps.lua\", completeGPS )\
6006shell.setCompletionFunction( \"rom/programs/help.lua\", completeHelp )\
6007shell.setCompletionFunction( \"rom/programs/id.lua\", completePeripheral )\
6008shell.setCompletionFunction( \"rom/programs/label.lua\", completeLabel )\
6009shell.setCompletionFunction( \"rom/programs/list.lua\", completeDir )\
6010shell.setCompletionFunction( \"rom/programs/mkdir.lua\", completeFile )\
6011shell.setCompletionFunction( \"rom/programs/monitor.lua\", completeMonitor )\
6012shell.setCompletionFunction( \"rom/programs/move.lua\", completeEitherEither )\
6013shell.setCompletionFunction( \"rom/programs/redstone.lua\", completeRedstone )\
6014shell.setCompletionFunction( \"rom/programs/rename.lua\", completeEitherEither )\
6015shell.setCompletionFunction( \"rom/programs/shell.lua\", completeProgram )\
6016shell.setCompletionFunction( \"rom/programs/type.lua\", completeEither )\
6017shell.setCompletionFunction( \"rom/programs/set.lua\", completeSet )\
6018shell.setCompletionFunction( \"rom/programs/advanced/bg.lua\", completeProgram )\
6019shell.setCompletionFunction( \"rom/programs/advanced/fg.lua\", completeProgram )\
6020shell.setCompletionFunction( \"rom/programs/fun/dj.lua\", completeDJ )\
6021shell.setCompletionFunction( \"rom/programs/fun/advanced/paint.lua\", completeFile )\
6022shell.setCompletionFunction( \"rom/programs/http/pastebin.lua\", completePastebin )\
6023shell.setCompletionFunction( \"rom/programs/rednet/chat.lua\", completeChat )\
6024shell.setCompletionFunction( \"rom/programs/command/exec.lua\", completeExec )\
6025\
6026if turtle then\
6027 local tGoOptions = { \"left\", \"right\", \"forward\", \"back\", \"down\", \"up\" }\
6028 local function completeGo( shell, nIndex, sText )\
6029 return completeMultipleChoice( sText, tGoOptions, true)\
6030 end\
6031 local tTurnOptions = { \"left\", \"right\" }\
6032 local function completeTurn( shell, nIndex, sText )\
6033 return completeMultipleChoice( sText, tTurnOptions, true )\
6034 end\
6035 local tEquipOptions = { \"left\", \"right\" }\
6036 local function completeEquip( shell, nIndex, sText )\
6037 if nIndex == 2 then\
6038 return completeMultipleChoice( sText, tEquipOptions )\
6039 end\
6040 end\
6041 local function completeUnequip( shell, nIndex, sText )\
6042 if nIndex == 1 then\
6043 return completeMultipleChoice( sText, tEquipOptions )\
6044 end\
6045 end\
6046 shell.setCompletionFunction( \"rom/programs/turtle/go.lua\", completeGo )\
6047 shell.setCompletionFunction( \"rom/programs/turtle/turn.lua\", completeTurn )\
6048 shell.setCompletionFunction( \"rom/programs/turtle/equip.lua\", completeEquip )\
6049 shell.setCompletionFunction( \"rom/programs/turtle/unequip.lua\", completeUnequip )\
6050end\
6051\
6052\
6053-- Run autorun files\
6054if fs.exists( \"/rom/autorun\" ) and fs.isDir( \"/rom/autorun\" ) then\
6055 local tFiles = fs.list( \"/rom/autorun\" )\
6056 table.sort( tFiles )\
6057 for n, sFile in ipairs( tFiles ) do\
6058 if string.sub( sFile, 1, 1 ) ~= \".\" then\
6059 local sPath = \"/rom/autorun/\"..sFile\
6060 if not fs.isDir( sPath ) then\
6061 shell.run( sPath )\
6062 end\
6063 end\
6064 end\
6065end\
6066\
6067local function findStartups( sBaseDir )\
6068 local tStartups = nil\
6069 local sBasePath = \"/\" .. fs.combine( sBaseDir, \"startup\" )\
6070 local sStartupNode = shell.resolveProgram( sBasePath )\
6071 if sStartupNode then\
6072 tStartups = { sStartupNode }\
6073 end\
6074 -- It's possible that there is a startup directory and a startup.lua file, so this has to be\
6075 -- executed even if a file has already been found.\
6076 if fs.isDir( sBasePath ) then\
6077 if tStartups == nil then\
6078 tStartups = {}\
6079 end\
6080 for _,v in pairs( fs.list( sBasePath ) ) do\
6081 local sPath = \"/\" .. fs.combine( sBasePath, v )\
6082 if not fs.isDir( sPath ) then\
6083 tStartups[ #tStartups + 1 ] = sPath\
6084 end\
6085 end\
6086 end\
6087 return tStartups\
6088end\
6089\
6090-- Run the user created startup, either from disk drives or the root\
6091local tUserStartups = nil\
6092if settings.get( \"shell.allow_startup\" ) then\
6093 tUserStartups = findStartups( \"/\" )\
6094end\
6095if settings.get( \"shell.allow_disk_startup\" ) then\
6096 for n,sName in pairs( peripheral.getNames() ) do\
6097 if disk.isPresent( sName ) and disk.hasData( sName ) then\
6098 local startups = findStartups( disk.getMountPath( sName ) )\
6099 if startups then\
6100 tUserStartups = startups\
6101 break\
6102 end\
6103 end\
6104 end\
6105end\
6106if tUserStartups then\
6107 for _,v in pairs( tUserStartups ) do\
6108 shell.run( v )\
6109 end\
6110end",
6111 [ "programs/type.lua" ] = "\
6112local tArgs = { ... }\
6113if #tArgs < 1 then\
6114 print( \"Usage: type <path>\" )\
6115 return\
6116end\
6117\
6118local sPath = shell.resolve( tArgs[1] )\
6119if fs.exists( sPath ) then\
6120 if fs.isDir( sPath ) then\
6121 print( \"directory\" )\
6122 else\
6123 print( \"file\" )\
6124 end\
6125else\
6126 print( \"No such path\" )\
6127end\
6128",
6129 [ "help/set.txt" ] = "The set program can be used to inspect and change system settings.\
6130\
6131Usage:\
6132\"set\" will print all the system settings and their values\
6133\"set foo\" will print the value of the system setting \"foo\"\
6134\"set foo bar\" will set the value of the system setting \"foo\" to \"bar\"",
6135 [ "programs/turtle/unequip.lua" ] = "\
6136local tArgs = { ... }\
6137local function printUsage()\
6138 print( \"Usage: unequip <side>\" )\
6139end\
6140\
6141if #tArgs ~= 1 then\
6142 printUsage()\
6143 return\
6144end\
6145\
6146local function unequip( fnEquipFunction )\
6147 for nSlot=1,16 do\
6148 local nOldCount = turtle.getItemCount( nSlot )\
6149 if nOldCount == 0 then\
6150 turtle.select( nSlot )\
6151 if fnEquipFunction() then\
6152 local nNewCount = turtle.getItemCount( nSlot )\
6153 if nNewCount > 0 then\
6154 print( \"Item unequipped\" )\
6155 return\
6156 else\
6157 print( \"Nothing to unequip\" )\
6158 return\
6159 end\
6160 end\
6161 end\
6162 end\
6163 print( \"No space to unequip item\" )\
6164end\
6165\
6166local sSide = tArgs[1]\
6167if sSide == \"left\" then\
6168 unequip( turtle.equipLeft )\
6169elseif sSide == \"right\" then\
6170 unequip( turtle.equipRight )\
6171else\
6172 printUsage()\
6173 return\
6174end",
6175 [ "help/intro.txt" ] = "Welcome to CraftOS!\
6176Type \"programs\" to see the programs you can run.\
6177Type \"help <program>\" to see help for a specific program.\
6178Type \"help programming\" to learn about programming.\
6179Type \"help whatsnew\" to find out about new features.\
6180Type \"help credits\" to learn who made all this.\
6181Type \"help index\" to see all help topics.",
6182 [ "help/gps.txt" ] = "gps can be used to host a GPS server, or to determine a position using trilateration.\
6183Type \"help gpsapi\" for help using GPS functions in lua programs.\
6184\
6185ex:\
6186\"gps locate\" will connect to nearby GPS servers, and try to determine the position of the computer or turtle.\
6187\"gps host\" will try to determine the position, and host a GPS server if successful.\
6188\"gps host 10 20 30\" will host a GPS server, using the manually entered position 10,20,30. \
6189\
6190Take care when manually entering host positions. If the positions entered into multiple GPS hosts\
6191are not consistent, the results of locate calls will be incorrect.",
6192 [ "help/peripheral.txt" ] = "The peripheral API is for interacting with external peripheral devices. Type \"help peripherals\" to learn about the peripherals available.\
6193\
6194Functions in the peripheral API:\
6195peripheral.getNames()\
6196peripheral.isPresent( name )\
6197peripheral.getType( name )\
6198peripheral.getMethods( name )\
6199peripheral.call( name, methodName, param1, param2, etc )\
6200peripheral.wrap( name )\
6201peripheral.find( type, [fnFilter] )\
6202\
6203Events fired by the peripheral API:\
6204\"peripheral\" when a new peripheral is attached. Argument is the name.\
6205\"peripheral_detach\" when a peripheral is removed. Argument is the name.\
6206Type \"help events\" to learn about the event system.",
6207 [ "help/paintutils.txt" ] = "Functions in the Paint Utilities API:\
6208paintutils.drawPixel( x, y, colour )\
6209paintutils.drawLine( startX, startY, endX, endY, colour )\
6210paintutils.drawBox( startX, startY, endX, endY, colour )\
6211paintutils.drawFilledBox( startX, startY, endX, endY, colour )\
6212paintutils.loadImage( path )\
6213paintutils.drawImage( image, x, y )",
6214 [ "programs/turtle/go.lua" ] = "local tArgs = { ... }\
6215if #tArgs < 1 then\
6216 print( \"Usage: go <direction> <distance>\" )\
6217 return\
6218end\
6219\
6220local tHandlers = {\
6221 [\"fd\"] = turtle.forward,\
6222 [\"forward\"] = turtle.forward,\
6223 [\"forwards\"] = turtle.forward,\
6224 [\"bk\"] = turtle.back,\
6225 [\"back\"] = turtle.back,\
6226 [\"up\"] = turtle.up,\
6227 [\"dn\"] = turtle.down,\
6228 [\"down\"] = turtle.down,\
6229 [\"lt\"] = turtle.turnLeft,\
6230 [\"left\"] = turtle.turnLeft,\
6231 [\"rt\"] = turtle.turnRight,\
6232 [\"right\"] = turtle.turnRight,\
6233}\
6234\
6235local nArg = 1\
6236while nArg <= #tArgs do\
6237 local sDirection = tArgs[nArg]\
6238 local nDistance = 1\
6239 if nArg < #tArgs then\
6240 local num = tonumber( tArgs[nArg + 1] )\
6241 if num then\
6242 nDistance = num\
6243 nArg = nArg + 1\
6244 end\
6245 end\
6246 nArg = nArg + 1\
6247\
6248 local fnHandler = tHandlers[string.lower(sDirection)]\
6249 if fnHandler then\
6250 while nDistance > 0 do\
6251 if fnHandler() then\
6252 nDistance = nDistance - 1\
6253 elseif turtle.getFuelLevel() == 0 then\
6254 print( \"Out of fuel\" )\
6255 return\
6256 else\
6257 sleep(0.5)\
6258 end\
6259 end\
6260 else\
6261 print( \"No such direction: \"..sDirection )\
6262 print( \"Try: forward, back, up, down\" )\
6263 return\
6264 end\
6265\
6266end",
6267 [ "programs/turtle/excavate.lua" ] = "\
6268local tArgs = { ... }\
6269if #tArgs ~= 1 then\
6270 print( \"Usage: excavate <diameter>\" )\
6271 return\
6272end\
6273\
6274-- Mine in a quarry pattern until we hit something we can't dig\
6275local size = tonumber( tArgs[1] )\
6276if size < 1 then\
6277 print( \"Excavate diameter must be positive\" )\
6278 return\
6279end\
6280\
6281local depth = 0\
6282local unloaded = 0\
6283local collected = 0\
6284\
6285local xPos,zPos = 0,0\
6286local xDir,zDir = 0,1\
6287\
6288local goTo -- Filled in further down\
6289local refuel -- Filled in further down\
6290\
6291local function unload( _bKeepOneFuelStack )\
6292 print( \"Unloading items...\" )\
6293 for n=1,16 do\
6294 local nCount = turtle.getItemCount(n)\
6295 if nCount > 0 then\
6296 turtle.select(n)\
6297 local bDrop = true\
6298 if _bKeepOneFuelStack and turtle.refuel(0) then\
6299 bDrop = false\
6300 _bKeepOneFuelStack = false\
6301 end\
6302 if bDrop then\
6303 turtle.drop()\
6304 unloaded = unloaded + nCount\
6305 end\
6306 end\
6307 end\
6308 collected = 0\
6309 turtle.select(1)\
6310end\
6311\
6312local function returnSupplies()\
6313 local x,y,z,xd,zd = xPos,depth,zPos,xDir,zDir\
6314 print( \"Returning to surface...\" )\
6315 goTo( 0,0,0,0,-1 )\
6316\
6317 local fuelNeeded = 2*(x+y+z) + 1\
6318 if not refuel( fuelNeeded ) then\
6319 unload( true )\
6320 print( \"Waiting for fuel\" )\
6321 while not refuel( fuelNeeded ) do\
6322 os.pullEvent( \"turtle_inventory\" )\
6323 end\
6324 else\
6325 unload( true )\
6326 end\
6327\
6328 print( \"Resuming mining...\" )\
6329 goTo( x,y,z,xd,zd )\
6330end\
6331\
6332local function collect()\
6333 local bFull = true\
6334 local nTotalItems = 0\
6335 for n=1,16 do\
6336 local nCount = turtle.getItemCount(n)\
6337 if nCount == 0 then\
6338 bFull = false\
6339 end\
6340 nTotalItems = nTotalItems + nCount\
6341 end\
6342\
6343 if nTotalItems > collected then\
6344 collected = nTotalItems\
6345 if math.fmod(collected + unloaded, 50) == 0 then\
6346 print( \"Mined \"..(collected + unloaded)..\" items.\" )\
6347 end\
6348 end\
6349\
6350 if bFull then\
6351 print( \"No empty slots left.\" )\
6352 return false\
6353 end\
6354 return true\
6355end\
6356\
6357function refuel( ammount )\
6358 local fuelLevel = turtle.getFuelLevel()\
6359 if fuelLevel == \"unlimited\" then\
6360 return true\
6361 end\
6362\
6363 local needed = ammount or (xPos + zPos + depth + 2)\
6364 if turtle.getFuelLevel() < needed then\
6365 local fueled = false\
6366 for n=1,16 do\
6367 if turtle.getItemCount(n) > 0 then\
6368 turtle.select(n)\
6369 if turtle.refuel(1) then\
6370 while turtle.getItemCount(n) > 0 and turtle.getFuelLevel() < needed do\
6371 turtle.refuel(1)\
6372 end\
6373 if turtle.getFuelLevel() >= needed then\
6374 turtle.select(1)\
6375 return true\
6376 end\
6377 end\
6378 end\
6379 end\
6380 turtle.select(1)\
6381 return false\
6382 end\
6383\
6384 return true\
6385end\
6386\
6387local function tryForwards()\
6388 if not refuel() then\
6389 print( \"Not enough Fuel\" )\
6390 returnSupplies()\
6391 end\
6392\
6393 while not turtle.forward() do\
6394 if turtle.detect() then\
6395 if turtle.dig() then\
6396 if not collect() then\
6397 returnSupplies()\
6398 end\
6399 else\
6400 return false\
6401 end\
6402 elseif turtle.attack() then\
6403 if not collect() then\
6404 returnSupplies()\
6405 end\
6406 else\
6407 sleep( 0.5 )\
6408 end\
6409 end\
6410\
6411 xPos = xPos + xDir\
6412 zPos = zPos + zDir\
6413 return true\
6414end\
6415\
6416local function tryDown()\
6417 if not refuel() then\
6418 print( \"Not enough Fuel\" )\
6419 returnSupplies()\
6420 end\
6421\
6422 while not turtle.down() do\
6423 if turtle.detectDown() then\
6424 if turtle.digDown() then\
6425 if not collect() then\
6426 returnSupplies()\
6427 end\
6428 else\
6429 return false\
6430 end\
6431 elseif turtle.attackDown() then\
6432 if not collect() then\
6433 returnSupplies()\
6434 end\
6435 else\
6436 sleep( 0.5 )\
6437 end\
6438 end\
6439\
6440 depth = depth + 1\
6441 if math.fmod( depth, 10 ) == 0 then\
6442 print( \"Descended \"..depth..\" metres.\" )\
6443 end\
6444\
6445 return true\
6446end\
6447\
6448local function turnLeft()\
6449 turtle.turnLeft()\
6450 xDir, zDir = -zDir, xDir\
6451end\
6452\
6453local function turnRight()\
6454 turtle.turnRight()\
6455 xDir, zDir = zDir, -xDir\
6456end\
6457\
6458function goTo( x, y, z, xd, zd )\
6459 while depth > y do\
6460 if turtle.up() then\
6461 depth = depth - 1\
6462 elseif turtle.digUp() or turtle.attackUp() then\
6463 collect()\
6464 else\
6465 sleep( 0.5 )\
6466 end\
6467 end\
6468\
6469 if xPos > x then\
6470 while xDir ~= -1 do\
6471 turnLeft()\
6472 end\
6473 while xPos > x do\
6474 if turtle.forward() then\
6475 xPos = xPos - 1\
6476 elseif turtle.dig() or turtle.attack() then\
6477 collect()\
6478 else\
6479 sleep( 0.5 )\
6480 end\
6481 end\
6482 elseif xPos < x then\
6483 while xDir ~= 1 do\
6484 turnLeft()\
6485 end\
6486 while xPos < x do\
6487 if turtle.forward() then\
6488 xPos = xPos + 1\
6489 elseif turtle.dig() or turtle.attack() then\
6490 collect()\
6491 else\
6492 sleep( 0.5 )\
6493 end\
6494 end\
6495 end\
6496\
6497 if zPos > z then\
6498 while zDir ~= -1 do\
6499 turnLeft()\
6500 end\
6501 while zPos > z do\
6502 if turtle.forward() then\
6503 zPos = zPos - 1\
6504 elseif turtle.dig() or turtle.attack() then\
6505 collect()\
6506 else\
6507 sleep( 0.5 )\
6508 end\
6509 end\
6510 elseif zPos < z then\
6511 while zDir ~= 1 do\
6512 turnLeft()\
6513 end\
6514 while zPos < z do\
6515 if turtle.forward() then\
6516 zPos = zPos + 1\
6517 elseif turtle.dig() or turtle.attack() then\
6518 collect()\
6519 else\
6520 sleep( 0.5 )\
6521 end\
6522 end\
6523 end\
6524\
6525 while depth < y do\
6526 if turtle.down() then\
6527 depth = depth + 1\
6528 elseif turtle.digDown() or turtle.attackDown() then\
6529 collect()\
6530 else\
6531 sleep( 0.5 )\
6532 end\
6533 end\
6534\
6535 while zDir ~= zd or xDir ~= xd do\
6536 turnLeft()\
6537 end\
6538end\
6539\
6540if not refuel() then\
6541 print( \"Out of Fuel\" )\
6542 return\
6543end\
6544\
6545print( \"Excavating...\" )\
6546\
6547local reseal = false\
6548turtle.select(1)\
6549if turtle.digDown() then\
6550 reseal = true\
6551end\
6552\
6553local alternate = 0\
6554local done = false\
6555while not done do\
6556 for n=1,size do\
6557 for m=1,size-1 do\
6558 if not tryForwards() then\
6559 done = true\
6560 break\
6561 end\
6562 end\
6563 if done then\
6564 break\
6565 end\
6566 if n<size then\
6567 if math.fmod(n + alternate,2) == 0 then\
6568 turnLeft()\
6569 if not tryForwards() then\
6570 done = true\
6571 break\
6572 end\
6573 turnLeft()\
6574 else\
6575 turnRight()\
6576 if not tryForwards() then\
6577 done = true\
6578 break\
6579 end\
6580 turnRight()\
6581 end\
6582 end\
6583 end\
6584 if done then\
6585 break\
6586 end\
6587\
6588 if size > 1 then\
6589 if math.fmod(size,2) == 0 then\
6590 turnRight()\
6591 else\
6592 if alternate == 0 then\
6593 turnLeft()\
6594 else\
6595 turnRight()\
6596 end\
6597 alternate = 1 - alternate\
6598 end\
6599 end\
6600\
6601 if not tryDown() then\
6602 done = true\
6603 break\
6604 end\
6605end\
6606\
6607print( \"Returning to surface...\" )\
6608\
6609-- Return to where we started\
6610goTo( 0,0,0,0,-1 )\
6611unload( false )\
6612goTo( 0,0,0,0,1 )\
6613\
6614-- Seal the hole\
6615if reseal then\
6616 turtle.placeDown()\
6617end\
6618\
6619print( \"Mined \"..(collected + unloaded)..\" items total.\" )",
6620 [ "programs/turtle/equip.lua" ] = "\
6621local tArgs = { ... }\
6622local function printUsage()\
6623 print( \"Usage: equip <slot> <side>\" )\
6624end\
6625\
6626if #tArgs ~= 2 then\
6627 printUsage()\
6628 return\
6629end\
6630\
6631local function equip( nSlot, fnEquipFunction )\
6632 turtle.select( nSlot )\
6633 local nOldCount = turtle.getItemCount( nSlot )\
6634 if nOldCount == 0 then\
6635 print( \"Nothing to equip\" )\
6636 elseif fnEquipFunction() then\
6637 local nNewCount = turtle.getItemCount( nSlot )\
6638 if nNewCount > 0 then\
6639 print( \"Items swapped\" )\
6640 else\
6641 print( \"Item equipped\" )\
6642 end\
6643 else\
6644 print( \"Item not equippable\" )\
6645 end\
6646end\
6647\
6648local nSlot = tonumber( tArgs[1] )\
6649local sSide = tArgs[2]\
6650if sSide == \"left\" then\
6651 equip( nSlot, turtle.equipLeft )\
6652elseif sSide == \"right\" then\
6653 equip( nSlot, turtle.equipRight )\
6654else\
6655 printUsage()\
6656 return\
6657end",
6658 [ "help/whatsnew.txt" ] = "New Features in ComputerCraft 1.80:\
6659\
6660* Added .getResponseHeaders() to HTTP responses.\
6661* Return a HTTP response when a HTTP error occurs.\
6662* Added a GUI to change ComputerCraft config options.\
6663* os.time() and os.day() now accept parameters to give the real world time.\
6664* Added os.epoch()\
6665* Monitor text now glows in the dark.\
6666* Added a \"Pocket Computer upgrade API\" so mod developers can add their own pocket upgrades.\
6667* Added pocket.equipBack()/pocket.unequipBack() to add/remove pocket upgrades.\
6668* Added term.setPaletteColor()/term.getPaletteColor() to change/check colors\
6669* Added colors.rgb8()/colours.rgb8() \
6670* Performance improvements to fs.find\
6671* Requires the player to be interacting with the computer when typing\
6672* Disk labels are limited to 32 characters\
6673* Labels can now only include characters within the printable range ( to ~)\
6674* Various model improvements\
6675* There is now a configurable file descriptor limit\
6676* Threads are now daemon threads\
6677* Termination signals are now sent unless the computer is off\
6678* Fixed compilation errors\
6679* Now handles tile entity changes\
6680* GPS coordinates now have to be numbers\
6681* Turtle upgrades now act as tools and peripherals\
6682* The Filesystem.list result is now sorted\
6683* The number of values to unpack can now be manually specified\
6684* Small terminal & monitor rendering improvements\
6685* General improvements to the documentation\
6686* Redstone inputs are no longer reset when adding peripherals\
6687* Turtles now use tinting\
6688* shell.resolveProgram now picks up on *.lua files\
6689* Fixed a handful of bugs in ComputerCraft\
6690* Added speaker block, turtle upgrade, pocket upgrade, and peripheral api\
6691* Startup can now be a directory containing multiple startup files\
6692* Added .getLabel to the computer peripheral\
6693\
6694Type \"help changelog\" to see the full version history.",
6695 [ "help/shutdown.txt" ] = "shutdown will turn off the computer.",
6696 [ "apis/settings.lua" ] = "\
6697local tSettings = {}\
6698\
6699function set( sName, value )\
6700 if type( sName ) ~= \"string\" then error( \"bad argument #1 (expected string, got \" .. type( sName ) .. \")\", 2 ) end\
6701\
6702 local sValueTy = type(value)\
6703 if sValueTy ~= \"number\" and sValueTy ~= \"string\" and sValueTy ~= \"boolean\" and sValueTy ~= \"table\" then\
6704 error( \"bad argument #2 (expected value, got \" .. sValueTy .. \")\", 2 )\
6705 end\
6706 if sValueTy == \"table\" then\
6707 -- Ensure value is serializeable\
6708 value = textutils.unserialize( textutils.serialize(value) )\
6709 end\
6710 tSettings[ sName ] = value\
6711end\
6712\
6713local copy\
6714function copy( value )\
6715 if type(value) == \"table\" then\
6716 local result = {}\
6717 for k,v in pairs(value) do\
6718 result[k] = copy(v)\
6719 end\
6720 return result\
6721 else\
6722 return value\
6723 end\
6724end\
6725\
6726function get( sName, default )\
6727 if type(sName) ~= \"string\" then\
6728 error( \"bad argument #1 (expected string, got \" .. type( sName ) .. \")\", 2 )\
6729 end\
6730 local result = tSettings[ sName ]\
6731 if result ~= nil then\
6732 return copy(result)\
6733 else\
6734 return default\
6735 end\
6736end\
6737\
6738function unset( sName )\
6739 if type(sName) ~= \"string\" then\
6740 error( \"bad argument #1 (expected string, got \" .. type( sName ) .. \")\", 2 )\
6741 end\
6742 tSettings[ sName ] = nil\
6743end\
6744\
6745function clear()\
6746 tSettings = {}\
6747end\
6748\
6749function getNames()\
6750 local result = {}\
6751 for k,v in pairs( tSettings ) do\
6752 result[ #result + 1 ] = k\
6753 end\
6754 table.sort(result)\
6755 return result\
6756end\
6757\
6758function load( sPath )\
6759 if type(sPath) ~= \"string\" then\
6760 error( \"bad argument #1 (expected string, got \" .. type( sPath ) .. \")\", 2 )\
6761 end\
6762 local file = fs.open( sPath, \"r\" )\
6763 if not file then\
6764 return false\
6765 end\
6766\
6767 local sText = file.readAll()\
6768 file.close()\
6769\
6770 local tFile = textutils.unserialize( sText )\
6771 if type(tFile) ~= \"table\" then\
6772 return false\
6773 end\
6774\
6775 for k,v in pairs(tFile) do\
6776 if type(k) == \"string\" and\
6777 (type(v) == \"string\" or type(v) == \"number\" or type(v) == \"boolean\" or type(v) == \"table\") then\
6778 set( k, v )\
6779 end\
6780 end\
6781\
6782 return true\
6783end\
6784\
6785function save( sPath )\
6786 if type(sPath) ~= \"string\" then\
6787 error( \"bad argument #1 (expected string, got \" .. type( sPath ) .. \")\", 2 )\
6788 end\
6789 local file = fs.open( sPath, \"w\" )\
6790 if not file then\
6791 return false\
6792 end\
6793\
6794 file.write( textutils.serialize( tSettings ) )\
6795 file.close()\
6796\
6797 return true\
6798end",
6799 [ "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\"",
6800 [ "help/term.txt" ] = "Functions in the Terminal API:\
6801term.write( text )\
6802term.blit( text, textColor, backgroundColor )\
6803term.clear()\
6804term.clearLine()\
6805term.getCursorPos()\
6806term.setCursorPos( x, y )\
6807term.setCursorBlink( blink )\
6808term.isColor()\
6809term.setTextColor( color )\
6810term.setBackgroundColor( color )\
6811term.getTextColor()\
6812term.getBackgroundColor()\
6813term.getSize()\
6814term.scroll( n )\
6815term.redirect( object )\
6816term.current()\
6817term.setPaletteColor( color, r, g, b )\
6818term.getPaletteColor( color )\
6819\
6820Events emitted by the terminals:\
6821\"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.",
6822 [ "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.\
6823\
6824ex:\
6825\"exec say Hello World\"\
6826\"exec setblock ~0 ~1 ~0 minecraft:dirt\"\
6827\
6828Type \"help commandsapi\" for help using commands in lua programs.",
6829 [ "programs/turtle/dance.lua" ] = "\
6830local tMoves = {\
6831 function()\
6832 turtle.up()\
6833 turtle.down()\
6834 end,\
6835 function()\
6836 turtle.up()\
6837 turtle.turnLeft()\
6838 turtle.turnLeft()\
6839 turtle.turnLeft()\
6840 turtle.turnLeft()\
6841 turtle.down()\
6842 end,\
6843 function()\
6844 turtle.up()\
6845 turtle.turnRight()\
6846 turtle.turnRight()\
6847 turtle.turnRight()\
6848 turtle.turnRight()\
6849 turtle.down()\
6850 end,\
6851 function()\
6852 turtle.turnLeft()\
6853 turtle.turnLeft()\
6854 turtle.turnLeft()\
6855 turtle.turnLeft()\
6856 end,\
6857 function()\
6858 turtle.turnRight()\
6859 turtle.turnRight()\
6860 turtle.turnRight()\
6861 turtle.turnRight()\
6862 end,\
6863 function()\
6864 turtle.turnLeft()\
6865 turtle.back()\
6866 turtle.back()\
6867 turtle.turnRight()\
6868 turtle.turnRight()\
6869 turtle.back()\
6870 turtle.back()\
6871 turtle.turnLeft()\
6872 end,\
6873 function()\
6874 turtle.turnRight()\
6875 turtle.back()\
6876 turtle.back()\
6877 turtle.turnLeft()\
6878 turtle.turnLeft()\
6879 turtle.back()\
6880 turtle.back()\
6881 turtle.turnRight()\
6882 end,\
6883 function()\
6884 turtle.back()\
6885 turtle.turnLeft()\
6886 turtle.back()\
6887 turtle.turnLeft()\
6888 turtle.back()\
6889 turtle.turnLeft()\
6890 turtle.back()\
6891 turtle.turnLeft()\
6892 end,\
6893 function()\
6894 turtle.back()\
6895 turtle.turnRight()\
6896 turtle.back()\
6897 turtle.turnRight()\
6898 turtle.back()\
6899 turtle.turnRight()\
6900 turtle.back()\
6901 turtle.turnRight()\
6902 end,\
6903}\
6904\
6905textutils.slowWrite( \"Preparing to get down.\" )\
6906textutils.slowPrint( \"..\", 0.75 )\
6907\
6908local sAudio = nil\
6909for n,sName in pairs( peripheral.getNames() ) do\
6910 if disk.hasAudio( sName ) then\
6911 disk.playAudio( sName )\
6912 print( \"Jamming to \"..disk.getAudioTitle( sName ) )\
6913 sAudio = sName\
6914 break\
6915 end\
6916end\
6917\
6918print( \"Press any key to stop the groove\" )\
6919\
6920parallel.waitForAny(\
6921 function()\
6922 while not bEnd do\
6923 local event, key = os.pullEvent(\"key\")\
6924 if key ~= keys.escape then\
6925 return\
6926 end\
6927 end\
6928 end,\
6929 function()\
6930 while true do\
6931 local fnMove = tMoves[math.random(1,#tMoves)]\
6932 fnMove()\
6933 end\
6934 end\
6935)\
6936\
6937if sAudio then\
6938 disk.stopAudio( sAudio )\
6939end",
6940 [ "apis/rednet.lua" ] = "\
6941CHANNEL_BROADCAST = 65535\
6942CHANNEL_REPEAT = 65533\
6943\
6944local tReceivedMessages = {}\
6945local tReceivedMessageTimeouts = {}\
6946local tHostnames = {}\
6947\
6948function open( sModem )\
6949 if type( sModem ) ~= \"string\" then\
6950 error( \"bad argument #1 (expected string, got \" .. type( sModem ) .. \")\", 2 )\
6951 end\
6952 if peripheral.getType( sModem ) ~= \"modem\" then\
6953 error( \"No such modem: \"..sModem, 2 )\
6954 end\
6955 peripheral.call( sModem, \"open\", os.getComputerID() )\
6956 peripheral.call( sModem, \"open\", CHANNEL_BROADCAST )\
6957end\
6958\
6959function close( sModem )\
6960 if sModem then\
6961 -- Close a specific modem\
6962 if type( sModem ) ~= \"string\" then\
6963 error( \"bad argument #1 (expected string, got \" .. type( sModem ) .. \")\", 2 )\
6964 end\
6965 if peripheral.getType( sModem ) ~= \"modem\" then\
6966 error( \"No such modem: \"..sModem, 2 )\
6967 end\
6968 peripheral.call( sModem, \"close\", os.getComputerID() )\
6969 peripheral.call( sModem, \"close\", CHANNEL_BROADCAST )\
6970 else\
6971 -- Close all modems\
6972 for n,sModem in ipairs( peripheral.getNames() ) do\
6973 if isOpen( sModem ) then\
6974 close( sModem )\
6975 end\
6976 end\
6977 end\
6978end\
6979\
6980function isOpen( sModem )\
6981 if sModem then\
6982 -- Check if a specific modem is open\
6983 if type( sModem ) ~= \"string\" then\
6984 error( \"bad argument #1 (expected string, got \" .. type( sModem ) .. \")\", 2 )\
6985 end\
6986 if peripheral.getType( sModem ) == \"modem\" then\
6987 return peripheral.call( sModem, \"isOpen\", os.getComputerID() ) and peripheral.call( sModem, \"isOpen\", CHANNEL_BROADCAST )\
6988 end\
6989 else\
6990 -- Check if any modem is open\
6991 for n,sModem in ipairs( peripheral.getNames() ) do\
6992 if isOpen( sModem ) then\
6993 return true\
6994 end\
6995 end\
6996 end\
6997 return false\
6998end\
6999\
7000function send( nRecipient, message, sProtocol )\
7001 if type( nRecipient ) ~= \"number\" then\
7002 error( \"bad argument #1 (expected number, got \" .. type( nRecipient ) .. \")\", 2 )\
7003 end\
7004 if sProtocol ~= nil and type( sProtocol ) ~= \"string\" then\
7005 error( \"bad argument #3 (expected string, got \" .. type( sProtocol ) .. \")\", 2 )\
7006 end\
7007 -- Generate a (probably) unique message ID\
7008 -- We could do other things to guarantee uniqueness, but we really don't need to\
7009 -- Store it to ensure we don't get our own messages back\
7010 local nMessageID = math.random( 1, 2147483647 )\
7011 tReceivedMessages[ nMessageID ] = true\
7012 tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = nMessageID\
7013\
7014 -- Create the message\
7015 local nReplyChannel = os.getComputerID()\
7016 local tMessage = {\
7017 nMessageID = nMessageID,\
7018 nRecipient = nRecipient,\
7019 message = message,\
7020 sProtocol = sProtocol,\
7021 }\
7022\
7023 local sent = false\
7024 if nRecipient == os.getComputerID() then\
7025 -- Loopback to ourselves\
7026 os.queueEvent( \"rednet_message\", nReplyChannel, message, sProtocol )\
7027 sent = true\
7028 else\
7029 -- Send on all open modems, to the target and to repeaters\
7030 for n,sModem in ipairs( peripheral.getNames() ) do\
7031 if isOpen( sModem ) then\
7032 peripheral.call( sModem, \"transmit\", nRecipient, nReplyChannel, tMessage );\
7033 peripheral.call( sModem, \"transmit\", CHANNEL_REPEAT, nReplyChannel, tMessage );\
7034 sent = true\
7035 end\
7036 end\
7037 end\
7038 \
7039 return sent\
7040end\
7041\
7042function broadcast( message, sProtocol )\
7043 if sProtocol ~= nil and type( sProtocol ) ~= \"string\" then\
7044 error( \"bad argument #2 (expected string, got \" .. type( sProtocol ) .. \")\", 2 )\
7045 end\
7046 send( CHANNEL_BROADCAST, message, sProtocol )\
7047end\
7048\
7049function receive( sProtocolFilter, nTimeout )\
7050 -- The parameters used to be ( nTimeout ), detect this case for backwards compatibility\
7051 if type(sProtocolFilter) == \"number\" and nTimeout == nil then\
7052 sProtocolFilter, nTimeout = nil, sProtocolFilter\
7053 end\
7054 if sProtocolFilter ~= nil and type( sProtocolFilter ) ~= \"string\" then\
7055 error( \"bad argument #1 (expected string, got \" .. type( sProtocolFilter ) .. \")\", 2 )\
7056 end\
7057 if nTimeout ~= nil and type( nTimeout ) ~= \"number\" then\
7058 error( \"bad argument #2 (expected number, got \" .. type( nTimeout ) .. \")\", 2 )\
7059 end\
7060\
7061 -- Start the timer\
7062 local timer = nil\
7063 local sFilter = nil\
7064 if nTimeout then\
7065 timer = os.startTimer( nTimeout )\
7066 sFilter = nil\
7067 else\
7068 sFilter = \"rednet_message\"\
7069 end\
7070\
7071 -- Wait for events\
7072 while true do\
7073 local sEvent, p1, p2, p3 = os.pullEvent( sFilter )\
7074 if sEvent == \"rednet_message\" then\
7075 -- Return the first matching rednet_message\
7076 local nSenderID, message, sProtocol = p1, p2, p3\
7077 if sProtocolFilter == nil or sProtocol == sProtocolFilter then\
7078 return nSenderID, message, sProtocol\
7079 end\
7080 elseif sEvent == \"timer\" then\
7081 -- Return nil if we timeout\
7082 if p1 == timer then\
7083 return nil\
7084 end\
7085 end\
7086 end\
7087end\
7088\
7089function host( sProtocol, sHostname )\
7090 if type( sProtocol ) ~= \"string\" then\
7091 error( \"bad argument #1 (expected string, got \" .. type( sProtocol ) .. \")\", 2 )\
7092 end\
7093 if type( sHostname ) ~= \"string\" then\
7094 error( \"bad argument #2 (expected string, got \" .. type( sHostname ) .. \")\", 2 )\
7095 end\
7096 if sHostname == \"localhost\" then\
7097 error( \"Reserved hostname\", 2 )\
7098 end\
7099 if tHostnames[ sProtocol ] ~= sHostname then\
7100 if lookup( sProtocol, sHostname ) ~= nil then\
7101 error( \"Hostname in use\", 2 )\
7102 end\
7103 tHostnames[ sProtocol ] = sHostname\
7104 end\
7105end\
7106\
7107function unhost( sProtocol )\
7108 if type( sProtocol ) ~= \"string\" then\
7109 error( \"bad argument #1 (expected string, got \" .. type( sProtocol ) .. \")\", 2 )\
7110 end\
7111 tHostnames[ sProtocol ] = nil\
7112end\
7113\
7114function lookup( sProtocol, sHostname )\
7115 if type( sProtocol ) ~= \"string\" then\
7116 error( \"bad argument #1 (expected string, got \" .. type( sProtocol ) .. \")\", 2 )\
7117 end\
7118 if sHostname ~= nil and type( sHostname ) ~= \"string\" then\
7119 error( \"bad argument #2 (expected string, got \" .. type( sHostname ) .. \")\", 2 )\
7120 end\
7121\
7122 -- Build list of host IDs\
7123 local tResults = nil\
7124 if sHostname == nil then\
7125 tResults = {}\
7126 end\
7127\
7128 -- Check localhost first\
7129 if tHostnames[ sProtocol ] then\
7130 if sHostname == nil then\
7131 table.insert( tResults, os.getComputerID() )\
7132 elseif sHostname == \"localhost\" or sHostname == tHostnames[ sProtocol ] then\
7133 return os.getComputerID()\
7134 end\
7135 end\
7136\
7137 if not isOpen() then\
7138 if tResults then\
7139 return table.unpack( tResults )\
7140 end\
7141 return nil\
7142 end\
7143\
7144 -- Broadcast a lookup packet\
7145 broadcast( {\
7146 sType = \"lookup\",\
7147 sProtocol = sProtocol,\
7148 sHostname = sHostname,\
7149 }, \"dns\" )\
7150\
7151 -- Start a timer\
7152 local timer = os.startTimer( 2 )\
7153\
7154 -- Wait for events\
7155 while true do\
7156 local event, p1, p2, p3 = os.pullEvent()\
7157 if event == \"rednet_message\" then\
7158 -- Got a rednet message, check if it's the response to our request\
7159 local nSenderID, tMessage, sMessageProtocol = p1, p2, p3\
7160 if sMessageProtocol == \"dns\" and type(tMessage) == \"table\" and tMessage.sType == \"lookup response\" then\
7161 if tMessage.sProtocol == sProtocol then\
7162 if sHostname == nil then\
7163 table.insert( tResults, nSenderID )\
7164 elseif tMessage.sHostname == sHostname then\
7165 return nSenderID\
7166 end\
7167 end\
7168 end\
7169 else\
7170 -- Got a timer event, check it's the end of our timeout\
7171 if p1 == timer then\
7172 break\
7173 end\
7174 end\
7175 end\
7176 if tResults then\
7177 return table.unpack( tResults )\
7178 end\
7179 return nil\
7180end\
7181\
7182local bRunning = false\
7183function run()\
7184 if bRunning then\
7185 error( \"rednet is already running\", 2 )\
7186 end\
7187 bRunning = true\
7188\
7189 while bRunning do\
7190 local sEvent, p1, p2, p3, p4 = os.pullEventRaw()\
7191 if sEvent == \"modem_message\" then\
7192 -- Got a modem message, process it and add it to the rednet event queue\
7193 local sModem, nChannel, nReplyChannel, tMessage = p1, p2, p3, p4\
7194 if isOpen( sModem ) and ( nChannel == os.getComputerID() or nChannel == CHANNEL_BROADCAST ) then\
7195 if type( tMessage ) == \"table\" and tMessage.nMessageID then\
7196 if not tReceivedMessages[ tMessage.nMessageID ] then\
7197 tReceivedMessages[ tMessage.nMessageID ] = true\
7198 tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = tMessage.nMessageID\
7199 os.queueEvent( \"rednet_message\", nReplyChannel, tMessage.message, tMessage.sProtocol )\
7200 end\
7201 end\
7202 end\
7203\
7204 elseif sEvent == \"rednet_message\" then\
7205 -- Got a rednet message (queued from above), respond to dns lookup\
7206 local nSenderID, tMessage, sProtocol = p1, p2, p3\
7207 if sProtocol == \"dns\" and type(tMessage) == \"table\" and tMessage.sType == \"lookup\" then\
7208 local sHostname = tHostnames[ tMessage.sProtocol ]\
7209 if sHostname ~= nil and (tMessage.sHostname == nil or tMessage.sHostname == sHostname) then\
7210 rednet.send( nSenderID, {\
7211 sType = \"lookup response\",\
7212 sHostname = sHostname,\
7213 sProtocol = tMessage.sProtocol,\
7214 }, \"dns\" )\
7215 end\
7216 end\
7217\
7218 elseif sEvent == \"timer\" then\
7219 -- Got a timer event, use it to clear the event queue\
7220 local nTimer = p1\
7221 local nMessage = tReceivedMessageTimeouts[ nTimer ]\
7222 if nMessage then\
7223 tReceivedMessageTimeouts[ nTimer ] = nil\
7224 tReceivedMessages[ nMessage ] = nil\
7225 end\
7226 end\
7227 end\
7228end",
7229 [ "programs/time.lua" ] = "local nTime = os.time()\
7230local nDay = os.day()\
7231print( \"The time is \"..textutils.formatTime( nTime, false )..\" on Day \"..nDay )",
7232 [ "help/clear.txt" ] = "clear clears the screen.",
7233 [ "programs/shutdown.lua" ] = "if term.isColour() then\
7234 term.setTextColour( colours.yellow )\
7235end\
7236print( \"Goodbye\" )\
7237term.setTextColour( colours.white )\
7238\
7239sleep( 1 )\
7240os.shutdown()",
7241 [ "apis/parallel.lua" ] = "\
7242local function create( ... )\
7243 local tFns = table.pack(...)\
7244 local tCos = {}\
7245 for i = 1, tFns.n, 1 do\
7246 local fn = tFns[i]\
7247 if type( fn ) ~= \"function\" then\
7248 error( \"bad argument #\" .. i .. \" (expected function, got \" .. type( fn ) .. \")\", 3 )\
7249 end\
7250\
7251 tCos[i] = coroutine.create(fn)\
7252 end\
7253\
7254 return tCos\
7255end\
7256\
7257local function runUntilLimit( _routines, _limit )\
7258 local count = #_routines\
7259 local living = count\
7260\
7261 local tFilters = {}\
7262 local eventData = { n = 0 }\
7263 while true do\
7264 for n=1,count do\
7265 local r = _routines[n]\
7266 if r then\
7267 if tFilters[r] == nil or tFilters[r] == eventData[1] or eventData[1] == \"terminate\" then\
7268 local ok, param = coroutine.resume( r, table.unpack( eventData, 1, eventData.n ) )\
7269 if not ok then\
7270 error( param, 0 )\
7271 else\
7272 tFilters[r] = param\
7273 end\
7274 if coroutine.status( r ) == \"dead\" then\
7275 _routines[n] = nil\
7276 living = living - 1\
7277 if living <= _limit then\
7278 return n\
7279 end\
7280 end\
7281 end\
7282 end\
7283 end\
7284 for n=1,count do\
7285 local r = _routines[n]\
7286 if r and coroutine.status( r ) == \"dead\" then\
7287 _routines[n] = nil\
7288 living = living - 1\
7289 if living <= _limit then\
7290 return n\
7291 end\
7292 end\
7293 end\
7294 eventData = table.pack( os.pullEventRaw() )\
7295 end\
7296end\
7297\
7298function waitForAny( ... )\
7299 local routines = create( ... )\
7300 return runUntilLimit( routines, #routines - 1 )\
7301end\
7302\
7303function waitForAll( ... )\
7304 local routines = create( ... )\
7305 runUntilLimit( routines, 0 )\
7306end",
7307 [ "help/time.txt" ] = "time prints the current time of day.",
7308 [ "help/dance.txt" ] = "dance is a program for Turtles. Turtles love to get funky.",
7309 [ "programs/shell.lua" ] = "\
7310local multishell = multishell\
7311local parentShell = shell\
7312local parentTerm = term.current()\
7313\
7314if multishell then\
7315 multishell.setTitle( multishell.getCurrent(), \"shell\" )\
7316end\
7317\
7318local bExit = false\
7319local sDir = (parentShell and parentShell.dir()) or \"\"\
7320local sPath = (parentShell and parentShell.path()) or \".:/rom/programs\"\
7321local tAliases = (parentShell and parentShell.aliases()) or {}\
7322local tCompletionInfo = (parentShell and parentShell.getCompletionInfo()) or {}\
7323local tProgramStack = {}\
7324\
7325local shell = {}\
7326local function createShellEnv( sDir )\
7327 local tEnv = {}\
7328 tEnv[ \"shell\" ] = shell\
7329 tEnv[ \"multishell\" ] = multishell\
7330\
7331 local package = {}\
7332 package.loaded = {\
7333 _G = _G,\
7334 bit32 = bit32,\
7335 coroutine = coroutine,\
7336 math = math,\
7337 package = package,\
7338 string = string,\
7339 table = table,\
7340 }\
7341 package.path = \"?;?.lua;?/init.lua;/rom/modules/main/?;/rom/modules/main/?.lua;/rom/modules/main/?/init.lua\"\
7342 if turtle then\
7343 package.path = package.path..\";/rom/modules/turtle/?;/rom/modules/turtle/?.lua;/rom/modules/turtle/?/init.lua\"\
7344 elseif command then\
7345 package.path = package.path..\";/rom/modules/command/?;/rom/modules/command/?.lua;/rom/modules/command/?/init.lua\"\
7346 end\
7347 package.config = \"/\\n;\\n?\\n!\\n-\"\
7348 package.preload = {}\
7349 package.loaders = {\
7350 function( name )\
7351 if package.preload[name] then\
7352 return package.preload[name]\
7353 else\
7354 return nil, \"no field package.preload['\" .. name .. \"']\"\
7355 end\
7356 end,\
7357 function( name )\
7358 local fname = string.gsub(name, \"%.\", \"/\")\
7359 local sError = \"\"\
7360 for pattern in string.gmatch(package.path, \"[^;]+\") do\
7361 local sPath = string.gsub(pattern, \"%?\", fname)\
7362 if sPath:sub(1,1) ~= \"/\" then\
7363 sPath = fs.combine(sDir, sPath)\
7364 end\
7365 if fs.exists(sPath) and not fs.isDir(sPath) then\
7366 local fnFile, sError = loadfile( sPath, tEnv )\
7367 if fnFile then\
7368 return fnFile, sPath\
7369 else\
7370 return nil, sError\
7371 end\
7372 else\
7373 if #sError > 0 then\
7374 sError = sError .. \"\\n \"\
7375 end\
7376 sError = sError .. \"no file '\" .. sPath .. \"'\"\
7377 end\
7378 end\
7379 return nil, sError\
7380 end\
7381 }\
7382\
7383 local sentinel = {}\
7384 local function require( name )\
7385 if type( name ) ~= \"string\" then\
7386 error( \"bad argument #1 (expected string, got \" .. type( name ) .. \")\", 2 )\
7387 end\
7388 if package.loaded[name] == sentinel then\
7389 error(\"loop or previous error loading module '\" .. name .. \"'\", 0)\
7390 end\
7391 if package.loaded[name] then\
7392 return package.loaded[name]\
7393 end\
7394\
7395 local sError = \"module '\" .. name .. \"' not found:\"\
7396 for _, searcher in ipairs(package.loaders) do\
7397 local loader = table.pack(searcher(name))\
7398 if loader[1] then\
7399 package.loaded[name] = sentinel\
7400 local result = loader[1](name, table.unpack(loader, 2, loader.n))\
7401 if result == nil then result = true end\
7402\
7403 package.loaded[name] = result\
7404 return result\
7405 else\
7406 sError = sError .. \"\\n \" .. loader[2]\
7407 end\
7408 end\
7409 error(sError, 2)\
7410 end\
7411\
7412 tEnv[\"package\"] = package\
7413 tEnv[\"require\"] = require\
7414\
7415 return tEnv\
7416end\
7417\
7418-- Colours\
7419local promptColour, textColour, bgColour\
7420if term.isColour() then\
7421 promptColour = colours.yellow\
7422 textColour = colours.white\
7423 bgColour = colours.black\
7424else\
7425 promptColour = colours.white\
7426 textColour = colours.white\
7427 bgColour = colours.black\
7428end\
7429\
7430local function run( _sCommand, ... )\
7431 local sPath = shell.resolveProgram( _sCommand )\
7432 if sPath ~= nil then\
7433 tProgramStack[#tProgramStack + 1] = sPath\
7434 if multishell then\
7435 local sTitle = fs.getName( sPath )\
7436 if sTitle:sub(-4) == \".lua\" then\
7437 sTitle = sTitle:sub(1,-5)\
7438 end\
7439 multishell.setTitle( multishell.getCurrent(), sTitle )\
7440 end\
7441 local sDir = fs.getDir( sPath )\
7442 local result = os.run( createShellEnv( sDir ), sPath, ... )\
7443 tProgramStack[#tProgramStack] = nil\
7444 if multishell then\
7445 if #tProgramStack > 0 then\
7446 local sTitle = fs.getName( tProgramStack[#tProgramStack] )\
7447 if sTitle:sub(-4) == \".lua\" then\
7448 sTitle = sTitle:sub(1,-5)\
7449 end\
7450 multishell.setTitle( multishell.getCurrent(), sTitle )\
7451 else\
7452 multishell.setTitle( multishell.getCurrent(), \"shell\" )\
7453 end\
7454 end\
7455 return result\
7456 else\
7457 printError( \"No such program\" )\
7458 return false\
7459 end\
7460end\
7461\
7462local function tokenise( ... )\
7463 local sLine = table.concat( { ... }, \" \" )\
7464 local tWords = {}\
7465 local bQuoted = false\
7466 for match in string.gmatch( sLine .. \"\\\"\", \"(.-)\\\"\" ) do\
7467 if bQuoted then\
7468 table.insert( tWords, match )\
7469 else\
7470 for m in string.gmatch( match, \"[^ \\t]+\" ) do\
7471 table.insert( tWords, m )\
7472 end\
7473 end\
7474 bQuoted = not bQuoted\
7475 end\
7476 return tWords\
7477end\
7478\
7479-- Install shell API\
7480function shell.run( ... )\
7481 local tWords = tokenise( ... )\
7482 local sCommand = tWords[1]\
7483 if sCommand then\
7484 return run( sCommand, table.unpack( tWords, 2 ) )\
7485 end\
7486 return false\
7487end\
7488\
7489function shell.exit()\
7490 bExit = true\
7491end\
7492\
7493function shell.dir()\
7494 return sDir\
7495end\
7496\
7497function shell.setDir( _sDir )\
7498 if type( _sDir ) ~= \"string\" then\
7499 error( \"bad argument #1 (expected string, got \" .. type( _sDir ) .. \")\", 2 )\
7500 end\
7501 if not fs.isDir( _sDir ) then\
7502 error( \"Not a directory\", 2 )\
7503 end\
7504 sDir = _sDir\
7505end\
7506\
7507function shell.path()\
7508 return sPath\
7509end\
7510\
7511function shell.setPath( _sPath )\
7512 if type( _sPath ) ~= \"string\" then\
7513 error( \"bad argument #1 (expected string, got \" .. type( _sPath ) .. \")\", 2 )\
7514 end\
7515 sPath = _sPath\
7516end\
7517\
7518function shell.resolve( _sPath )\
7519 if type( _sPath ) ~= \"string\" then\
7520 error( \"bad argument #1 (expected string, got \" .. type( _sPath ) .. \")\", 2 )\
7521 end\
7522 local sStartChar = string.sub( _sPath, 1, 1 )\
7523 if sStartChar == \"/\" or sStartChar == \"\\\\\" then\
7524 return fs.combine( \"\", _sPath )\
7525 else\
7526 return fs.combine( sDir, _sPath )\
7527 end\
7528end\
7529\
7530local function pathWithExtension( _sPath, _sExt )\
7531 local nLen = #sPath\
7532 local sEndChar = string.sub( _sPath, nLen, nLen )\
7533 -- Remove any trailing slashes so we can add an extension to the path safely\
7534 if sEndChar == \"/\" or sEndChar == \"\\\\\" then\
7535 _sPath = string.sub( _sPath, 1, nLen - 1 )\
7536 end\
7537 return _sPath .. \".\" .. _sExt\
7538end\
7539\
7540function shell.resolveProgram( _sCommand )\
7541 if type( _sCommand ) ~= \"string\" then\
7542 error( \"bad argument #1 (expected string, got \" .. type( _sCommand ) .. \")\", 2 )\
7543 end\
7544 -- Substitute aliases firsts\
7545 if tAliases[ _sCommand ] ~= nil then\
7546 _sCommand = tAliases[ _sCommand ]\
7547 end\
7548\
7549 -- If the path is a global path, use it directly\
7550 if _sCommand:find(\"/\") or _sCommand:find(\"\\\\\") then\
7551 local sPath = shell.resolve( _sCommand )\
7552 if fs.exists( sPath ) and not fs.isDir( sPath ) then\
7553 return sPath\
7554 else\
7555 local sPathLua = pathWithExtension( sPath, \"lua\" )\
7556 if fs.exists( sPathLua ) and not fs.isDir( sPathLua ) then\
7557 return sPathLua\
7558 end\
7559 end\
7560 return nil\
7561 end\
7562\
7563 -- Otherwise, look on the path variable\
7564 for sPath in string.gmatch(sPath, \"[^:]+\") do\
7565 sPath = fs.combine( shell.resolve( sPath ), _sCommand )\
7566 if fs.exists( sPath ) and not fs.isDir( sPath ) then\
7567 return sPath\
7568 else\
7569 local sPathLua = pathWithExtension( sPath, \"lua\" )\
7570 if fs.exists( sPathLua ) and not fs.isDir( sPathLua ) then\
7571 return sPathLua\
7572 end\
7573 end\
7574 end\
7575\
7576 -- Not found\
7577 return nil\
7578end\
7579\
7580function shell.programs( _bIncludeHidden )\
7581 local tItems = {}\
7582\
7583 -- Add programs from the path\
7584 for sPath in string.gmatch(sPath, \"[^:]+\") do\
7585 sPath = shell.resolve( sPath )\
7586 if fs.isDir( sPath ) then\
7587 local tList = fs.list( sPath )\
7588 for n=1,#tList do\
7589 local sFile = tList[n]\
7590 if not fs.isDir( fs.combine( sPath, sFile ) ) and\
7591 (_bIncludeHidden or string.sub( sFile, 1, 1 ) ~= \".\") then\
7592 if #sFile > 4 and sFile:sub(-4) == \".lua\" then\
7593 sFile = sFile:sub(1,-5)\
7594 end\
7595 tItems[ sFile ] = true\
7596 end\
7597 end\
7598 end\
7599 end\
7600\
7601 -- Sort and return\
7602 local tItemList = {}\
7603 for sItem, b in pairs( tItems ) do\
7604 table.insert( tItemList, sItem )\
7605 end\
7606 table.sort( tItemList )\
7607 return tItemList\
7608end\
7609\
7610local function completeProgram( sLine )\
7611 if #sLine > 0 and (sLine:find(\"/\") or sLine:find(\"\\\\\")) then\
7612 -- Add programs from the root\
7613 return fs.complete( sLine, sDir, true, false )\
7614\
7615 else\
7616 local tResults = {}\
7617 local tSeen = {}\
7618\
7619 -- Add aliases\
7620 for sAlias, sCommand in pairs( tAliases ) do\
7621 if #sAlias > #sLine and string.sub( sAlias, 1, #sLine ) == sLine then\
7622 local sResult = string.sub( sAlias, #sLine + 1 )\
7623 if not tSeen[ sResult ] then\
7624 table.insert( tResults, sResult )\
7625 tSeen[ sResult ] = true\
7626 end\
7627 end\
7628 end\
7629\
7630 -- Add all subdirectories. We don't include files as they will be added in the block below\
7631 local tDirs = fs.complete( sLine, sDir, false, false )\
7632 for i = 1, #tDirs do\
7633 local sResult = tDirs[i]\
7634 if not tSeen[ sResult ] then\
7635 table.insert ( tResults, sResult )\
7636 tSeen [ sResult ] = true\
7637 end\
7638 end\
7639\
7640 -- Add programs from the path\
7641 local tPrograms = shell.programs()\
7642 for n=1,#tPrograms do\
7643 local sProgram = tPrograms[n]\
7644 if #sProgram > #sLine and string.sub( sProgram, 1, #sLine ) == sLine then\
7645 local sResult = string.sub( sProgram, #sLine + 1 )\
7646 if not tSeen[ sResult ] then\
7647 table.insert( tResults, sResult )\
7648 tSeen[ sResult ] = true\
7649 end\
7650 end\
7651 end\
7652\
7653 -- Sort and return\
7654 table.sort( tResults )\
7655 return tResults\
7656 end\
7657end\
7658\
7659local function completeProgramArgument( sProgram, nArgument, sPart, tPreviousParts )\
7660 local tInfo = tCompletionInfo[ sProgram ]\
7661 if tInfo then\
7662 return tInfo.fnComplete( shell, nArgument, sPart, tPreviousParts )\
7663 end\
7664 return nil\
7665end\
7666\
7667function shell.complete( sLine )\
7668 if type( sLine ) ~= \"string\" then\
7669 error( \"bad argument #1 (expected string, got \" .. type( sLine ) .. \")\", 2 )\
7670 end\
7671 if #sLine > 0 then\
7672 local tWords = tokenise( sLine )\
7673 local nIndex = #tWords\
7674 if string.sub( sLine, #sLine, #sLine ) == \" \" then\
7675 nIndex = nIndex + 1\
7676 end\
7677 if nIndex == 1 then\
7678 local sBit = tWords[1] or \"\"\
7679 local sPath = shell.resolveProgram( sBit )\
7680 if tCompletionInfo[ sPath ] then\
7681 return { \" \" }\
7682 else\
7683 local tResults = completeProgram( sBit )\
7684 for n=1,#tResults do\
7685 local sResult = tResults[n]\
7686 local sPath = shell.resolveProgram( sBit .. sResult )\
7687 if tCompletionInfo[ sPath ] then\
7688 tResults[n] = sResult .. \" \"\
7689 end\
7690 end\
7691 return tResults\
7692 end\
7693\
7694 elseif nIndex > 1 then\
7695 local sPath = shell.resolveProgram( tWords[1] )\
7696 local sPart = tWords[nIndex] or \"\"\
7697 local tPreviousParts = tWords\
7698 tPreviousParts[nIndex] = nil\
7699 return completeProgramArgument( sPath , nIndex - 1, sPart, tPreviousParts )\
7700\
7701 end\
7702 end\
7703 return nil\
7704end\
7705\
7706function shell.completeProgram( sProgram )\
7707 if type( sProgram ) ~= \"string\" then\
7708 error( \"bad argument #1 (expected string, got \" .. type( sProgram ) .. \")\", 2 )\
7709 end\
7710 return completeProgram( sProgram )\
7711end\
7712\
7713function shell.setCompletionFunction( sProgram, fnComplete )\
7714 if type( sProgram ) ~= \"string\" then\
7715 error( \"bad argument #1 (expected string, got \" .. type( sProgram ) .. \")\", 2 )\
7716 end\
7717 if type( fnComplete ) ~= \"function\" then\
7718 error( \"bad argument #2 (expected function, got \" .. type( fnComplete ) .. \")\", 2 )\
7719 end\
7720 tCompletionInfo[ sProgram ] = {\
7721 fnComplete = fnComplete\
7722 }\
7723end\
7724\
7725function shell.getCompletionInfo()\
7726 return tCompletionInfo\
7727end\
7728\
7729function shell.getRunningProgram()\
7730 if #tProgramStack > 0 then\
7731 return tProgramStack[#tProgramStack]\
7732 end\
7733 return nil\
7734end\
7735\
7736function shell.setAlias( _sCommand, _sProgram )\
7737 if type( _sCommand ) ~= \"string\" then\
7738 error( \"bad argument #1 (expected string, got \" .. type( _sCommand ) .. \")\", 2 )\
7739 end\
7740 if type( _sProgram ) ~= \"string\" then\
7741 error( \"bad argument #2 (expected string, got \" .. type( _sProgram ) .. \")\", 2 )\
7742 end\
7743 tAliases[ _sCommand ] = _sProgram\
7744end\
7745\
7746function shell.clearAlias( _sCommand )\
7747 if type( _sCommand ) ~= \"string\" then\
7748 error( \"bad argument #1 (expected string, got \" .. type( _sCommand ) .. \")\", 2 )\
7749 end\
7750 tAliases[ _sCommand ] = nil\
7751end\
7752\
7753function shell.aliases()\
7754 -- Copy aliases\
7755 local tCopy = {}\
7756 for sAlias, sCommand in pairs( tAliases ) do\
7757 tCopy[sAlias] = sCommand\
7758 end\
7759 return tCopy\
7760end\
7761\
7762if multishell then\
7763 function shell.openTab( ... )\
7764 local tWords = tokenise( ... )\
7765 local sCommand = tWords[1]\
7766 if sCommand then\
7767 local sPath = shell.resolveProgram( sCommand )\
7768 if sPath == \"rom/programs/shell.lua\" then\
7769 return multishell.launch( createShellEnv( \"rom/programs\" ), sPath, table.unpack( tWords, 2 ) )\
7770 elseif sPath ~= nil then\
7771 return multishell.launch( createShellEnv( \"rom/programs\" ), \"rom/programs/shell.lua\", sCommand, table.unpack( tWords, 2 ) )\
7772 else\
7773 printError( \"No such program\" )\
7774 end\
7775 end\
7776 end\
7777\
7778 function shell.switchTab( nID )\
7779 if type( nID ) ~= \"number\" then\
7780 error( \"bad argument #1 (expected number, got \" .. type( nID ) .. \")\", 2 )\
7781 end\
7782 multishell.setFocus( nID )\
7783 end\
7784end\
7785\
7786local tArgs = { ... }\
7787if #tArgs > 0 then\
7788 -- \"shell x y z\"\
7789 -- Run the program specified on the commandline\
7790 shell.run( ... )\
7791\
7792else\
7793 -- \"shell\"\
7794 -- Print the header\
7795 term.setBackgroundColor( bgColour )\
7796 term.setTextColour( promptColour )\
7797 print( os.version() )\
7798 term.setTextColour( textColour )\
7799\
7800 -- Run the startup program\
7801 if parentShell == nil then\
7802 shell.run( \"/rom/startup.lua\" )\
7803 end\
7804\
7805 -- Read commands and execute them\
7806 local tCommandHistory = {}\
7807 while not bExit do\
7808 term.redirect( parentTerm )\
7809 term.setBackgroundColor( bgColour )\
7810 term.setTextColour( promptColour )\
7811 write( shell.dir() .. \"> \" )\
7812 term.setTextColour( textColour )\
7813\
7814\
7815 local sLine\
7816 if settings.get( \"shell.autocomplete\" ) then\
7817 sLine = read( nil, tCommandHistory, shell.complete )\
7818 else\
7819 sLine = read( nil, tCommandHistory )\
7820 end\
7821 if sLine:match(\"%S\") and tCommandHistory[#tCommandHistory] ~= sLine then\
7822 table.insert( tCommandHistory, sLine )\
7823 end\
7824 shell.run( sLine )\
7825 end\
7826end",
7827 [ "help/colors.txt" ] = "Functions in the colors api\
7828(used for redstone.setBundledOutput):\
7829colors.combine( color1, color2, color3, ... )\
7830colors.subtract( colors, color1, color2, ... )\
7831colors.test( colors, color )\
7832colors.rgb8( r, g, b )\
7833\
7834Color constants in the colors api, in ascending bit order:\
7835colors.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.",
7836 [ "programs/redstone.lua" ] = "\
7837local tArgs = { ... }\
7838\
7839local function printUsage()\
7840 print( \"Usages:\" )\
7841 print( \"redstone probe\" )\
7842 print( \"redstone set <side> <value>\" )\
7843 print( \"redstone set <side> <color> <value>\" )\
7844 print( \"redstone pulse <side> <count> <period>\" )\
7845end\
7846\
7847local sCommand = tArgs[1]\
7848if sCommand == \"probe\" then\
7849 -- \"redstone probe\"\
7850 -- Regular input\
7851 print( \"Redstone inputs: \" )\
7852\
7853 local count = 0\
7854 local bundledCount = 0\
7855 for n,sSide in ipairs( redstone.getSides() ) do\
7856 if redstone.getBundledInput( sSide ) > 0 then\
7857 bundledCount = bundledCount + 1\
7858 end\
7859 if redstone.getInput( sSide ) then\
7860 if count > 0 then\
7861 io.write( \", \" )\
7862 end\
7863 io.write( sSide )\
7864 count = count + 1\
7865 end\
7866 end\
7867 if count > 0 then\
7868 print( \".\" )\
7869 else\
7870 print( \"None.\" )\
7871 end\
7872\
7873 -- Bundled input\
7874 if bundledCount > 0 then\
7875 print()\
7876 print( \"Bundled inputs:\" )\
7877 for i,sSide in ipairs( redstone.getSides() ) do\
7878 local nInput = redstone.getBundledInput( sSide )\
7879 if nInput ~= 0 then\
7880 write( sSide..\": \" )\
7881 local count = 0\
7882 for sColour,nColour in pairs( colors ) do\
7883 if type( nColour ) == \"number\" and colors.test( nInput, nColour ) then\
7884 if count > 0 then\
7885 write( \", \" )\
7886 end\
7887 if term.isColour() then\
7888 term.setTextColour( nColour )\
7889 end\
7890 write( sColour )\
7891 if term.isColour() then\
7892 term.setTextColour( colours.white )\
7893 end\
7894 count = count + 1\
7895 end\
7896 end\
7897 print( \".\" )\
7898 end\
7899 end\
7900 end\
7901\
7902elseif sCommand == \"pulse\" then\
7903 -- \"redstone pulse\"\
7904 local sSide = tArgs[2]\
7905 local nCount = tonumber( tArgs[3] ) or 1\
7906 local nPeriod = tonumber( tArgs[4] ) or 0.5\
7907 for n=1,nCount do\
7908 redstone.setOutput( sSide, true )\
7909 sleep( nPeriod / 2 )\
7910 redstone.setOutput( sSide, false )\
7911 sleep( nPeriod / 2 )\
7912 end\
7913\
7914elseif sCommand == \"set\" then\
7915 -- \"redstone set\"\
7916 local sSide = tArgs[2]\
7917 if #tArgs > 3 then\
7918 -- Bundled cable output\
7919 local sColour = tArgs[3]\
7920 local nColour = colors[sColour] or colours[sColour]\
7921 if type(nColour) ~= \"number\" then\
7922 printError( \"No such color\" )\
7923 return\
7924 end\
7925\
7926 local sValue = tArgs[4]\
7927 if sValue == \"true\" then\
7928 rs.setBundledOutput( sSide, colors.combine( rs.getBundledOutput( sSide ), nColour ) )\
7929 elseif sValue == \"false\" then\
7930 rs.setBundledOutput( sSide, colors.subtract( rs.getBundledOutput( sSide ), nColour ) )\
7931 else\
7932 print( \"Value must be boolean\" )\
7933 end\
7934 else\
7935 -- Regular output\
7936 local sValue = tArgs[3]\
7937 local nValue = tonumber(sValue)\
7938 if sValue == \"true\" then\
7939 rs.setOutput( sSide, true )\
7940 elseif sValue == \"false\" then\
7941 rs.setOutput( sSide, false )\
7942 elseif nValue and nValue >= 0 and nValue <= 15 then\
7943 rs.setAnalogOutput( sSide, nValue )\
7944 else\
7945 print( \"Value must be boolean or 0-15\" )\
7946 end\
7947 end\
7948\
7949else\
7950 -- Something else\
7951 printUsage()\
7952\
7953end",
7954 [ "programs/rednet/repeat.lua" ] = "\
7955-- Find modems\
7956local tModems = {}\
7957for n,sModem in ipairs( peripheral.getNames() ) do\
7958 if peripheral.getType( sModem ) == \"modem\" then\
7959 table.insert( tModems, sModem )\
7960 end\
7961end\
7962if #tModems == 0 then\
7963 print( \"No modems found.\" )\
7964 return\
7965elseif #tModems == 1 then\
7966 print( \"1 modem found.\" )\
7967else\
7968 print( #tModems .. \" modems found.\" )\
7969end\
7970\
7971local function open( nChannel )\
7972 for n=1,#tModems do\
7973 local sModem = tModems[n]\
7974 peripheral.call( sModem, \"open\", nChannel )\
7975 end\
7976end\
7977\
7978local function close( nChannel )\
7979 for n=1,#tModems do\
7980 local sModem = tModems[n]\
7981 peripheral.call( sModem, \"close\", nChannel )\
7982 end\
7983end\
7984\
7985-- Open channels\
7986print( \"0 messages repeated.\" )\
7987open( rednet.CHANNEL_REPEAT )\
7988\
7989-- Main loop (terminate to break)\
7990local ok, error = pcall( function()\
7991 local tReceivedMessages = {}\
7992 local tReceivedMessageTimeouts = {}\
7993 local nTransmittedMessages = 0\
7994\
7995 while true do\
7996 local sEvent, sModem, nChannel, nReplyChannel, tMessage = os.pullEvent()\
7997 if sEvent == \"modem_message\" then\
7998 -- Got a modem message, rebroadcast it if it's a rednet thing\
7999 if nChannel == rednet.CHANNEL_REPEAT then\
8000 if type( tMessage ) == \"table\" and tMessage.nMessageID and tMessage.nRecipient and type(tMessage.nRecipient) == \"number\" then\
8001 if not tReceivedMessages[ tMessage.nMessageID ] then\
8002 -- Ensure we only repeat a message once\
8003 tReceivedMessages[ tMessage.nMessageID ] = true\
8004 tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = tMessage.nMessageID\
8005\
8006 -- Send on all other open modems, to the target and to other repeaters\
8007 for n=1,#tModems do\
8008 local sOtherModem = tModems[n]\
8009 peripheral.call( sOtherModem, \"transmit\", rednet.CHANNEL_REPEAT, nReplyChannel, tMessage )\
8010 peripheral.call( sOtherModem, \"transmit\", tMessage.nRecipient, nReplyChannel, tMessage )\
8011 end\
8012\
8013 -- Log the event\
8014 nTransmittedMessages = nTransmittedMessages + 1\
8015 local x,y = term.getCursorPos()\
8016 term.setCursorPos( 1, y - 1 )\
8017 term.clearLine()\
8018 if nTransmittedMessages == 1 then\
8019 print( nTransmittedMessages .. \" message repeated.\" )\
8020 else\
8021 print( nTransmittedMessages .. \" messages repeated.\" )\
8022 end\
8023 end\
8024 end\
8025 end\
8026\
8027 elseif sEvent == \"timer\" then\
8028 -- Got a timer event, use it to clear the message history\
8029 local nTimer = sModem\
8030 local nMessageID = tReceivedMessageTimeouts[ nTimer ]\
8031 if nMessageID then\
8032 tReceivedMessageTimeouts[ nTimer ] = nil\
8033 tReceivedMessages[ nMessageID ] = nil\
8034 end\
8035\
8036 end\
8037 end\
8038end )\
8039if not ok then\
8040 printError( error )\
8041end\
8042\
8043-- Close channels\
8044close( rednet.CHANNEL_REPEAT )",
8045 [ "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.\
8046\
8047ex:\
8048\"excavate 3\" will mine a 3x3 shaft.",
8049 [ "programs/rednet/chat.lua" ] = "\
8050local tArgs = { ... }\
8051\
8052local function printUsage()\
8053 print( \"Usages:\" )\
8054 print( \"chat host <hostname>\" )\
8055 print( \"chat join <hostname> <nickname>\" )\
8056end\
8057\
8058local sOpenedModem = nil\
8059local function openModem()\
8060 for n,sModem in ipairs( peripheral.getNames() ) do\
8061 if peripheral.getType( sModem ) == \"modem\" then\
8062 if not rednet.isOpen( sModem ) then\
8063 rednet.open( sModem )\
8064 sOpenedModem = sModem\
8065 end\
8066 return true\
8067 end\
8068 end\
8069 print( \"No modems found.\" )\
8070 return false\
8071end\
8072\
8073local function closeModem()\
8074 if sOpenedModem ~= nil then\
8075 rednet.close( sOpenedModem )\
8076 sOpenedModem = nil\
8077 end\
8078end\
8079\
8080-- Colours\
8081local highlightColour, textColour\
8082if term.isColour() then\
8083 textColour = colours.white\
8084 highlightColour = colours.yellow\
8085else\
8086 textColour = colours.white\
8087 highlightColour = colours.white\
8088end\
8089\
8090local sCommand = tArgs[1]\
8091if sCommand == \"host\" then\
8092 -- \"chat host\"\
8093 -- Get hostname\
8094 local sHostname = tArgs[2]\
8095 if sHostname == nil then\
8096 printUsage()\
8097 return\
8098 end\
8099\
8100 -- Host server\
8101 if not openModem() then\
8102 return\
8103 end\
8104 rednet.host( \"chat\", sHostname )\
8105 print( \"0 users connected.\" )\
8106\
8107 local tUsers = {}\
8108 local nUsers = 0\
8109 local function send( sText, nUserID )\
8110 if nUserID then\
8111 local tUser = tUsers[ nUserID ]\
8112 if tUser then\
8113 rednet.send( tUser.nID, {\
8114 sType = \"text\",\
8115 nUserID = nUserID,\
8116 sText = sText,\
8117 }, \"chat\" )\
8118 end\
8119 else\
8120 for nUserID, tUser in pairs( tUsers ) do\
8121 rednet.send( tUser.nID, {\
8122 sType = \"text\",\
8123 nUserID = nUserID,\
8124 sText = sText,\
8125 }, \"chat\" )\
8126 end\
8127 end\
8128 end\
8129\
8130 -- Setup ping pong\
8131 local tPingPongTimer = {}\
8132 local function ping( nUserID )\
8133 local tUser = tUsers[ nUserID ]\
8134 rednet.send( tUser.nID, {\
8135 sType = \"ping to client\",\
8136 nUserID = nUserID,\
8137 }, \"chat\" )\
8138\
8139 local timer = os.startTimer( 15 )\
8140 tUser.bPingPonged = false\
8141 tPingPongTimer[ timer ] = nUserID\
8142 end\
8143\
8144 local function printUsers()\
8145 local x,y = term.getCursorPos()\
8146 term.setCursorPos( 1, y - 1 )\
8147 term.clearLine()\
8148 if nUsers == 1 then\
8149 print( nUsers .. \" user connected.\" )\
8150 else\
8151 print( nUsers .. \" users connected.\" )\
8152 end\
8153 end\
8154\
8155 -- Handle messages\
8156 local ok, error = pcall( function()\
8157 parallel.waitForAny( function()\
8158 while true do\
8159 local sEvent, timer = os.pullEvent( \"timer\" )\
8160 local nUserID = tPingPongTimer[ timer ]\
8161 if nUserID and tUsers[ nUserID ] then\
8162 local tUser = tUsers[ nUserID ]\
8163 if tUser then\
8164 if not tUser.bPingPonged then\
8165 send( \"* \"..tUser.sUsername..\" has timed out\" )\
8166 tUsers[ nUserID ] = nil\
8167 nUsers = nUsers - 1\
8168 printUsers()\
8169 else\
8170 ping( nUserID )\
8171 end\
8172 end\
8173 end\
8174 end\
8175 end,\
8176 function()\
8177 while true do\
8178 local tCommands\
8179 tCommands = {\
8180 [\"me\"] = function( tUser, sContent )\
8181 if string.len(sContent) > 0 then\
8182 send( \"* \"..tUser.sUsername..\" \"..sContent )\
8183 else\
8184 send( \"* Usage: /me [words]\", tUser.nUserID )\
8185 end\
8186 end,\
8187 [\"nick\"] = function( tUser, sContent )\
8188 if string.len(sContent) > 0 then\
8189 local sOldName = tUser.sUsername\
8190 tUser.sUsername = sContent\
8191 send( \"* \"..sOldName..\" is now known as \"..tUser.sUsername )\
8192 else\
8193 send( \"* Usage: /nick [nickname]\", tUser.nUserID )\
8194 end\
8195 end,\
8196 [\"users\"] = function( tUser, sContent )\
8197 send( \"* Connected Users:\", tUser.nUserID )\
8198 local sUsers = \"*\"\
8199 for nUserID, tUser in pairs( tUsers ) do\
8200 sUsers = sUsers .. \" \" .. tUser.sUsername\
8201 end\
8202 send( sUsers, tUser.nUserID )\
8203 end,\
8204 [\"help\"] = function( tUser, sContent )\
8205 send( \"* Available commands:\", tUser.nUserID )\
8206 local sCommands = \"*\"\
8207 for sCommand, fnCommand in pairs( tCommands ) do\
8208 sCommands = sCommands .. \" /\" .. sCommand\
8209 end\
8210 send( sCommands..\" /logout\", tUser.nUserID )\
8211 end,\
8212 }\
8213\
8214 local nSenderID, tMessage = rednet.receive( \"chat\" )\
8215 if type( tMessage ) == \"table\" then\
8216 if tMessage.sType == \"login\" then\
8217 -- Login from new client\
8218 local nUserID = tMessage.nUserID\
8219 local sUsername = tMessage.sUsername\
8220 if nUserID and sUsername then\
8221 tUsers[ nUserID ] = {\
8222 nID = nSenderID,\
8223 nUserID = nUserID,\
8224 sUsername = sUsername,\
8225 }\
8226 nUsers = nUsers + 1\
8227 printUsers()\
8228 send( \"* \"..sUsername..\" has joined the chat\" )\
8229 ping( nUserID )\
8230 end\
8231\
8232 else\
8233 -- Something else from existing client\
8234 local nUserID = tMessage.nUserID\
8235 local tUser = tUsers[ nUserID ]\
8236 if tUser and tUser.nID == nSenderID then\
8237 if tMessage.sType == \"logout\" then\
8238 send( \"* \"..tUser.sUsername..\" has left the chat\" )\
8239 tUsers[ nUserID ] = nil\
8240 nUsers = nUsers - 1\
8241 printUsers()\
8242\
8243 elseif tMessage.sType == \"chat\" then\
8244 local sMessage = tMessage.sText\
8245 if sMessage then\
8246 local sCommand = string.match( sMessage, \"^/([a-z]+)\" )\
8247 if sCommand then\
8248 local fnCommand = tCommands[ sCommand ]\
8249 if fnCommand then\
8250 local sContent = string.sub( sMessage, string.len(sCommand)+3 )\
8251 fnCommand( tUser, sContent )\
8252 else\
8253 send( \"* Unrecognised command: /\"..sCommand, tUser.nUserID )\
8254 end\
8255 else\
8256 send( \"<\"..tUser.sUsername..\"> \"..tMessage.sText )\
8257 end\
8258 end\
8259\
8260 elseif tMessage.sType == \"ping to server\" then\
8261 rednet.send( tUser.nID, {\
8262 sType = \"pong to client\",\
8263 nUserID = nUserID,\
8264 }, \"chat\" )\
8265\
8266 elseif tMessage.sType == \"pong to server\" then\
8267 tUser.bPingPonged = true\
8268\
8269 end\
8270 end\
8271 end\
8272 end\
8273 end\
8274 end )\
8275 end )\
8276 if not ok then\
8277 printError( error )\
8278 end\
8279\
8280 -- Unhost server\
8281 for nUserID, tUser in pairs( tUsers ) do\
8282 rednet.send( tUser.nID, {\
8283 sType = \"kick\",\
8284 nUserID = nUserID,\
8285 }, \"chat\" )\
8286 end\
8287 rednet.unhost( \"chat\" )\
8288 closeModem()\
8289\
8290elseif sCommand == \"join\" then\
8291 -- \"chat join\"\
8292 -- Get hostname and username\
8293 local sHostname = tArgs[2]\
8294 local sUsername = tArgs[3]\
8295 if sHostname == nil or sUsername == nil then\
8296 printUsage()\
8297 return\
8298 end\
8299\
8300 -- Connect\
8301 if not openModem() then\
8302 return\
8303 end\
8304 write( \"Looking up \" .. sHostname .. \"... \" )\
8305 local nHostID = rednet.lookup( \"chat\", sHostname )\
8306 if nHostID == nil then\
8307 print( \"Failed.\" )\
8308 return\
8309 else\
8310 print( \"Success.\" )\
8311 end\
8312\
8313 -- Login\
8314 local nUserID = math.random( 1, 2147483647 )\
8315 rednet.send( nHostID, {\
8316 sType = \"login\",\
8317 nUserID = nUserID,\
8318 sUsername = sUsername,\
8319 }, \"chat\" )\
8320\
8321 -- Setup ping pong\
8322 local bPingPonged = true\
8323 local pingPongTimer = os.startTimer( 0 )\
8324\
8325 local function ping()\
8326 rednet.send( nHostID, {\
8327 sType = \"ping to server\",\
8328 nUserID = nUserID,\
8329 }, \"chat\" )\
8330 bPingPonged = false\
8331 pingPongTimer = os.startTimer( 15 )\
8332 end\
8333\
8334 -- Handle messages\
8335 local w,h = term.getSize()\
8336 local parentTerm = term.current()\
8337 local titleWindow = window.create( parentTerm, 1, 1, w, 1, true )\
8338 local historyWindow = window.create( parentTerm, 1, 2, w, h-2, true )\
8339 local promptWindow = window.create( parentTerm, 1, h, w, 1, true )\
8340 historyWindow.setCursorPos( 1, h-2 )\
8341\
8342 term.clear()\
8343 term.setTextColour( textColour )\
8344 term.redirect( promptWindow )\
8345 promptWindow.restoreCursor()\
8346\
8347 local function drawTitle()\
8348 local x,y = titleWindow.getCursorPos()\
8349 local w,h = titleWindow.getSize()\
8350 local sTitle = sUsername..\" on \"..sHostname\
8351 titleWindow.setTextColour( highlightColour )\
8352 titleWindow.setCursorPos( math.floor( w/2 - string.len(sTitle)/2 ), 1 )\
8353 titleWindow.clearLine()\
8354 titleWindow.write( sTitle )\
8355 promptWindow.restoreCursor()\
8356 end\
8357\
8358 local function printMessage( sMessage )\
8359 term.redirect( historyWindow )\
8360 print()\
8361 if string.match( sMessage, \"^%*\" ) then\
8362 -- Information\
8363 term.setTextColour( highlightColour )\
8364 write( sMessage )\
8365 term.setTextColour( textColour )\
8366 else\
8367 -- Chat\
8368 local sUsernameBit = string.match( sMessage, \"^<[^>]*>\" )\
8369 if sUsernameBit then\
8370 term.setTextColour( highlightColour )\
8371 write( sUsernameBit )\
8372 term.setTextColour( textColour )\
8373 write( string.sub( sMessage, string.len( sUsernameBit ) + 1 ) )\
8374 else\
8375 write( sMessage )\
8376 end\
8377 end\
8378 term.redirect( promptWindow )\
8379 promptWindow.restoreCursor()\
8380 end\
8381\
8382 drawTitle()\
8383\
8384 local ok, error = pcall( function()\
8385 parallel.waitForAny( function()\
8386 while true do\
8387 local sEvent, timer = os.pullEvent()\
8388 if sEvent == \"timer\" then\
8389 if timer == pingPongTimer then\
8390 if not bPingPonged then\
8391 printMessage( \"Server timeout.\" )\
8392 return\
8393 else\
8394 ping()\
8395 end\
8396 end\
8397\
8398 elseif sEvent == \"term_resize\" then\
8399 local w,h = parentTerm.getSize()\
8400 titleWindow.reposition( 1, 1, w, 1 )\
8401 historyWindow.reposition( 1, 2, w, h-2 )\
8402 promptWindow.reposition( 1, h, w, 1 )\
8403\
8404 end\
8405 end\
8406 end,\
8407 function()\
8408 while true do\
8409 local nSenderID, tMessage = rednet.receive( \"chat\" )\
8410 if nSenderID == nHostID and type( tMessage ) == \"table\" and tMessage.nUserID == nUserID then\
8411 if tMessage.sType == \"text\" then\
8412 local sText = tMessage.sText\
8413 if sText then\
8414 printMessage( sText )\
8415 end\
8416\
8417 elseif tMessage.sType == \"ping to client\" then\
8418 rednet.send( nSenderID, {\
8419 sType = \"pong to server\",\
8420 nUserID = nUserID,\
8421 }, \"chat\" )\
8422\
8423 elseif tMessage.sType == \"pong to client\" then\
8424 bPingPonged = true\
8425\
8426 elseif tMessage.sType == \"kick\" then\
8427 return\
8428\
8429 end\
8430 end\
8431 end\
8432 end,\
8433 function()\
8434 local tSendHistory = {}\
8435 while true do\
8436 promptWindow.setCursorPos( 1,1 )\
8437 promptWindow.clearLine()\
8438 promptWindow.setTextColor( highlightColour )\
8439 promptWindow.write( \": \")\
8440 promptWindow.setTextColor( textColour )\
8441\
8442 local sChat = read( nil, tSendHistory )\
8443 if string.match( sChat, \"^/logout\" ) then\
8444 break\
8445 else\
8446 rednet.send( nHostID, {\
8447 sType = \"chat\",\
8448 nUserID = nUserID,\
8449 sText = sChat,\
8450 }, \"chat\" )\
8451 table.insert( tSendHistory, sChat )\
8452 end\
8453 end\
8454 end )\
8455 end )\
8456\
8457 -- Close the windows\
8458 term.redirect( parentTerm )\
8459\
8460 -- Print error notice\
8461 local w,h = term.getSize()\
8462 term.setCursorPos( 1, h )\
8463 term.clearLine()\
8464 term.setCursorBlink( false )\
8465 if not ok then\
8466 printError( error )\
8467 end\
8468\
8469 -- Logout\
8470 rednet.send( nHostID, {\
8471 sType = \"logout\",\
8472 nUserID = nUserID,\
8473 }, \"chat\" )\
8474 closeModem()\
8475\
8476 -- Print disconnection notice\
8477 print( \"Disconnected.\" )\
8478\
8479else\
8480 -- \"chat somethingelse\"\
8481 printUsage()\
8482\
8483end",
8484 [ "programs/reboot.lua" ] = "if term.isColour() then\
8485 term.setTextColour( colours.yellow )\
8486end\
8487print( \"Goodbye\" )\
8488term.setTextColour( colours.white )\
8489\
8490sleep( 1 )\
8491os.reboot()",
8492 [ "help/refuel.txt" ] = "refuel is a program for Turtles. Refuel will consume items from the inventory as fuel for turtle.\
8493\
8494ex:\
8495\"refuel\" will refuel with at most one fuel item\
8496\"refuel 10\" will refuel with at most 10 fuel items\
8497\"refuel all\" will refuel with as many fuel items as possible",
8498 [ "programs/programs.lua" ] = "\
8499local bAll = false\
8500local tArgs = { ... }\
8501if #tArgs > 0 and tArgs[1] == \"all\" then\
8502 bAll = true\
8503end\
8504\
8505local tPrograms = shell.programs( bAll )\
8506textutils.pagedTabulate( tPrograms )",
8507 [ "help/redirection.txt" ] = "Redirection ComputerCraft Edition is the CraftOS version of a fun new puzzle game by Dan200, the author of ComputerCraft.\
8508Play it on any Advanced Computer, then visit http://www.redirectiongame.com to play the full game!",
8509 [ "programs/pocket/unequip.lua" ] = "local ok, err = pocket.unequipBack()\
8510if not ok then\
8511 printError( err )\
8512else\
8513 print( \"Item unequipped\" )\
8514end",
8515 [ "programs/emu.lua" ] = "local args = { ... }\
8516\
8517if ccemux then\
8518 local function help()\
8519 print(\"Usages:\")\
8520 print(\"emu close - close this computer\")\
8521 print(\"emu open [id] - open another computer\")\
8522 print(\"emu data - opens the data folder\")\
8523 print(\"emu config - opens the config editor\")\
8524 --print(\"emu set <setting> <values> - edits a setting\")\
8525 --print(\"emu list settings - list editable settings\")\
8526 --print(\"emu save - saves current settings\")\
8527 print(\"Run 'help emu' for additional information\")\
8528 end\
8529\
8530 if #args == 0 then\
8531 help()\
8532 else\
8533 if args[1] == \"close\" then\
8534 ccemux.closeEmu()\
8535 elseif args[1] == \"open\" then\
8536 print(\"Opened computer ID \" .. ccemux.openEmu(tonumber(args[2])))\
8537 elseif args[1] == \"data\" then\
8538 if ccemux.openDataDir() then\
8539 print(\"Opened data folder\")\
8540 else\
8541 print(\"Unable to open data folder\")\
8542 end\
8543 elseif args[1] == \"config\" then\
8544 local ok, err = ccemux.openConfig()\
8545 if ok then\
8546 print(\"Opened config editor\")\
8547 else\
8548 print(err)\
8549 end\
8550 elseif args[1] == \"set\" then\
8551 if #args <= 1 then\
8552 help()\
8553 else\
8554 if args[2] == \"resolution\" then\
8555 if #args == 4 then\
8556 ccemux.setResolution(tonumber(args[3]), tonumber(args[4]))\
8557 print(\"Set resolution to \" .. args[3] .. \"x\" .. args[4])\
8558 elseif #args == 3 then\
8559 if args[3] == \"computer\" then\
8560 ccemux.setResolution(51, 19)\
8561 print(\"Set resolution to computer (51x19)\")\
8562 elseif args[3] == \"pocket\" then\
8563 ccemux.setResolution(26, 20)\
8564 print(\"Set resolution to pocket (26x20)\")\
8565 elseif args[3] == \"turtle\" then\
8566 ccemux.setResolution(39, 13)\
8567 print(\"Set resolution to turtle (39x13)\")\
8568 end\
8569 else\
8570 printError(\"Usage: emu set resolution <width> <height>\")\
8571 end\
8572 --elseif args[2] == \"scale\" then\
8573\
8574 elseif args[2] == \"cursor\" then\
8575 ccemux.setCursorChar(args[3])\
8576 print(\"Set cursor char to \" .. args[3])\
8577 else\
8578 printError(\"Unrecognized setting: \" .. args[2])\
8579 end\
8580 end\
8581 elseif args[1] == \"list\" then\
8582 if args[2] == \"settings\" then\
8583 print(\"Editable settings:\")\
8584 print(\"resolution <width> <height>\")\
8585 -- not yet implemented\
8586 --print(\"scale <pixels>\")\
8587 print(\"cursor <char>\")\
8588 else\
8589 printError(\"Unrecognized subcommand: \" .. args[2])\
8590 end\
8591 elseif args[1] == \"save\" then\
8592 ccemux.saveSettings()\
8593 print(\"Saved settings\")\
8594 else\
8595 printError(\"Unrecognized subcommand: \" .. args[1])\
8596 help()\
8597 end\
8598 end\
8599else\
8600 printError(\"CCEmuX API is disabled or unavailable.\")\
8601end",
8602 [ "programs/fun/advanced/levels/10.dat" ] = "5\
8603 777 77777\
8604 727777778837\
8605 788888878787\
8606 787777888887\
860777877778777777\
86087e8b7888b888e7\
86097787787b777877\
8610 777887887887\
8611 7487807487\
8612 7777777777",
8613 [ "programs/monitor.lua" ] = "local function printUsage()\
8614 print( \"Usage: monitor <name> <program> <arguments>\" )\
8615 return\
8616end\
8617\
8618local tArgs = { ... }\
8619if #tArgs < 2 then\
8620 printUsage()\
8621 return\
8622end\
8623\
8624local sName = tArgs[1]\
8625if peripheral.getType( sName ) ~= \"monitor\" then\
8626 print( \"No monitor named \".. sName )\
8627 return\
8628end\
8629\
8630local sProgram = tArgs[2]\
8631local sPath = shell.resolveProgram( sProgram )\
8632if sPath == nil then\
8633 print( \"No such program: \"..sProgram )\
8634 return\
8635end\
8636\
8637print( \"Running \"..sProgram..\" on monitor \"..sName )\
8638\
8639local monitor = peripheral.wrap( sName )\
8640local previousTerm = term.redirect( monitor )\
8641\
8642local co = coroutine.create( function()\
8643 shell.run( sProgram, table.unpack( tArgs, 3 ) )\
8644end )\
8645\
8646local function resume( ... )\
8647 local ok, param = coroutine.resume( co, ... )\
8648 if not ok then\
8649 printError( param )\
8650 end\
8651 return param\
8652end\
8653\
8654local ok, param = pcall( function()\
8655 local sFilter = resume()\
8656 while coroutine.status( co ) ~= \"dead\" do\
8657 local tEvent = table.pack( os.pullEventRaw() )\
8658 if sFilter == nil or tEvent[1] == sFilter or tEvent[1] == \"terminate\" then\
8659 sFilter = resume( table.unpack( tEvent, 1, tEvent.n ) )\
8660 end\
8661 if coroutine.status( co ) ~= \"dead\" and (sFilter == nil or sFilter == \"mouse_click\") then\
8662 if tEvent[1] == \"monitor_touch\" and tEvent[2] == sName then\
8663 sFilter = resume( \"mouse_click\", 1, table.unpack( tEvent, 3, tEvent.n ) )\
8664 end\
8665 end\
8666 if coroutine.status( co ) ~= \"dead\" and (sFilter == nil or sFilter == \"term_resize\") then\
8667 if tEvent[1] == \"monitor_resize\" and tEvent[2] == sName then\
8668 sFilter = resume( \"term_resize\" )\
8669 end\
8670 end\
8671 end\
8672end )\
8673\
8674term.redirect( previousTerm )\
8675if not ok then\
8676 printError( param )\
8677end",
8678 [ "apis/term.lua" ] = "\
8679local native = (term.native and term.native()) or term\
8680local redirectTarget = native\
8681\
8682local function wrap( _sFunction )\
8683 return function( ... )\
8684 return redirectTarget[ _sFunction ]( ... )\
8685 end\
8686end\
8687\
8688local term = {}\
8689\
8690term.redirect = function( target )\
8691 if type( target ) ~= \"table\" then\
8692 error( \"bad argument #1 (expected table, got \" .. type( target ) .. \")\", 2 )\
8693 end\
8694 if target == term then\
8695 error( \"term is not a recommended redirect target, try term.current() instead\", 2 )\
8696 end\
8697 for k,v in pairs( native ) do\
8698 if type( k ) == \"string\" and type( v ) == \"function\" then\
8699 if type( target[k] ) ~= \"function\" then\
8700 target[k] = function()\
8701 error( \"Redirect object is missing method \"..k..\".\", 2 )\
8702 end\
8703 end\
8704 end\
8705 end\
8706 local oldRedirectTarget = redirectTarget\
8707 redirectTarget = target\
8708 return oldRedirectTarget\
8709end\
8710\
8711term.current = function()\
8712 return redirectTarget\
8713end\
8714\
8715term.native = function()\
8716 -- NOTE: please don't use this function unless you have to.\
8717 -- If you're running in a redirected or multitasked enviorment, term.native() will NOT be\
8718 -- the current terminal when your program starts up. It is far better to use term.current()\
8719 return native\
8720end\
8721\
8722-- Some methods shouldn't go through redirects, so we move them to the main\
8723-- term API.\
8724for _, method in ipairs { \"nativePaletteColor\", \"nativePaletteColour\"} do\
8725 term[method] = native[method]\
8726 native[method] = nil\
8727end\
8728\
8729for k,v in pairs( native ) do\
8730 if type( k ) == \"string\" and type( v ) == \"function\" and term[k] == nil then\
8731 term[k] = wrap( k )\
8732 end\
8733end\
8734\
8735local env = _ENV\
8736for k,v in pairs( term ) do\
8737 env[k] = v\
8738end",
8739 [ "help/fs.txt" ] = "Functions in the Filesystem API:\
8740fs.list( path )\
8741fs.find( wildcard )\
8742fs.exists( path )\
8743fs.isDir( path )\
8744fs.isReadOnly( path )\
8745fs.getDir( path )\
8746fs.getName( path )\
8747fs.getSize( path )\
8748fs.getDrive( path )\
8749fs.getFreeSpace( path )\
8750fs.makeDir( path )\
8751fs.move( path, path )\
8752fs.copy( path, path )\
8753fs.delete( path )\
8754fs.combine( path, localpath )\
8755fs.open( path, mode )\
8756fs.complete( path, location )\
8757Available fs.open() modes are \"r\", \"w\", \"a\", \"rb\", \"wb\" and \"ab\".\
8758\
8759Functions on files opened with mode \"r\":\
8760readLine()\
8761readAll()\
8762close()\
8763read( number )\
8764\
8765Functions on files opened with mode \"w\" or \"a\":\
8766write( string )\
8767writeLine( string )\
8768flush()\
8769close()\
8770\
8771Functions on files opened with mode \"rb\":\
8772read()\
8773close()\
8774\
8775Functions on files opened with mode \"wb\" or \"ab\":\
8776write( byte )\
8777flush()\
8778close()",
8779 [ "programs/lua.lua" ] = "\
8780local tArgs = { ... }\
8781if #tArgs > 0 then\
8782 print( \"This is an interactive Lua prompt.\" )\
8783 print( \"To run a lua program, just type its name.\" )\
8784 return\
8785end\
8786\
8787local bRunning = true\
8788local tCommandHistory = {}\
8789local tEnv = {\
8790 [\"exit\"] = function()\
8791 bRunning = false\
8792 end,\
8793 [\"_echo\"] = function( ... )\
8794 return ...\
8795 end,\
8796}\
8797setmetatable( tEnv, { __index = _ENV } )\
8798\
8799if term.isColour() then\
8800 term.setTextColour( colours.yellow )\
8801end\
8802print( \"Interactive Lua prompt.\" )\
8803print( \"Call exit() to exit.\" )\
8804term.setTextColour( colours.white )\
8805\
8806while bRunning do\
8807 --if term.isColour() then\
8808 -- term.setTextColour( colours.yellow )\
8809 --end\
8810 write( \"lua> \" )\
8811 --term.setTextColour( colours.white )\
8812\
8813 local s = read( nil, tCommandHistory, function( sLine )\
8814 if settings.get( \"lua.autocomplete\" ) then\
8815 local nStartPos = string.find( sLine, \"[a-zA-Z0-9_%.:]+$\" )\
8816 if nStartPos then\
8817 sLine = string.sub( sLine, nStartPos )\
8818 end\
8819 if #sLine > 0 then\
8820 return textutils.complete( sLine, tEnv )\
8821 end\
8822 end\
8823 return nil\
8824 end )\
8825 if s:match(\"%S\") and tCommandHistory[#tCommandHistory] ~= s then\
8826 table.insert( tCommandHistory, s )\
8827 end\
8828\
8829 local nForcePrint = 0\
8830 local func, e = load( s, \"=lua\", \"t\", tEnv )\
8831 local func2, e2 = load( \"return _echo(\"..s..\");\", \"=lua\", \"t\", tEnv )\
8832 if not func then\
8833 if func2 then\
8834 func = func2\
8835 e = nil\
8836 nForcePrint = 1\
8837 end\
8838 else\
8839 if func2 then\
8840 func = func2\
8841 end\
8842 end\
8843\
8844 if func then\
8845 local tResults = table.pack( pcall( func ) )\
8846 if tResults[1] then\
8847 local n = 1\
8848 while n < tResults.n or (n <= nForcePrint) do\
8849 local value = tResults[ n + 1 ]\
8850 if type( value ) == \"table\" then\
8851 local metatable = getmetatable( value )\
8852 if type(metatable) == \"table\" and type(metatable.__tostring) == \"function\" then\
8853 print( tostring( value ) )\
8854 else\
8855 local ok, serialised = pcall( textutils.serialise, value )\
8856 if ok then\
8857 print( serialised )\
8858 else\
8859 print( tostring( value ) )\
8860 end\
8861 end\
8862 else\
8863 print( tostring( value ) )\
8864 end\
8865 n = n + 1\
8866 end\
8867 else\
8868 printError( tResults[2] )\
8869 end\
8870 else\
8871 printError( e )\
8872 end\
8873\
8874end",
8875 [ "programs/fun/advanced/levels/11.dat" ] = "4\
8876 777777777\
8877 727872787\
8878 787878787\
8879777787878787777\
88807be888888888be7\
8881777787878787777\
8882 787878787\
8883 787478747\
8884 777777777",
8885 [ "help/copy.txt" ] = "cp copies a file or directory from one location to another.\
8886\
8887ex:\
8888\"cp rom myrom\" copies \"rom\" to \"myrom\".\
8889\"cp rom mystuff/rom\" copies \"rom\" to \"mystuff/rom\".\
8890\"cp disk/* disk2\" copies the contents of one disk to another",
8891 [ "help/delete.txt" ] = "rm deletes a file or a directory and its contents.\
8892\
8893ex:\
8894\"rm foo\" will delete the file foo.\
8895\"rm disk/*\" will delete the contents of a disk.",
8896 [ "programs/advanced/fg.lua" ] = "\
8897if not shell.openTab then\
8898 printError( \"Requires multishell\" )\
8899 return\
8900end\
8901\
8902local tArgs = { ... }\
8903if #tArgs > 0 then\
8904 local nTask = shell.openTab( table.unpack( tArgs ) )\
8905 if nTask then\
8906 shell.switchTab( nTask )\
8907 end\
8908else\
8909 local nTask = shell.openTab( \"shell\" )\
8910 if nTask then\
8911 shell.switchTab( nTask )\
8912 end\
8913end",
8914 [ "programs/apis.lua" ] = "\
8915local tApis = {}\
8916for k,v in pairs( _G ) do\
8917 if type(k) == \"string\" and type(v) == \"table\" and k ~= \"_G\" then\
8918 table.insert( tApis, k )\
8919 end\
8920end\
8921table.insert( tApis, \"shell\" )\
8922table.insert( tApis, \"package\" )\
8923if multishell then\
8924 table.insert( tApis, \"multishell\" )\
8925end\
8926table.sort( tApis )\
8927\
8928textutils.pagedTabulate( tApis )",
8929 [ "programs/label.lua" ] = "\
8930local function printUsage()\
8931 print( \"Usages:\" )\
8932 print( \"label get\" )\
8933 print( \"label get <drive>\" )\
8934 print( \"label set <text>\" )\
8935 print( \"label set <drive> <text>\" )\
8936 print( \"label clear\" )\
8937 print( \"label clear <drive>\" )\
8938end\
8939\
8940local function checkDrive( sDrive )\
8941 if peripheral.getType( sDrive ) == \"drive\" then\
8942 -- Check the disk exists\
8943 local bData = disk.hasData( sDrive )\
8944 if not bData then\
8945 print( \"No disk in \"..sDrive..\" drive\" )\
8946 return false\
8947 end\
8948 else\
8949 print( \"No disk drive named \"..sDrive )\
8950 return false\
8951 end\
8952 return true\
8953end\
8954\
8955local function get( sDrive )\
8956 if sDrive ~= nil then\
8957 if checkDrive( sDrive ) then\
8958 local sLabel = disk.getLabel( sDrive )\
8959 if sLabel then\
8960 print( \"Disk label is \\\"\"..sLabel..\"\\\"\" )\
8961 else\
8962 print( \"No Disk label\" )\
8963 end\
8964 end\
8965 else\
8966 local sLabel = os.getComputerLabel()\
8967 if sLabel then\
8968 print( \"Computer label is \\\"\"..sLabel..\"\\\"\" )\
8969 else\
8970 print( \"No Computer label\" )\
8971 end\
8972 end\
8973end\
8974\
8975local function set( sDrive, sText )\
8976 if sDrive ~= nil then\
8977 if checkDrive( sDrive ) then\
8978 disk.setLabel( sDrive, sText )\
8979 local sLabel = disk.getLabel( sDrive )\
8980 if sLabel then\
8981 print( \"Disk label set to \\\"\"..sLabel..\"\\\"\" )\
8982 else\
8983 print( \"Disk label cleared\" )\
8984 end\
8985 end\
8986 else\
8987 os.setComputerLabel( sText )\
8988 local sLabel = os.getComputerLabel()\
8989 if sLabel then\
8990 print( \"Computer label set to \\\"\"..sLabel..\"\\\"\" )\
8991 else\
8992 print( \"Computer label cleared\" )\
8993 end\
8994 end\
8995end\
8996\
8997local tArgs = { ... }\
8998local sCommand = tArgs[1]\
8999if sCommand == \"get\" then\
9000 -- Get a label\
9001 if #tArgs == 1 then\
9002 get( nil )\
9003 elseif #tArgs == 2 then\
9004 get( tArgs[2] )\
9005 else\
9006 printUsage()\
9007 end\
9008elseif sCommand == \"set\" then\
9009 -- Set a label\
9010 if #tArgs == 2 then\
9011 set( nil, tArgs[2] )\
9012 elseif #tArgs == 3 then\
9013 set( tArgs[2], tArgs[3] )\
9014 else\
9015 printUsage()\
9016 end\
9017elseif sCommand == \"clear\" then\
9018 -- Clear a label\
9019 if #tArgs == 1 then\
9020 set( nil, nil )\
9021 elseif #tArgs == 2 then\
9022 set( tArgs[2], nil )\
9023 else\
9024 printUsage()\
9025 end\
9026else\
9027 printUsage()\
9028end",
9029 [ "programs/id.lua" ] = "\
9030local sDrive = nil\
9031local tArgs = { ... }\
9032if #tArgs > 0 then\
9033 sDrive = tostring( tArgs[1] )\
9034end\
9035\
9036if sDrive == nil then\
9037 print( \"This is computer #\"..os.getComputerID() )\
9038\
9039 local label = os.getComputerLabel()\
9040 if label then\
9041 print( \"This computer is labelled \\\"\"..label..\"\\\"\" )\
9042 end\
9043\
9044else\
9045 local bData = disk.hasData( sDrive )\
9046 if not bData then\
9047 print( \"No disk in drive \"..sDrive )\
9048 return\
9049 end\
9050\
9051 print( \"The disk is #\"..disk.getID( sDrive ) )\
9052\
9053 local label = disk.getLabel( sDrive )\
9054 if label then\
9055 print( \"The disk is labelled \\\"\"..label..\"\\\"\" )\
9056 end\
9057end",
9058 [ "programs/http/pastebin.lua" ] = "\
9059local function printUsage()\
9060 print( \"Usages:\" )\
9061 print( \"pastebin put <filename>\" )\
9062 print( \"pastebin get <code> <filename>\" )\
9063 print( \"pastebin run <code> <arguments>\" )\
9064end\
9065\
9066local tArgs = { ... }\
9067if #tArgs < 2 then\
9068 printUsage()\
9069 return\
9070end\
9071\
9072if not http then\
9073 printError( \"Pastebin requires http API\" )\
9074 printError( \"Set http_enable to true in ComputerCraft.cfg\" )\
9075 return\
9076end\
9077\
9078--- Attempts to guess the pastebin ID from the given code or URL\
9079local function extractId(paste)\
9080 local patterns = {\
9081 \"^([%a%d]+)$\",\
9082 \"^https?://pastebin.com/([%a%d]+)$\",\
9083 \"^pastebin.com/([%a%d]+)$\",\
9084 \"^https?://pastebin.com/raw/([%a%d]+)$\",\
9085 \"^pastebin.com/raw/([%a%d]+)$\",\
9086 }\
9087\
9088 for i = 1, #patterns do\
9089 local code = paste:match( patterns[i] )\
9090 if code then return code end\
9091 end\
9092\
9093 return nil\
9094end\
9095\
9096local function get(url)\
9097 local paste = extractId( url )\
9098 if not paste then\
9099 io.stderr:write( \"Invalid pastebin code.\\n\" )\
9100 io.write( \"The code is the ID at the end of the pastebin.com URL.\\n\" )\
9101 return\
9102 end\
9103\
9104 write( \"Connecting to pastebin.com... \" )\
9105 -- Add a cache buster so that spam protection is re-checked\
9106 local cacheBuster = (\"%x\"):format(math.random(0, 2^30))\
9107 local response, err = http.get(\
9108 \"https://pastebin.com/raw/\"..textutils.urlEncode( paste )..\"?cb=\"..cacheBuster\
9109 )\
9110\
9111 if response then\
9112 -- If spam protection is activated, we get redirected to /paste with Content-Type: text/html\
9113 local headers = response.getResponseHeaders()\
9114 if not headers[\"Content-Type\"] or not headers[\"Content-Type\"]:find( \"^text/plain\" ) then\
9115 io.stderr:write( \"Failed.\\n\" )\
9116 print( \"Pastebin blocked the download due to spam protection. Please complete the captcha in a web browser: https://pastebin.com/\" .. textutils.urlEncode( paste ) )\
9117 return\
9118 end\
9119\
9120 print( \"Success.\" )\
9121\
9122 local sResponse = response.readAll()\
9123 response.close()\
9124 return sResponse\
9125 else\
9126 io.stderr:write( \"Failed.\\n\" )\
9127 print(err)\
9128 end\
9129end\
9130\
9131local sCommand = tArgs[1]\
9132if sCommand == \"put\" then\
9133 -- Upload a file to pastebin.com\
9134 -- Determine file to upload\
9135 local sFile = tArgs[2]\
9136 local sPath = shell.resolve( sFile )\
9137 if not fs.exists( sPath ) or fs.isDir( sPath ) then\
9138 print( \"No such file\" )\
9139 return\
9140 end\
9141\
9142 -- Read in the file\
9143 local sName = fs.getName( sPath )\
9144 local file = fs.open( sPath, \"r\" )\
9145 local sText = file.readAll()\
9146 file.close()\
9147\
9148 -- POST the contents to pastebin\
9149 write( \"Connecting to pastebin.com... \" )\
9150 local key = \"0ec2eb25b6166c0c27a394ae118ad829\"\
9151 local response = http.post(\
9152 \"https://pastebin.com/api/api_post.php\",\
9153 \"api_option=paste&\"..\
9154 \"api_dev_key=\"..key..\"&\"..\
9155 \"api_paste_format=lua&\"..\
9156 \"api_paste_name=\"..textutils.urlEncode(sName)..\"&\"..\
9157 \"api_paste_code=\"..textutils.urlEncode(sText)\
9158 )\
9159\
9160 if response then\
9161 print( \"Success.\" )\
9162\
9163 local sResponse = response.readAll()\
9164 response.close()\
9165\
9166 local sCode = string.match( sResponse, \"[^/]+$\" )\
9167 print( \"Uploaded as \"..sResponse )\
9168 print( \"Run \\\"pastebin get \"..sCode..\"\\\" to download anywhere\" )\
9169\
9170 else\
9171 print( \"Failed.\" )\
9172 end\
9173\
9174elseif sCommand == \"get\" then\
9175 -- Download a file from pastebin.com\
9176 if #tArgs < 3 then\
9177 printUsage()\
9178 return\
9179 end\
9180\
9181 -- Determine file to download\
9182 local sCode = tArgs[2]\
9183 local sFile = tArgs[3]\
9184 local sPath = shell.resolve( sFile )\
9185 if fs.exists( sPath ) then\
9186 print( \"File already exists\" )\
9187 return\
9188 end\
9189\
9190 -- GET the contents from pastebin\
9191 local res = get(sCode)\
9192 if res then\
9193 local file = fs.open( sPath, \"w\" )\
9194 file.write( res )\
9195 file.close()\
9196\
9197 print( \"Downloaded as \"..sFile )\
9198 end\
9199elseif sCommand == \"run\" then\
9200 local sCode = tArgs[2]\
9201\
9202 local res = get(sCode)\
9203 if res then\
9204 local func, err = load(res, sCode, \"t\", _ENV)\
9205 if not func then\
9206 printError( err )\
9207 return\
9208 end\
9209 local success, msg = pcall(func, select(3, ...))\
9210 if not success then\
9211 printError( msg )\
9212 end\
9213 end\
9214else\
9215 printUsage()\
9216 return\
9217end",
9218 [ "help/programs.txt" ] = "programs lists all the programs on the rom of the computer.",
9219 [ "programs/peripherals.lua" ] = "local tPeripherals = peripheral.getNames()\
9220print( \"Attached Peripherals:\" )\
9221if #tPeripherals > 0 then\
9222 for n=1,#tPeripherals do\
9223 local sPeripheral = tPeripherals[n]\
9224 print( sPeripheral .. \" (\" .. peripheral.getType( sPeripheral ) .. \")\" )\
9225 end\
9226else\
9227 print( \"None\" )\
9228end",
9229 [ "programs/fun/advanced/levels/2.dat" ] = "1\
9230777777777\
92317888888b7\
9232787778887\
9233787 78777\
92347877787\
92357888887\
92367777787\
9237 707\
9238 777",
9239 [ "programs/fun/worm.lua" ] = "\
9240-- Display the start screen\
9241local w,h = term.getSize()\
9242\
9243local titleColour, headingColour, textColour, wormColour, fruitColour\
9244if term.isColour() then\
9245 titleColour = colours.red\
9246 headingColour = colours.yellow\
9247 textColour = colours.white\
9248 wormColour = colours.green\
9249 fruitColour = colours.red\
9250else\
9251 titleColour = colours.white\
9252 headingColour = colours.white\
9253 textColour = colours.white\
9254 wormColour = colours.white\
9255 fruitColour = colours.white\
9256end\
9257\
9258local function printCentred( y, s )\
9259 local x = math.floor((w - string.len(s)) / 2)\
9260 term.setCursorPos(x,y)\
9261 --term.clearLine()\
9262 term.write( s )\
9263end\
9264\
9265local xVel,yVel = 1,0\
9266local xPos, yPos = math.floor(w/2), math.floor(h/2)\
9267local pxVel, pyVel = nil, nil\
9268\
9269local nLength = 1\
9270local nExtraLength = 6\
9271local bRunning = true\
9272\
9273local tailX,tailY = xPos,yPos\
9274local nScore = 0\
9275local nDifficulty = 2\
9276local nSpeed, nInterval\
9277\
9278-- Setup the screen\
9279local screen = {}\
9280for x=1,w do\
9281 screen[x] = {}\
9282 for y=1,h do\
9283 screen[x][y] = {}\
9284 end\
9285end\
9286screen[xPos][yPos] = { snake = true }\
9287\
9288local nFruit = 1\
9289local tFruits = {\
9290 \"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\",\
9291 \"I\", \"J\", \"K\", \"L\", \"M\", \"N\", \"O\", \"P\",\
9292 \"Q\", \"R\", \"S\", \"T\", \"U\", \"V\", \"W\", \"X\",\
9293 \"Y\", \"Z\",\
9294 \"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\",\
9295 \"i\", \"j\", \"k\", \"l\", \"m\", \"n\", \"o\", \"p\",\
9296 \"q\", \"r\", \"s\", \"t\", \"u\", \"v\", \"w\", \"x\",\
9297 \"y\", \"z\",\
9298 \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"0\",\
9299 \"@\", \"$\", \"%\", \"#\", \"&\", \"!\", \"?\", \"+\", \"*\", \"~\"\
9300}\
9301\
9302local function addFruit()\
9303 while true do\
9304 local x = math.random(1,w)\
9305 local y = math.random(2,h)\
9306 local fruit = screen[x][y]\
9307 if fruit.snake == nil and fruit.wall == nil and fruit.fruit == nil then\
9308 screen[x][y] = { fruit = true }\
9309 term.setCursorPos(x,y)\
9310 term.setBackgroundColour( fruitColour )\
9311 term.write(\" \")\
9312 term.setBackgroundColour( colours.black )\
9313 break\
9314 end\
9315 end\
9316\
9317 nFruit = nFruit + 1\
9318 if nFruit > #tFruits then\
9319 nFruit = 1\
9320 end\
9321end\
9322\
9323local function drawMenu()\
9324 term.setTextColour( headingColour )\
9325 term.setCursorPos(1,1)\
9326 term.write( \"SCORE \" )\
9327\
9328 term.setTextColour( textColour )\
9329 term.setCursorPos(7,1)\
9330 term.write( tostring(nScore) )\
9331\
9332 term.setTextColour( headingColour )\
9333 term.setCursorPos(w-11,1)\
9334 term.write( \"DIFFICULTY \")\
9335\
9336 term.setTextColour( textColour )\
9337 term.setCursorPos(w,1)\
9338 term.write( tostring(nDifficulty or \"?\") )\
9339\
9340 term.setTextColour( colours.white )\
9341end\
9342\
9343local function update( )\
9344 local x,y = xPos,yPos\
9345 if pxVel and pyVel then\
9346 xVel, yVel = pxVel, pyVel\
9347 pxVel, pyVel = nil, nil\
9348 end\
9349\
9350 -- Remove the tail\
9351 if nExtraLength == 0 then\
9352 local tail = screen[tailX][tailY]\
9353 screen[tailX][tailY] = {}\
9354 term.setCursorPos(tailX,tailY)\
9355 term.write(\" \")\
9356 tailX = tail.nextX\
9357 tailY = tail.nextY\
9358 else\
9359 nExtraLength = nExtraLength - 1\
9360 end\
9361\
9362 -- Update the head\
9363 local head = screen[xPos][yPos]\
9364 local newXPos = xPos + xVel\
9365 local newYPos = yPos + yVel\
9366 if newXPos < 1 then\
9367 newXPos = w\
9368 elseif newXPos > w then\
9369 newXPos = 1\
9370 end\
9371 if newYPos < 2 then\
9372 newYPos = h\
9373 elseif newYPos > h then\
9374 newYPos = 2\
9375 end\
9376\
9377 local newHead = screen[newXPos][newYPos]\
9378 if newHead.snake == true or newHead.wall == true then\
9379 bRunning = false\
9380\
9381 else\
9382 if newHead.fruit == true then\
9383 nScore = nScore + 10\
9384 nExtraLength = nExtraLength + 1\
9385 addFruit()\
9386 end\
9387 xPos = newXPos\
9388 yPos = newYPos\
9389 head.nextX = newXPos\
9390 head.nextY = newYPos\
9391 screen[newXPos][newYPos] = { snake = true }\
9392\
9393 end\
9394\
9395 term.setCursorPos(xPos,yPos)\
9396 term.setBackgroundColour( wormColour )\
9397 term.write(\" \")\
9398 term.setBackgroundColour( colours.black )\
9399\
9400 drawMenu()\
9401end\
9402\
9403-- Display the frontend\
9404term.clear()\
9405local function drawFrontend()\
9406 --term.setTextColour( titleColour )\
9407 --printCentred( math.floor(h/2) - 4, \" W O R M \" )\
9408\
9409 term.setTextColour( headingColour )\
9410 printCentred( math.floor(h/2) - 3, \"\" )\
9411 printCentred( math.floor(h/2) - 2, \" SELECT DIFFICULTY \" )\
9412 printCentred( math.floor(h/2) - 1, \"\" )\
9413\
9414 printCentred( math.floor(h/2) + 0, \" \" )\
9415 printCentred( math.floor(h/2) + 1, \" \" )\
9416 printCentred( math.floor(h/2) + 2, \" \" )\
9417 printCentred( math.floor(h/2) - 1 + nDifficulty, \" [ ] \" )\
9418\
9419 term.setTextColour( textColour )\
9420 printCentred( math.floor(h/2) + 0, \"EASY\" )\
9421 printCentred( math.floor(h/2) + 1, \"MEDIUM\" )\
9422 printCentred( math.floor(h/2) + 2, \"HARD\" )\
9423 printCentred( math.floor(h/2) + 3, \"\" )\
9424\
9425 term.setTextColour( colours.white )\
9426end\
9427\
9428drawMenu()\
9429drawFrontend()\
9430while true do\
9431 local e,key = os.pullEvent( \"key\" )\
9432 if key == keys.up or key == keys.w then\
9433 -- Up\
9434 if nDifficulty > 1 then\
9435 nDifficulty = nDifficulty - 1\
9436 drawMenu()\
9437 drawFrontend()\
9438 end\
9439 elseif key == keys.down or key == keys.s then\
9440 -- Down\
9441 if nDifficulty < 3 then\
9442 nDifficulty = nDifficulty + 1\
9443 drawMenu()\
9444 drawFrontend()\
9445 end\
9446 elseif key == keys.enter then\
9447 -- Enter\
9448 break\
9449 end\
9450end\
9451\
9452local tSpeeds = { 5, 10, 25 }\
9453nSpeed = tSpeeds[nDifficulty]\
9454nInterval = 1 / nSpeed\
9455\
9456-- Grow the snake to its intended size\
9457term.clear()\
9458drawMenu()\
9459screen[tailX][tailY].snake = true\
9460while nExtraLength > 0 do\
9461 update()\
9462end\
9463addFruit()\
9464addFruit()\
9465\
9466-- Play the game\
9467local timer = os.startTimer(0)\
9468while bRunning do\
9469 local event, p1, p2 = os.pullEvent()\
9470 if event == \"timer\" and p1 == timer then\
9471 timer = os.startTimer(nInterval)\
9472 update( false )\
9473\
9474 elseif event == \"key\" then\
9475 local key = p1\
9476 if key == keys.up or key == keys.w then\
9477 -- Up\
9478 if yVel == 0 then\
9479 pxVel,pyVel = 0,-1\
9480 end\
9481 elseif key == keys.down or key == keys.s then\
9482 -- Down\
9483 if yVel == 0 then\
9484 pxVel,pyVel = 0,1\
9485 end\
9486 elseif key == keys.left or key == keys.a then\
9487 -- Left\
9488 if xVel == 0 then\
9489 pxVel,pyVel = -1,0\
9490 end\
9491\
9492 elseif key == keys.right or key == keys.d then\
9493 -- Right\
9494 if xVel == 0 then\
9495 pxVel,pyVel = 1,0\
9496 end\
9497\
9498 end\
9499 end\
9500end\
9501\
9502-- Display the gameover screen\
9503term.setTextColour( headingColour )\
9504printCentred( math.floor(h/2) - 2, \" \" )\
9505printCentred( math.floor(h/2) - 1, \" G A M E O V E R \" )\
9506\
9507term.setTextColour( textColour )\
9508printCentred( math.floor(h/2) + 0, \" \" )\
9509printCentred( math.floor(h/2) + 1, \" FINAL SCORE \"..nScore..\" \" )\
9510printCentred( math.floor(h/2) + 2, \" \" )\
9511term.setTextColour( colours.white )\
9512\
9513local timer = os.startTimer(2.5)\
9514repeat\
9515 local e,p = os.pullEvent()\
9516 if e == \"timer\" and p == timer then\
9517 term.setTextColour( textColour )\
9518 printCentred( math.floor(h/2) + 2, \" PRESS ANY KEY \" )\
9519 printCentred( math.floor(h/2) + 3, \" \" )\
9520 term.setTextColour( colours.white )\
9521 end\
9522until e == \"char\"\
9523\
9524term.clear()\
9525term.setCursorPos(1,1)",
9526 [ "programs/fun/hello.lua" ] = "if term.isColour() then\
9527 term.setTextColour( 2^math.random(0,15) )\
9528end\
9529textutils.slowPrint( \"Hello World!\" )\
9530term.setTextColour( colours.white )",
9531 [ "programs/fun/dj.lua" ] = "local tArgs = { ... }\
9532\
9533local function printUsage()\
9534 print( \"Usages:\")\
9535 print( \"dj play\" )\
9536 print( \"dj play <drive>\" )\
9537 print( \"dj stop\" )\
9538end\
9539\
9540if #tArgs > 2 then\
9541 printUsage()\
9542 return\
9543end\
9544\
9545local sCommand = tArgs[1]\
9546if sCommand == \"stop\" then\
9547 -- Stop audio\
9548 disk.stopAudio()\
9549\
9550elseif sCommand == \"play\" or sCommand == nil then\
9551 -- Play audio\
9552 local sName = tArgs[2]\
9553 if sName == nil then\
9554 -- No disc specified, pick one at random\
9555 local tNames = {}\
9556 for n,sName in ipairs( peripheral.getNames() ) do\
9557 if disk.isPresent( sName ) and disk.hasAudio( sName ) then\
9558 table.insert( tNames, sName )\
9559 end\
9560 end\
9561 if #tNames == 0 then\
9562 print( \"No Music Discs in attached disk drives\" )\
9563 return\
9564 end\
9565 sName = tNames[ math.random(1,#tNames) ]\
9566 end\
9567\
9568 -- Play the disc\
9569 if disk.isPresent( sName ) and disk.hasAudio( sName ) then\
9570 print( \"Playing \"..disk.getAudioTitle( sName ) )\
9571 disk.playAudio( sName )\
9572 else\
9573 print( \"No Music Disc in disk drive: \"..sName )\
9574 return\
9575 end\
9576\
9577else\
9578 printUsage()\
9579\
9580end",
9581 [ "help/disk.txt" ] = "Functions in the disk API. These functions are for interacting with disk drives:\
9582disk.isPresent( drive )\
9583disk.setLabel( drive, label )\
9584disk.getLabel( drive )\
9585disk.hasData( drive )\
9586disk.getMountPath( drive )\
9587disk.hasAudio( drive )\
9588disk.getAudioTitle( drive )\
9589disk.playAudio( drive )\
9590disk.stopAudio( )\
9591disk.eject( drive )\
9592disk.getID( drive )\
9593\
9594Events fired by the disk API:\
9595\"disk\" when a disk or other item is inserted into a disk drive. Argument is the name of the drive\
9596\"disk_eject\" when a disk is removed from a disk drive. Argument is the name of the drive\
9597Type \"help events\" to learn about the event system.",
9598 [ "programs/fun/advanced/levels/5.dat" ] = "3\
9599777777777\
9600788888887\
9601787787787\
9602787787787\
9603788888887\
9604787787787\
9605787787787\
960678e748887\
9607777777777",
9608 [ "help/credits.txt" ] = "\
9609ComputerCraft was created by Daniel \"dan200\" Ratcliffe, with additional code by Aaron \"Cloudy\" Mills.\
9610Thanks to nitrogenfingers, GopherATL and RamiLego for program contributions.\
9611Thanks to Mojang, the Forge team, and the MCP team.\
9612Uses LuaJ from http://luaj.sourceforge.net/\
9613\
9614The ComputerCraft 1.76 update was sponsored by MinecraftU and Deep Space.\
9615Visit http://www.minecraftu.org and http://www.deepspace.me/space-cadets to find out more.\
9616\
9617Join the ComputerCraft community online at http://www.computercraft.info\
9618Follow @DanTwoHundred on Twitter!\
9619\
9620To help contribute to ComputerCraft, browse the source code at https://github.com/dan200/ComputerCraft.\
9621\
9622GitHub Contributors:\
9623absolument\
9624Alessandro\
9625apemanzilla\
9626Bartek Bok\
9627Bomb Bloke\
9628CrazedProgrammer\
9629Cruor\
9630daelvn\
9631Devilholk\
9632Drew Lemmy\
9633gegy1000\
9634hugeblank\
9635hydraz\
9636Iunius118\
9637Jonathan Leitschuh\
9638Joseph C. Sible\
9639KingofGamesYami\
9640Lignum\
9641Linus Ramneborg\
9642Logan Davis\
9643Luca\
9644Luca S\
9645MineRobber___T\
9646Nephi (AKA Lupus590)\
9647ObloxCC\
9648Oliver Marks\
9649Restioson\
9650SquidDev\
9651Steven Dirth\
9652theoriginalbit\
9653Tim Ittermann\
9654Vexatos\
9655Wilma456\
9656Wilma456 (Jakob0815)\
9657Wojbie",
9658 [ "programs/gps.lua" ] = "\
9659local function printUsage()\
9660 print( \"Usages:\" )\
9661 print( \"gps host\" )\
9662 print( \"gps host <x> <y> <z>\" )\
9663 print( \"gps locate\" )\
9664end\
9665\
9666local tArgs = { ... }\
9667if #tArgs < 1 then\
9668 printUsage()\
9669 return\
9670end\
9671\
9672 local sCommand = tArgs[1]\
9673if sCommand == \"locate\" then\
9674 -- \"gps locate\"\
9675 -- Just locate this computer (this will print the results)\
9676 gps.locate( 2, true )\
9677\
9678elseif sCommand == \"host\" then\
9679 -- \"gps host\"\
9680 -- Act as a GPS host\
9681 if pocket then\
9682 print( \"GPS Hosts must be stationary\" )\
9683 return\
9684 end\
9685\
9686 -- Find a modem\
9687 local sModemSide = nil\
9688 for n,sSide in ipairs( rs.getSides() ) do\
9689 if peripheral.getType( sSide ) == \"modem\" and peripheral.call( sSide, \"isWireless\" ) then\
9690 sModemSide = sSide\
9691 break\
9692 end\
9693 end\
9694\
9695 if sModemSide == nil then\
9696 print( \"No wireless modems found. 1 required.\" )\
9697 return\
9698 end\
9699\
9700 -- Determine position\
9701 local x,y,z\
9702 if #tArgs >= 4 then\
9703 -- Position is manually specified\
9704 x = tonumber(tArgs[2])\
9705 y = tonumber(tArgs[3])\
9706 z = tonumber(tArgs[4])\
9707 if x == nil or y == nil or z == nil then\
9708 printUsage()\
9709 return\
9710 end\
9711 print( \"Position is \"..x..\",\"..y..\",\"..z )\
9712 else\
9713 -- Position is to be determined using locate\
9714 x,y,z = gps.locate( 2, true )\
9715 if x == nil then\
9716 print( \"Run \\\"gps host <x> <y> <z>\\\" to set position manually\" )\
9717 return\
9718 end\
9719 end\
9720\
9721 -- Open a channel\
9722 local modem = peripheral.wrap( sModemSide )\
9723 print( \"Opening channel on modem \"..sModemSide )\
9724 modem.open( gps.CHANNEL_GPS )\
9725\
9726 -- Serve requests indefinately\
9727 local nServed = 0\
9728 while true do\
9729 local e, p1, p2, p3, p4, p5 = os.pullEvent( \"modem_message\" )\
9730 if e == \"modem_message\" then\
9731 -- We received a message from a modem\
9732 local sSide, sChannel, sReplyChannel, sMessage, nDistance = p1, p2, p3, p4, p5\
9733 if sSide == sModemSide and sChannel == gps.CHANNEL_GPS and sMessage == \"PING\" and nDistance then\
9734 -- We received a ping message on the GPS channel, send a response\
9735 modem.transmit( sReplyChannel, gps.CHANNEL_GPS, { x, y, z } )\
9736\
9737 -- Print the number of requests handled\
9738 nServed = nServed + 1\
9739 if nServed > 1 then\
9740 local x,y = term.getCursorPos()\
9741 term.setCursorPos(1,y-1)\
9742 end\
9743 print( nServed..\" GPS requests served\" )\
9744 end\
9745 end\
9746 end\
9747else\
9748 -- \"gps somethingelse\"\
9749 -- Error\
9750 printUsage()\
9751end",
9752 [ "programs/fun/advanced/levels/12.dat" ] = "6\
975377 777 77\
975472888888897\
9755 8 8 8\
9756 8 8b888 8\
975778 e8888 87\
975878888788887\
975978 8888e 87\
9760 8 888b8 8\
9761 8 8 8\
976275888888807\
976377 777 77",
9764 [ "programs/help.lua" ] = "local tArgs = { ... }\
9765local sTopic\
9766if #tArgs > 0 then\
9767 sTopic = tArgs[1]\
9768else\
9769 sTopic = \"intro\"\
9770end\
9771\
9772if sTopic == \"index\" then\
9773 print( \"Help topics availiable:\" )\
9774 local tTopics = help.topics()\
9775 textutils.pagedTabulate( tTopics )\
9776 return\
9777end\
9778\
9779local sFile = help.lookup( sTopic )\
9780local file = ((sFile ~= nil) and io.open( sFile )) or nil\
9781if file then\
9782 local sContents = file:read(\"*a\")\
9783 file:close()\
9784\
9785 local _, nHeight = term.getSize()\
9786 textutils.pagedPrint( sContents, nHeight - 3 )\
9787else\
9788 print( \"No help available\" )\
9789end",
9790 [ "help/label.txt" ] = "label gets or sets the label of the Computer, or of Floppy Disks in attached disk drives.\
9791\
9792ex:\
9793\"label get\" prints the label of the computer.\
9794\"label get left\" prints the label of the disk in the left drive.\
9795\"label set \"My Computer\"\" set the label of the computer to \"My Computer\".\
9796\"label set left \"My Programs\"\" - sets the label of the disk in the left drive to \"My Programs\".\
9797\"label clear\" clears the label of the computer.\
9798\"label clear left\" clears the label of the disk in the left drive.",
9799 [ "programs/pocket/falling.lua" ] = "--[[\
9800Falling - Based on Tetris by Alexey Pajitnov\
9801This version written by Gopher, at the request of Dan200, for\
9802ComputerCraft v1.6. No particular rights are reserved.\
9803--]]\
9804\
9805local function colorass(c,bw)\
9806 return term.isColor() and c or bw\
9807end\
9808\
9809local block_s1= {\
9810 {\
9811 { 1,0,0,0, },\
9812 { 1,1,0,0, },\
9813 { 0,1,0,0, },\
9814 { 0,0,0,0, },\
9815 },\
9816 {\
9817 { 0,0,0,0, },\
9818 { 0,1,1,0, },\
9819 { 1,1,0,0, },\
9820 { 0,0,0,0, },\
9821 },\
9822 ch=colorass(\" \",\"{}\"),\
9823 fg=colorass(colors.blue,colors.black),\
9824 bg=colorass(colors.cyan,colors.white),\
9825 }\
9826local block_s2= {\
9827 {\
9828 { 0,1,0,0, },\
9829 { 1,1,0,0, },\
9830 { 1,0,0,0, },\
9831 { 0,0,0,0, },\
9832 },\
9833 {\
9834 { 0,0,0,0, },\
9835 { 1,1,0,0, },\
9836 { 0,1,1,0, },\
9837 { 0,0,0,0, },\
9838 },\
9839 ch=colorass(\" \",\"{}\"),\
9840 fg=colorass(colors.green,colors.black),\
9841 bg=colorass(colors.lime,colors.white),\
9842 }\
9843local block_line = {\
9844 {\
9845 { 0,1,0,0, },\
9846 { 0,1,0,0, },\
9847 { 0,1,0,0, },\
9848 { 0,1,0,0, },\
9849 },\
9850 {\
9851 { 0,0,0,0, },\
9852 { 1,1,1,1, },\
9853 { 0,0,0,0, },\
9854 { 0,0,0,0, },\
9855 },\
9856 ch=colorass(\" \",\"[]\"),\
9857 fg=colorass(colors.pink,colors.black),\
9858 bg=colorass(colors.red,colors.white),\
9859 }\
9860local block_square = {\
9861 {\
9862 { 1,1,0,0, },\
9863 { 1,1,0,0, },\
9864 { 0,0,0,0, },\
9865 { 0,0,0,0, },\
9866 },\
9867 ch=colorass(\" \",\"[]\"),\
9868 fg=colorass(colors.lightBlue,colors.black),\
9869 bg=colorass(colors.blue,colors.white),\
9870 }\
9871local block_L1 = {\
9872 {\
9873 { 1,1,0,0, },\
9874 { 0,1,0,0, },\
9875 { 0,1,0,0, },\
9876 { 0,0,0,0, },\
9877 },\
9878 {\
9879 { 0,0,0,0, },\
9880 { 1,1,1,0, },\
9881 { 1,0,0,0, },\
9882 { 0,0,0,0, },\
9883 },\
9884 {\
9885 { 0,1,0,0, },\
9886 { 0,1,0,0, },\
9887 { 0,1,1,0, },\
9888 { 0,0,0,0, },\
9889 },\
9890 {\
9891 { 0,0,1,0, },\
9892 { 1,1,1,0, },\
9893 { 0,0,0,0, },\
9894 { 0,0,0,0, },\
9895 },\
9896 ch=colorass(\" \",\"()\"),\
9897 fg=colorass(colors.orange,colors.black),\
9898 bg=colorass(colors.yellow,colors.white),\
9899 }\
9900local block_L2 = {\
9901 {\
9902 { 0,1,0,0, },\
9903 { 0,1,0,0, },\
9904 { 1,1,0,0, },\
9905 { 0,0,0,0, },\
9906 },\
9907 {\
9908 { 0,0,0,0, },\
9909 { 1,1,1,0, },\
9910 { 0,0,1,0, },\
9911 { 0,0,0,0, },\
9912 },\
9913 {\
9914 { 0,1,1,0, },\
9915 { 0,1,0,0, },\
9916 { 0,1,0,0, },\
9917 { 0,0,0,0, },\
9918 },\
9919 {\
9920 { 1,0,0,0, },\
9921 { 1,1,1,0, },\
9922 { 0,0,0,0, },\
9923 { 0,0,0,0, },\
9924 },\
9925 ch=colorass(\" \",\"()\"),\
9926 fg=colorass(colors.brown,colors.black),\
9927 bg=colorass(colors.orange,colors.white),\
9928 }\
9929local block_T = {\
9930 {\
9931 { 0,1,0,0, },\
9932 { 1,1,0,0, },\
9933 { 0,1,0,0, },\
9934 { 0,0,0,0, },\
9935 },\
9936 {\
9937 { 0,0,0,0, },\
9938 { 1,1,1,0, },\
9939 { 0,1,0,0, },\
9940 { 0,0,0,0, },\
9941 },\
9942 {\
9943 { 0,1,0,0, },\
9944 { 0,1,1,0, },\
9945 { 0,1,0,0, },\
9946 { 0,0,0,0, },\
9947 },\
9948 {\
9949 { 0,1,0,0, },\
9950 { 1,1,1,0, },\
9951 { 0,0,0,0, },\
9952 { 0,0,0,0, },\
9953 },\
9954 ch=colorass(\" \",\"<>\"),\
9955 fg=colorass(colors.cyan,colors.black),\
9956 bg=colorass(colors.purple,colors.white),\
9957 }\
9958\
9959local blocks={ block_line, block_square, block_s1, block_s2, block_L1, block_L2, block_T}\
9960\
9961local points={4,10,30,120}\
9962\
9963local function lpad(text,amt)\
9964 text=tostring(text)\
9965 return string.rep(\" \",amt-#text)..text\
9966end\
9967\
9968local width,height=term.getSize()\
9969\
9970if height<19 or width<26 then\
9971 print(\"Your screen is too small to play :(\")\
9972 return\
9973end\
9974\
9975\
9976local speedsByLevel={\
9977 1.2,\
9978 1.0,\
9979 .8,\
9980 .65,\
9981 .5,\
9982 .4,\
9983 .3,\
9984 .25,\
9985 .2,\
9986 .15,\
9987 .1,\
9988 .05,}\
9989\
9990local level=1\
9991\
9992local function playGame()\
9993 local score=0\
9994 local lines=0\
9995 local initialLevel=level\
9996 local next=blocks[math.random(1,#blocks)]\
9997\
9998 local pit={}\
9999\
10000\
10001 local heightAdjust=0\
10002\
10003 if height<=19 then\
10004 heightAdjust=1\
10005 end\
10006\
10007\
10008\
10009 local function drawScreen()\
10010 term.setTextColor(colors.white)\
10011 term.setBackgroundColor(colors.black)\
10012 term.clear()\
10013\
10014 term.setTextColor(colors.black)\
10015 term.setBackgroundColor(colorass(colors.lightGray, colors.white))\
10016 term.setCursorPos(22,2)\
10017 term.write(\"Score\") --score\
10018 term.setCursorPos(22,5)\
10019 term.write(\"Level\") --level\
10020 term.setCursorPos(22,8)\
10021 term.write(\"Lines\") --lines\
10022 term.setCursorPos(22,12)\
10023 term.write(\"Next\") --next\
10024\
10025 term.setCursorPos(21,1)\
10026 term.write(\" \")\
10027 term.setCursorPos(21,2)\
10028 term.write(\" \") --score\
10029 term.setCursorPos(21,3)\
10030 term.write(\" \")\
10031 term.setCursorPos(21,4)\
10032 term.write(\" \")\
10033 term.setCursorPos(21,5)\
10034 term.write(\" \") --level\
10035 term.setCursorPos(21,6)\
10036 term.write(\" \")\
10037 term.setCursorPos(21,7)\
10038 term.write(\" \")\
10039 term.setCursorPos(21,8)\
10040 term.write(\" \") --lines\
10041 term.setCursorPos(21,9)\
10042 term.write(\" \")\
10043 term.setCursorPos(21,10)\
10044 term.write(\" \")\
10045 term.setCursorPos(21,11)\
10046 term.write(\" \")\
10047 term.setCursorPos(21,12)\
10048 term.write(\" \") --next\
10049 term.setCursorPos(26,12)\
10050 term.write(\" \") --next\
10051 term.setCursorPos(21,13)\
10052 term.write(\" \")\
10053 term.setCursorPos(21,14)\
10054 term.write(\" \")\
10055 term.setCursorPos(21,15)\
10056 term.write(\" \")\
10057 term.setCursorPos(21,16)\
10058 term.write(\" \")\
10059 term.setCursorPos(21,17)\
10060 term.write(\" \")\
10061 term.setCursorPos(21,18)\
10062 term.write(\" \")\
10063 term.setCursorPos(21,19)\
10064 term.write(\" \")\
10065 term.setCursorPos(21,20)\
10066 term.write(\" \")\
10067 end\
10068\
10069 local function updateNumbers()\
10070 term.setTextColor(colors.white)\
10071 term.setBackgroundColor(colors.black)\
10072\
10073 term.setCursorPos(22,3)\
10074 term.write(lpad(score,5)) --score\
10075 term.setCursorPos(22,6)\
10076 term.write(lpad(level,5)) --level\
10077 term.setCursorPos(22,9)\
10078 term.write(lpad(lines,5)) --lines\
10079 end\
10080\
10081 local function drawBlockAt(block,xp,yp,rot)\
10082 term.setTextColor(block.fg)\
10083 term.setBackgroundColor(block.bg)\
10084 for y=1,4 do\
10085 for x=1,4 do\
10086 if block[rot][y][x]==1 then\
10087 term.setCursorPos((xp+x)*2-3,yp+y-1-heightAdjust)\
10088 term.write(block.ch)\
10089 end\
10090 end\
10091 end\
10092 end\
10093\
10094 local function eraseBlockAt(block,xp,yp,rot)\
10095 term.setTextColor(colors.white)\
10096 term.setBackgroundColor(colors.black)\
10097 for y=1,4 do\
10098 for x=1,4 do\
10099 if block[rot][y][x]==1 then\
10100 term.setCursorPos((xp+x)*2-3,yp+y-1-heightAdjust)\
10101 term.write(\" \")\
10102 end\
10103 end\
10104 end\
10105 end\
10106\
10107 local function testBlockAt(block,xp,yp,rot)\
10108 for y=1,4 do\
10109 local ty=yp+y-1\
10110 for x=1,4 do\
10111 local tx=xp+x-1\
10112 if block[rot][y][x]==1 then\
10113 if tx>10 or tx<1 or ty>20 or pit[ty][tx]~=0 then\
10114 return true\
10115 end\
10116 end\
10117 end\
10118 end\
10119 end\
10120\
10121 local function pitBlock(block,xp,yp,rot)\
10122 for y=1,4 do\
10123 for x=1,4 do\
10124 if block[rot][y][x]==1 then\
10125 pit[yp+y-1][xp+x-1]=block\
10126 end\
10127 end\
10128 end\
10129 end\
10130\
10131\
10132 local function clearPit()\
10133 for row=1,20 do\
10134 pit[row]={}\
10135 for col=1,10 do\
10136 pit[row][col]=0\
10137 end\
10138 end\
10139 end\
10140\
10141\
10142\
10143 drawScreen()\
10144 updateNumbers()\
10145\
10146 --declare & init the pit\
10147 clearPit()\
10148\
10149\
10150\
10151 local halt=false\
10152 local dropSpeed=speedsByLevel[math.min(level,12)]\
10153\
10154\
10155 local curBlock=next\
10156 next=blocks[math.random(1,7)]\
10157\
10158 local curX, curY, curRot=4, 1, 1\
10159 local dropTimer=os.startTimer(dropSpeed)\
10160\
10161 drawBlockAt(next,11.5,15+heightAdjust,1)\
10162 drawBlockAt(curBlock,curX,curY,curRot)\
10163\
10164 local function redrawPit()\
10165 for r=1+heightAdjust,20 do\
10166 term.setCursorPos(1,r-heightAdjust)\
10167 for c=1,10 do\
10168 if pit[r][c]==0 then\
10169 term.setTextColor(colors.black)\
10170 term.setBackgroundColor(colors.black)\
10171 term.write(\" \")\
10172 else\
10173 term.setTextColor(pit[r][c].fg)\
10174 term.setBackgroundColor(pit[r][c].bg)\
10175 term.write(pit[r][c].ch)\
10176 end\
10177 end\
10178 end\
10179 end\
10180\
10181 local function hidePit()\
10182 for r=1+heightAdjust,20 do\
10183 term.setCursorPos(1,r-heightAdjust)\
10184 term.setTextColor(colors.black)\
10185 term.setBackgroundColor(colors.black)\
10186 term.write(\" \")\
10187 end\
10188 end\
10189\
10190 local function msgBox(message)\
10191 local x=math.floor((17-#message)/2)\
10192 term.setBackgroundColor(colorass(colors.lightGray,colors.white))\
10193 term.setTextColor(colors.black)\
10194 term.setCursorPos(x,9)\
10195 term.write(\"+\"..string.rep(\"-\",#message+2)..\"+\")\
10196 term.setCursorPos(x,10)\
10197 term.write(\"|\")\
10198 term.setCursorPos(x+#message+3,10)\
10199 term.write(\"|\")\
10200 term.setCursorPos(x,11)\
10201 term.write(\"+\"..string.rep(\"-\",#message+2)..\"+\")\
10202 term.setTextColor(colors.white)\
10203 term.setBackgroundColor(colors.black)\
10204 term.setCursorPos(x+1,10)\
10205 term.write(\" \"..message..\" \")\
10206 end\
10207\
10208 local function clearRows()\
10209 local rows={}\
10210 for r=1,20 do\
10211 local count=0\
10212 for c=1,10 do\
10213 if pit[r][c]~=0 then\
10214 count=count+1\
10215 else\
10216 break\
10217 end\
10218 end\
10219 if count==10 then\
10220 rows[#rows+1]=r\
10221 end\
10222 end\
10223\
10224 if #rows>0 then\
10225 for i=1,4 do\
10226 sleep(.1)\
10227 for r=1,#rows do\
10228 r=rows[r]\
10229 term.setCursorPos(1,r-heightAdjust)\
10230 for c=1,10 do\
10231 term.setTextColor(pit[r][c].bg)\
10232 term.setBackgroundColor(pit[r][c].fg)\
10233 term.write(pit[r][c].ch)\
10234 end\
10235 end\
10236 sleep(.1)\
10237 for r=1,#rows do\
10238 r=rows[r]\
10239 term.setCursorPos(1,r-heightAdjust)\
10240 for c=1,10 do\
10241 term.setTextColor(pit[r][c].fg)\
10242 term.setBackgroundColor(pit[r][c].bg)\
10243 term.write(pit[r][c].ch)\
10244 end\
10245 end\
10246 end\
10247 --now remove the rows and drop everythign else\
10248 term.setBackgroundColor(colors.black)\
10249 for r=1,#rows do\
10250 r=rows[r]\
10251 term.setCursorPos(1,r-heightAdjust)\
10252 term.write(\" \")\
10253 end\
10254 sleep(.25)\
10255 for r=1,#rows do\
10256 table.remove(pit,rows[r])\
10257 table.insert(pit,1,{0,0,0,0,0,0,0,0,0,0})\
10258 end\
10259 redrawPit()\
10260 lines=lines+#rows\
10261 score=score+points[#rows]*math.min(level,20)\
10262 level=math.floor(lines/10)+initialLevel\
10263 dropSpeed=speedsByLevel[math.min(level,12)]\
10264 updateNumbers()\
10265 end\
10266 sleep(.25)\
10267 end\
10268\
10269 local function blockFall()\
10270 local result = false\
10271 if testBlockAt(curBlock,curX,curY+1,curRot) then\
10272 pitBlock(curBlock,curX,curY,curRot)\
10273 --detect rows that clear\
10274 clearRows()\
10275\
10276 curBlock=next\
10277 curX=4\
10278 curY=1\
10279 curRot=1\
10280 if testBlockAt(curBlock,curX,curY,curRot) then\
10281 halt=true\
10282 end\
10283 drawBlockAt(curBlock,curX,curY,curRot)\
10284 eraseBlockAt(next,11.5,15+heightAdjust,1)\
10285 next=blocks[math.random(1,7)]\
10286 drawBlockAt(next,11.5,15+heightAdjust,1)\
10287 return true\
10288 else\
10289 eraseBlockAt(curBlock,curX,curY,curRot)\
10290 curY=curY+1\
10291 drawBlockAt(curBlock,curX,curY,curRot)\
10292 return false\
10293 end\
10294 end\
10295\
10296\
10297 while not halt do\
10298 local e={os.pullEvent()}\
10299 if e[1]==\"timer\" then\
10300 if e[2]==dropTimer then\
10301 blockFall()\
10302 dropTimer=os.startTimer(dropSpeed)\
10303 end\
10304 elseif e[1]==\"key\" then\
10305 local key=e[2]\
10306 local dx,dy,dr=0,0,0\
10307 if key==keys.left or key==keys.a then\
10308 dx=-1\
10309 elseif key==keys.right or key==keys.d then\
10310 dx=1\
10311 elseif key==keys.up or key==keys.w then\
10312 dr=1\
10313 elseif key==keys.down or key==keys.s then\
10314 while not blockFall() do end\
10315 dropTimer=os.startTimer(dropSpeed)\
10316 elseif key==keys.space then\
10317 hidePit()\
10318 msgBox(\"Paused\")\
10319 while ({os.pullEvent(\"key\")})[2]~=keys.space do end\
10320 redrawPit()\
10321 drawBlockAt(curBlock,curX,curY,curRot)\
10322 dropTimer=os.startTimer(dropSpeed)\
10323 end\
10324 if dx+dr~=0 then\
10325 if not testBlockAt(curBlock,curX+dx,curY+dy,(dr>0 and curRot%#curBlock+dr or curRot)) then\
10326 eraseBlockAt(curBlock,curX,curY,curRot)\
10327 curX=curX+dx\
10328 curY=curY+dy\
10329 curRot=dr==0 and curRot or (curRot%#curBlock+dr)\
10330 drawBlockAt(curBlock,curX,curY,curRot)\
10331 end\
10332 end\
10333 elseif e[1]==\"term_resize\" then\
10334 local w,h=term.getSize()\
10335 if h==20 then\
10336 heightAdjust=0\
10337 else\
10338 heightAdjust=1\
10339 end\
10340 redrawPit()\
10341 drawBlockAt(curBlock,curX,curY,curRot)\
10342 end\
10343 end\
10344\
10345 msgBox(\"Game Over!\")\
10346 while true do\
10347 local _,k=os.pullEvent(\"key\")\
10348 if k==keys.space or k==keys.enter then\
10349 break\
10350 end\
10351 end\
10352\
10353 level = math.min(level,9)\
10354end\
10355\
10356\
10357local selected=1\
10358local playersDetected=false\
10359\
10360local function drawMenu()\
10361 term.setBackgroundColor(colors.black)\
10362 term.setTextColor(colorass(colors.red,colors.white))\
10363 term.clear()\
10364\
10365 local cx,cy=math.floor(width/2),math.floor(height/2)\
10366\
10367 term.setCursorPos(cx-6,cy-2)\
10368 term.write(\"F A L L I N G\")\
10369\
10370 if playersDetected then\
10371 if selected==0 then\
10372 term.setTextColor(colorass(colors.blue,colors.black))\
10373 term.setBackgroundColor(colorass(colors.gray,colors.white))\
10374 else\
10375 term.setTextColor(colorass(colors.lightBlue,colors.white))\
10376 term.setBackgroundColor(colors.black)\
10377 end\
10378 term.setCursorPos(cx-12,cy)\
10379 term.write(\" Play head-to-head game! \")\
10380 end\
10381\
10382 term.setCursorPos(cx-10,cy+1)\
10383 if selected==1 then\
10384 term.setTextColor(colorass(colors.blue,colors.black))\
10385 term.setBackgroundColor(colorass(colors.lightGray,colors.white))\
10386 else\
10387 term.setTextColor(colorass(colors.lightBlue,colors.white))\
10388 term.setBackgroundColor(colors.black)\
10389 end\
10390 term.write(\" Play from level: <\" .. level .. \"> \")\
10391\
10392 term.setCursorPos(cx-3,cy+3)\
10393 if selected==2 then\
10394 term.setTextColor(colorass(colors.blue,colors.black))\
10395 term.setBackgroundColor(colorass(colors.lightGray,colors.white))\
10396 else\
10397 term.setTextColor(colorass(colors.lightBlue,colors.white))\
10398 term.setBackgroundColor(colors.black)\
10399 end\
10400 term.write(\" Quit \")\
10401end\
10402\
10403\
10404local function runMenu()\
10405 drawMenu()\
10406\
10407 while true do\
10408 local event={os.pullEvent()}\
10409 if event[1]==\"key\" then\
10410 local key=event[2]\
10411 if key==keys.right or key==keys.d and selected==1 then\
10412 level=math.min(level+1,9)\
10413 drawMenu()\
10414 elseif key==keys.left or key==keys.a and selected==1 then\
10415 level=math.max(level-1,1)\
10416 drawMenu()\
10417 elseif key>=keys.one and key<=keys.nine and selected==1 then\
10418 level=(key-keys.one) + 1\
10419 drawMenu()\
10420 elseif key==keys.up or key==keys.w then\
10421 selected=selected-1\
10422 if selected==0 then\
10423 selected=2\
10424 end\
10425 drawMenu()\
10426 elseif key==keys.down or key==keys.s then\
10427 selected=selected%2+1\
10428 drawMenu()\
10429 elseif key==keys.enter or key==keys.space then\
10430 break --begin play!\
10431 end\
10432 end\
10433 end\
10434end\
10435\
10436while true do\
10437 runMenu()\
10438 if selected==2 then\
10439 break\
10440 end\
10441\
10442 playGame()\
10443end\
10444\
10445\
10446term.setTextColor(colors.white)\
10447term.setBackgroundColor(colors.black)\
10448term.clear()\
10449term.setCursorPos(1,1)",
10450 [ "programs/delete.lua" ] = "\
10451local tArgs = { ... }\
10452if #tArgs < 1 then\
10453 print( \"Usage: rm <path>\" )\
10454 return\
10455end\
10456\
10457local sPath = shell.resolve( tArgs[1] )\
10458local tFiles = fs.find( sPath )\
10459if #tFiles > 0 then\
10460 for n,sFile in ipairs( tFiles ) do\
10461 fs.delete( sFile )\
10462 end\
10463else\
10464 printError( \"No matching files\" )\
10465end",
10466 [ "programs/command/exec.lua" ] = "\
10467local tArgs = { ... }\
10468if not commands then\
10469 printError( \"Requires a Command Computer.\" )\
10470 return\
10471end\
10472if #tArgs == 0 then\
10473 printError( \"Usage: exec <command>\" )\
10474 return\
10475end\
10476\
10477local function printSuccess( text )\
10478 if term.isColor() then\
10479 term.setTextColor( colors.green )\
10480 end\
10481 print( text )\
10482 term.setTextColor( colors.white )\
10483end\
10484\
10485local sCommand = string.lower( tArgs[1] )\
10486for n=2,#tArgs do\
10487 sCommand = sCommand .. \" \" .. tArgs[n]\
10488end\
10489\
10490local bResult, tOutput = commands.exec( sCommand )\
10491if bResult then\
10492 printSuccess( \"Success\" )\
10493 if #tOutput > 0 then\
10494 for n=1,#tOutput do\
10495 print( tOutput[n] )\
10496 end\
10497 end\
10498else\
10499 printError( \"Failed\" )\
10500 if #tOutput > 0 then\
10501 for n=1,#tOutput do\
10502 print( tOutput[n] )\
10503 end\
10504 end\
10505end",
10506 [ "help/helpapi.txt" ] = "Functions in the help API:\
10507help.setPath( path )\
10508help.lookup( topic )\
10509help.topics()\
10510help.completeTopic( topic )",
10511 [ "programs/cd.lua" ] = "\
10512local tArgs = { ... }\
10513if #tArgs < 1 then\
10514 print( \"Usage: cd <path>\" )\
10515 return\
10516end\
10517\
10518local sNewDir = shell.resolve( tArgs[1] )\
10519if fs.isDir( sNewDir ) then\
10520 shell.setDir( sNewDir )\
10521else\
10522 print( \"Not a directory\" )\
10523 return\
10524end",
10525 [ "programs/alias.lua" ] = "\
10526local tArgs = { ... }\
10527if #tArgs > 2 then\
10528 print( \"Usage: alias <alias> <program>\" )\
10529 return\
10530end\
10531\
10532local sAlias = tArgs[1]\
10533local sProgram = tArgs[2]\
10534\
10535if sAlias and sProgram then\
10536 -- Set alias\
10537 shell.setAlias( sAlias, sProgram )\
10538elseif sAlias then\
10539 -- Clear alias\
10540 shell.clearAlias( sAlias )\
10541else\
10542 -- List aliases\
10543 local tAliases = shell.aliases()\
10544 local tList = {}\
10545 for sAlias, sCommand in pairs( tAliases ) do\
10546 table.insert( tList, sAlias..\":\"..sCommand )\
10547 end\
10548 table.sort( tList )\
10549 textutils.pagedTabulate( tList )\
10550end",
10551 [ "help/apis.txt" ] = "apis lists the currently loaded APIs available to programs in CraftOS.\
10552\
10553Type \"help <api>\" to see help for a specific api.\
10554Call os.loadAPI( path ) to load extra apis.",
10555 [ "programs/list.lua" ] = "\
10556local tArgs = { ... }\
10557\
10558-- Get all the files in the directory\
10559local sDir = shell.dir()\
10560if tArgs[1] ~= nil then\
10561 sDir = shell.resolve( tArgs[1] )\
10562end\
10563\
10564if not fs.isDir( sDir ) then\
10565 printError( \"Not a directory\" )\
10566 return\
10567end\
10568\
10569-- Sort into dirs/files, and calculate column count\
10570local tAll = fs.list( sDir )\
10571local tFiles = {}\
10572local tDirs = {}\
10573\
10574local bShowHidden = settings.get( \"list.show_hidden\" )\
10575for n, sItem in pairs( tAll ) do\
10576 if bShowHidden or string.sub( sItem, 1, 1 ) ~= \".\" then\
10577 local sPath = fs.combine( sDir, sItem )\
10578 if fs.isDir( sPath ) then\
10579 table.insert( tDirs, sItem )\
10580 else\
10581 table.insert( tFiles, sItem )\
10582 end\
10583 end\
10584end\
10585table.sort( tDirs )\
10586table.sort( tFiles )\
10587\
10588if term.isColour() then\
10589 textutils.pagedTabulate( colors.green, tDirs, colors.white, tFiles )\
10590else\
10591 textutils.pagedTabulate( tDirs, tFiles )\
10592end",
10593 [ "programs/advanced/bg.lua" ] = "\
10594if not shell.openTab then\
10595 printError( \"Requires multishell\" )\
10596 return\
10597end\
10598\
10599local tArgs = { ... }\
10600if #tArgs > 0 then\
10601 shell.openTab( table.unpack( tArgs ) )\
10602else\
10603 shell.openTab( \"shell\" )\
10604end",
10605 [ "programs/fun/advanced/levels/6.dat" ] = "4\
106067777777777\
106077288888837\
1060878 87\
10609788888b 87\
10610788888b 87\
10611788888b 87\
10612788888b 87\
1061378 87\
106147188888807\
106157777777777",
10616 [ "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\".\
10617\
10618Methods exposed by the Printer:\
10619getInkLevel()\
10620getPaperLevel()\
10621newPage()\
10622setPageTitle( title )\
10623getPageSize()\
10624setCursorPos( x, y )\
10625getCursorPos()\
10626write( text )\
10627endPage()",
10628 [ "help/lua.txt" ] = "lua is an interactive prompt for the lua programming language. It's a useful tool for learning the language.",
10629 [ "help/changelog.txt" ] = "New Features in ComputerCraft 1.80:\
10630\
10631* Added .getResponseHeaders() to HTTP responses.\
10632* Return a HTTP response when a HTTP error occurs.\
10633* Added a GUI to change ComputerCraft config options.\
10634* os.time() and os.day() now accept parameters to give the real world time.\
10635* Added os.epoch()\
10636* Monitor text now glows in the dark.\
10637* Added a \"Pocket Computer upgrade API\" so mod developers can add their own pocket upgrades.\
10638* Added pocket.equipBack()/pocket.unequipBack() to add/remove pocket upgrades.\
10639* Added term.setPaletteColor()/term.getPaletteColor() to change/check colors\
10640* Added colors.rgb8()/colours.rgb8() \
10641* Performance improvements to fs.find\
10642* Requires the player to be interacting with the computer when typing\
10643* Disk labels are limited to 32 characters\
10644* Labels can now only include characters within the printable range ( to ~)\
10645* Various model improvements\
10646* There is now a configurable file descriptor limit\
10647* Threads are now daemon threads\
10648* Termination signals are now sent unless the computer is off\
10649* Fixed compilation errors\
10650* Now handles tile entity changes\
10651* GPS coordinates now have to be numbers\
10652* Turtle upgrades now act as tools and peripherals\
10653* The Filesystem.list result is now sorted\
10654* The number of values to unpack can now be manually specified\
10655* Small terminal & monitor rendering improvements\
10656* General improvements to the documentation\
10657* Redstone inputs are no longer reset when adding peripherals\
10658* Turtles now use tinting\
10659* shell.resolveProgram now picks up on *.lua files\
10660* Fixed a handful of bugs in ComputerCraft\
10661* Added speaker block, turtle upgrade, pocket upgrade, and peripheral api\
10662* Startup can now be a directory containing multiple startup files\
10663* Added .getLabel to the computer peripheral\
10664\
10665New Features in ComputerCraft 1.79:\
10666\
10667* Ported ComputerCraftEdu to Minecraft 1.8.9\
10668* Fixed a handful of bugs in ComputerCraft\
10669\
10670New Features in ComputerCraft 1.77:\
10671\
10672* Ported to Minecraft 1.8.9\
10673* Added \"settings\" API\
10674* Added \"set\" and \"wget\" programs\
10675* 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\
10676* All Computer and Turtle items except Command Computers can now be mounted in Disk Drives\
10677\
10678New Features in ComputerCraft 1.76:\
10679\
10680* Ported to Minecraft 1.8\
10681* Added Ender Modems for cross-dimensional communication\
10682* Fixed handling of 8-bit characters. All the characters in the ISO 8859-1 codepage can now be displayed\
10683* Added some extra graphical characters in the unused character positions, including a suite of characters for Teletext style drawing\
10684* Added support for the new commands in Minecraft 1.8 to the Command Computer\
10685* The return values of turtle.inspect() and commands.getBlockInfo() now include blockstate information\
10686* Added commands.getBlockInfos() function for Command Computers\
10687* Added new \"peripherals\" program\
10688* Replaced the \"_CC_VERSION\" and \"_MC_VERSION\" constants with a new \"_HOST\" constant\
10689* 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\
10690* 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\"\
10691* Fixed many bugs\
10692\
10693New Features in ComputerCraft 1.75:\
10694\
10695* Fixed monitors sometimes rendering without part of their text.\
10696* Fixed a regression in the \"bit\" API.\
10697\
10698New Features in ComputerCraft 1.74:\
10699\
10700* Added tab completion to \"edit\", \"lua\" and the shell.\
10701* Added textutils.complete(), fs.complete(), shell.complete(), shell.setCompletionFunction() and help.complete().\
10702* Added tab completion options to read().\
10703* Added \"key_up\" and \"mouse_up\" events.\
10704* Non-advanced terminals now accept both grey colours.\
10705* Added term.getTextColour(), term.getBackgroundColour() and term.blit().\
10706* Improved the performance of text rendering on Advanced Computers.\
10707* Added a \"Run\" button to the edit program on Advanced Computers.\
10708* Turtles can now push players and entities (configurable).\
10709* Turtles now respect server spawn protection (configurable).\
10710* Added a turtle permissions API for mod authors.\
10711* Implemented a subset of the Lua 5.2 API so programs can be written against it now, ahead of a future Lua version upgrade.\
10712* Added a config option to disable parts of the Lua 5.1 API which will be removed when a future Lua version upgrade happens.\
10713* Command Computers can no longer be broken by survival players.\
10714* Fixed the \"pick block\" key not working on ComputerCraft items in creative mode.\
10715* Fixed the \"edit\" program being hard to use on certain European keyboards.\
10716* Added \"_CC_VERSION\" and \"_MC_VERSION\" constants.\
10717\
10718New Features in ComputerCraft 1.73:\
10719\
10720* The \"exec\" program, commands.exec() and all related Command Computer functions now return the console output of the command.\
10721* Fixed two multiplayer crash bugs.\
10722\
10723New Features in ComputerCraft 1.7:\
10724\
10725* Added Command Computers\
10726* Added new API: commands\
10727* Added new programs: commands, exec\
10728* Added textutils.serializeJSON()\
10729* Added ILuaContext.executeMainThreadTask() for peripheral developers\
10730* Disk Drives and Printers can now be renamed with Anvils\
10731* Fixed various bugs, crashes and exploits\
10732* Fixed problems with HD texture packs\
10733* Documented the new features in the in-game help\
10734\
10735New Features in ComputerCraft 1.65:\
10736\
10737* Fixed a multiplayer-only crash with turtle.place()\
10738* Fixed some problems with http.post()\
10739* Fixed fs.getDrive() returning incorrect results on remote peripherals\
10740\
10741New Features in ComputerCraft 1.64:\
10742\
10743* Ported to Minecraft 1.7.10\
10744* New turtle functions: turtle.inspect(), turtle.inspectUp(), turtle.inspectDown(), turtle.getItemDetail()\
10745* Lots of bug and crash fixes, a huge stability improvement over previous versions\
10746\
10747New Features in ComputerCraft 1.63:\
10748\
10749* Turtles can now be painted with dyes, and cleaned with water buckets\
10750* Added a new game: Redirection - ComputerCraft Edition\
10751* Turtle label nameplates now only show when the Turtle is moused-over\
10752* The HTTP API is now enabled by default, and can be configured with a whitelist of permitted domains\
10753* http.get() and http.post() now accept parameters to control the request headers\
10754* New fs function: fs.getDir( path )\
10755* Fixed some bugs\
10756\
10757New Features in ComputerCraft 1.62:\
10758\
10759* Added IRC-style commands to the \"chat\" program\
10760* Fixed some bugs and crashes\
10761\
10762New Features in ComputerCraft 1.6:\
10763\
10764* Added Pocket Computers\
10765* Added a multi-tasking system for Advanced Computers and Turtles\
10766* Turtles can now swap out their tools and peripherals at runtime\
10767* Turtles can now carry two tools or peripherals at once in any combination\
10768* Turtles and Computers can now be labelled using Name Tags and Anvils\
10769* Added a configurable fuel limit for Turtles\
10770* Added hostnames, protocols and long distance routing to the rednet API\
10771* Added a peer-to-peer chat program to demonstrate new rednet capabilities\
10772* Added a new game, only on Pocket Computers: \"falling\" by GopherATL\
10773* File system commands in the shell now accept wildcard arguments\
10774* The shell now accepts long arguments in quotes\
10775* 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.\
10776* Added a new Windowing API for addressing sub-areas of the terminal\
10777* New programs: fg, bg, multishell, chat, repeat, redstone, equip, unequip\
10778* Improved programs: copy, move, delete, rename, paint, shell\
10779* Removed programs: redset, redprobe, redpulse\
10780* New APIs: window, multishell\
10781* New turtle functions: turtle.equipLeft() and turtle.equipRight()\
10782* New peripheral functions: peripheral.find( [type] )\
10783* New rednet functions: rednet.host( protocol, hostname ), rednet.unhost( protocol ), rednet.locate( protocol, [hostname] )\
10784* New fs function: fs.find( wildcard )\
10785* New shell functions: shell.openTab(), shell.switchTab( [number] )\
10786* New event \"term_resize\" fired when the size of a terminal changes\
10787* Improved rednet functions: rednet.send(), rednet.broadcast() and rednet.receive() now take optional protocol parameters\
10788* 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\
10789* turtle.suck( [limit] ) can now be used to limit the number of items picked up\
10790* 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)\
10791* textutils.serialise( text ) now produces human-readable output\
10792* Refactored most of the codebase and fixed many old bugs and instabilities, turtles should never ever lose their content now\
10793* Fixed the \"turtle_inventory\" event firing when it shouldn't have\
10794* Added error messages to many more turtle functions after they return false\
10795* Documented all new programs and API changes in the \"help\" system\
10796\
10797New Features in ComputerCraft 1.58:\
10798\
10799* Fixed a long standing bug where turtles could lose their identify if they travel too far away\
10800* Fixed use of deprecated code, ensuring mod compatibility with the latest versions of Minecraft Forge, and world compatibility with future versions of Minecraft\
10801\
10802New Features in ComputerCraft 1.57:\
10803\
10804* Ported to Minecraft 1.6.4\
10805* Added two new Treasure Disks: Conway's Game of Life by vilsol and Protector by fredthead\
10806* Fixed a very nasty item duplication bug\
10807\
10808New Features in ComputerCraft 1.56:\
10809\
10810* Added Treasure Disks: Floppy Disks in dungeons which contain interesting community made programs. Find them all!\
10811* All turtle functions now return additional error messages when they fail.\
10812* Resource Packs with Lua Programs can now be edited when extracted to a folder, for easier editing.\
10813\
10814New Features in ComputerCraft 1.55:\
10815\
10816* Ported to Minecraft 1.6.2\
10817* Added Advanced Turtles\
10818* Added \"turtle_inventory\" event. Fires when any change is made to the inventory of a turtle\
10819* Added missing functions io.close, io.flush, io.input, io.lines, io.output\
10820* Tweaked the screen colours used by Advanced Computers, Monitors and Turtles\
10821* Added new features for Peripheral authors\
10822* Lua programs can now be included in Resource Packs\
10823\
10824New Features in ComputerCraft 1.52:\
10825\
10826* Ported to Minecraft 1.5.1\
10827\
10828New Features in ComputerCraft 1.51:\
10829\
10830* Ported to Minecraft 1.5\
10831* Added Wired Modems\
10832* Added Networking Cables\
10833* Made Wireless Modems more expensive to craft\
10834* New redstone API functions: getAnalogInput(), setAnalogOutput(), getAnalogOutput()\
10835* Peripherals can now be controlled remotely over wired networks. New peripheral API function: getNames()\
10836* New event: \"monitor_resize\" when the size of a monitor changes\
10837* Except for labelled computers and turtles, ComputerCraft blocks no longer drop items in creative mode\
10838* The pick block function works in creative mode now works for all ComputerCraft blocks\
10839* All blocks and items now use the IDs numbers assigned by FTB by default\
10840* Fixed turtles sometimes placing blocks with incorrect orientations\
10841* Fixed Wireless modems being able to send messages to themselves\
10842* Fixed turtle.attack() having a very short range\
10843* Various bugfixes\
10844\
10845New Features in ComputerCraft 1.5:\
10846\
10847* 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\
10848* Floppy Disks can now be dyed with multiple dyes, just like armour\
10849* The \"excavate\" program now retains fuel in it's inventory, so can run unattended\
10850* turtle.place() now tries all possible block orientations before failing\
10851* turtle.refuel(0) returns true if a fuel item is selected\
10852* turtle.craft(0) returns true if the inventory is a valid recipe\
10853* The in-game help system now has documentation for all the peripherals and their methods, including the new modem functionality\
10854* A romantic surprise\
10855\
10856New Features in ComputerCraft 1.48:\
10857\
10858* Ported to Minecraft 1.4.6\
10859* Advanced Monitors now emit a \"monitor_touch\" event when right clicked\
10860* Advanced Monitors are now cheaper to craft\
10861* Turtles now get slightly less fuel from items\
10862* Computers can now interact with Command Blocks (if enabled in ComputerCraft.cfg)\
10863* New API function: os.day()\
10864* A christmas surprise\
10865\
10866New Features in ComputerCraft 1.45:\
10867\
10868* Added Advanced Computers\
10869* Added Advanced Monitors\
10870* New program: paint by nitrogenfingers\
10871* New API: paintutils\
10872* New term functions: term.setBackgroundColor, term.setTextColor, term.isColor\
10873* New turtle function: turtle.transferTo\
10874\
10875New Features in ComputerCraft 1.43:\
10876\
10877* Added Printed Pages\
10878* Added Printed Books\
10879* Fixed incompatibility with Forge 275 and above\
10880* Labelled Turtles now keep their fuel when broken\
10881\
10882New Features in ComputerCraft 1.42:\
10883\
10884* Ported to Minecraft 1.3.2\
10885* Added Printers\
10886* Floppy Disks can be dyed different colours\
10887* Wireless Crafty Turtles can now be crafted\
10888* New textures\
10889* New forge config file\
10890* Bug fixes\
10891\
10892New Features in ComputerCraft 1.4:\
10893\
10894* Ported to Forge Mod Loader. ComputerCraft can now be ran directly from the .zip without extraction\
10895* Added Farming Turtles\
10896* Added Felling Turtles\
10897* Added Digging Turtles\
10898* Added Melee Turtles\
10899* Added Crafty Turtles\
10900* Added 14 new Turtle Combinations accessible by combining the turtle upgrades above\
10901* Labelled computers and turtles can now be crafted into turtles or other turtle types without losing their ID, label and data\
10902* Added a \"Turtle Upgrade API\" for mod developers to create their own tools and peripherals for turtles\
10903* Turtles can now attack entities with turtle.attack(), and collect their dropped items\
10904* Turtles can now use turtle.place() with any item the player can, and can interact with entities\
10905* Turtles can now craft items with turtle.craft()\
10906* Turtles can now place items into inventories with turtle.drop()\
10907* Changed the behaviour of turtle.place() and turtle.drop() to only consider the currently selected slot\
10908* Turtles can now pick up items from the ground, or from inventories, with turtle.suck()\
10909* Turtles can now compare items in their inventories\
10910* Turtles can place signs with text on them with turtle.place( [signText] )\
10911* Turtles now optionally require fuel items to move, and can refuel themselves\
10912* The size of the the turtle inventory has been increased to 16\
10913* The size of the turtle screen has been increased\
10914* New turtle functions: turtle.compareTo( [slotNum] ), turtle.craft(), turtle.attack(), turtle.attackUp(), turtle.attackDown(), turtle.dropUp(), turtle.dropDown(), turtle.getFuelLevel(), turtle.refuel()\
10915* New disk function: disk.getID()\
10916* New turtle programs: craft, refuel\
10917* \"excavate\" program now much smarter: Will return items to a chest when full, attack mobs, and refuel itself automatically\
10918* New API: keys\
10919* Added optional Floppy Disk and Hard Drive space limits for computers and turtles\
10920* New fs function: fs.getFreeSpace( path ), also fs.getDrive() works again\
10921* The send and receive range of wireless modems now increases with altitude, allowing long range networking from high-altitude computers (great for GPS networks)\
10922* http.request() now supports https:// URLs\
10923* Right clicking a Disk Drive with a Floppy Disk or a Record when sneaking will insert the item into the Disk Drive automatically\
10924* The default size of the computer screen has been increased\
10925* 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.\
10926\
10927New Features in ComputerCraft 1.31:\
10928\
10929* Ported to Minecraft 1.2.3\
10930* Added Monitors (thanks to Cloudy)\
10931* Updated LuaJ to a newer, less memory hungry version\
10932* rednet_message event now has a third parameter, \"distance\", to support position triangulation.\
10933* New programs: gps, monitor, pastebin.\
10934* Added a secret program. Use with large monitors!\
10935* New apis: gps, vector\
10936* New turtle functions: turtle.compare(), turtle.compareUp(), turtle.compareDown(), turtle.drop( quantity )\
10937* New http functions: http.post().\
10938* New term functions: term.redirect(), term.restore()\
10939* New textutils functions: textutils.urlEncode()\
10940* New rednet functions: rednet.isOpen()\
10941* New config options: modem_range, modem_rangeDuringStorm\
10942* Bug fixes, program tweaks, and help updates\
10943\
10944New Features in ComputerCraft 1.3:\
10945\
10946* Ported to Minecraft Forge\
10947* Added Turtles\
10948* Added Wireless Modems\
10949* Added Mining Turtles\
10950* Added Wireless Turtles\
10951* Added Wireless Mining Turtles\
10952* Computers and Disk Drives no longer get destroyed by water.\
10953* Computers and Turtles can now be labelled with the label program, and labelled devices keep their state when destroyed.\
10954* Computers/Turtles can connect to adjacent devices, and turn them on and off\
10955* User programs now give line numbers in their error messages\
10956* New APIs: turtle, peripheral\
10957* New programs for turtles: tunnel, excavate, go, turn, dance\
10958* New os functions: os.getComputerLabel(), os.setComputerLabel()\
10959* Added \"filter\" parameter to os.pullEvent()\
10960* New shell function: shell.getCurrentProgram()\
10961* New textutils functions: textutils.serialize(), textutils.unserialize(), textutils.tabulate(), textutils.pagedTabulate(), textutils.slowWrite()\
10962* New io file function: file:lines()\
10963* New fs function: fs.getSize()\
10964* Disk Drives can now play records from other mods\
10965* Bug fixes, program tweaks, and help updates\
10966\
10967New Features in ComputerCraft 1.2:\
10968\
10969* Added Disk Drives and Floppy Disks\
10970* Added Ctrl+T shortcut to terminate the current program (hold)\
10971* Added Ctrl+S shortcut to shutdown the computer (hold)\
10972* Added Ctrl+R shortcut to reboot the computer (hold)\
10973* New Programs: alias, apis, copy, delete, dj, drive, eject, id, label, list, move, reboot, redset, rename, time, worm.\
10974* New APIs: bit, colours, disk, help, rednet, parallel, textutils.\
10975* New color functions: colors.combine(), colors.subtract(), colors.test()\
10976* New fs functions: fs.getName(), new modes for fs.open()\
10977* New os functions: os.loadAPI(), os.unloadAPI(),\
10978os.clock(), os.time(), os.setAlarm(),\
10979os.reboot(), os.queueEvent()\
10980* New redstone function: redstone.getSides()\
10981* New shell functions: shell.setPath(), shell.programs(), shell.resolveProgram(), shell.setAlias()\
10982* Lots of updates to the help pages\
10983* Bug fixes\
10984\
10985New Features in ComputerCraft 1.1:\
10986\
10987* Added Multiplayer support throughout.\
10988* Added connectivity with RedPower bundled cables\
10989* Added HTTP api, enabled via the mod config, to allow computers to access the real world internet\
10990* Added command history to the shell.\
10991* Programs which spin in an infinite loop without yielding will no longer freeze minecraft\
10992* Help updates and bug fixes\
10993\
10994New Features in ComputerCraft 1.0:\
10995\
10996* First Release!",
10997 [ "help/emu.txt" ] = "USAGE\
10998\
10999* emu close\
11000Closes the current emulated computer, without affecting the others. Can be called from within programs via ccemux.closeEmu().\
11001\
11002* emu open [id]\
11003Opens 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)\
11004\
11005* emu data\
11006This 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)\
11007\
11008* emu config\
11009Opens an interface to edit the CCEmuX configuration. Note that not all rendering backends support this.\
11010\
11011CREDITS\
11012\
11013* Lignum - developer\
11014* apemanzilla - developer\
11015* Lemmmy - contributions to ccemux API and program\
11016* SquidDev - CCTweaks support and general help during development\
11017* BombBloke - created and allowed us to use the HD font\
11018\
11019LICENSE INFORMATION\
11020\
11021CCEmuX is licensed under the MIT license. The complete source code and license for CCEmuX can be found at https://github.com/Lignum/CCEmuX\
11022\
11023CCEmuX 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",
11024 [ "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.\
11025The HTTP API must be enabled in ComputerCraft.cfg to use this program.\
11026\
11027ex:\
11028\"pastebin put foo\" will upload the file \"foo\" to pastebin.com, and print the URL.\
11029\"pastebin get xq5gc7LB foo\" will download the file from the URL http://pastebin.com/xq5gc7LB, and save it as \"foo\".\
11030\"pastebin run CxaWmPrX\" will download the file from the URL http://pastebin.com/CxaWmPrX, and immediately run it.",
11031 [ "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.\
11032\
11033Methods exposed by the Monitor:\
11034write( text )\
11035blit( text, textColor, backgroundColor )\
11036clear()\
11037clearLine()\
11038getCursorPos()\
11039setCursorPos( x, y )\
11040setCursorBlink( blink )\
11041isColor()\
11042setTextColor( color )\
11043setBackgroundColor( color )\
11044getTextColor()\
11045getBackgroundColor()\
11046getSize()\
11047scroll( n )\
11048setPaletteColor( color, r, g, b )\
11049getPaletteColor( color )\
11050\
11051Events fired by the Monitor:\
11052\"monitor_touch\" when an Advanced Monitor is touched by the player. Arguments are name, x, y\
11053\"monitor_resize\" when the size of a Monitor changes. Argument is the name of the monitor.",
11054 [ "modules/command/.ignoreme" ] = "--[[\
11055Alright then, don't ignore me. This file is to ensure the existence of the \"modules/command\" folder.\
11056You can use this folder to add modules who can be loaded with require() to your Resourcepack.\
11057]]",
11058 [ "help/window.txt" ] = "Functions in the window API:\
11059window.create( parent, x, y, width, height, visible )\
11060\
11061Windows created with the window API have the following methods:\
11062write( text )\
11063blit( text, textColor, backgroundColor )\
11064clear()\
11065clearLine()\
11066getCursorPos()\
11067setCursorPos( x, y )\
11068setCursorBlink( blink )\
11069isColor()\
11070setTextColor( color )\
11071setBackgroundColor( color )\
11072getTextColor()\
11073getBackgroundColor()\
11074getSize()\
11075scroll( n )\
11076setVisible( bVisible )\
11077redraw()\
11078restoreCursor()\
11079getPosition()\
11080reposition( x, y, width, height )\
11081getPaletteColor( color )\
11082setPaletteColor( color, r, g, b )",
11083 [ "help/commands.txt" ] = "On a Command Computer, \"commands\" will list all the commands available for use. Use \"exec\" to execute them.\
11084Type \"help commandsapi\" for help using commands in lua programs.",
11085 [ "apis/io.lua" ] = "-- Definition for the IO API\
11086local typeOf = _G.type\
11087\
11088--- If we return nil then close the file, as we've reached the end.\
11089-- We use this weird wrapper function as we wish to preserve the varargs\
11090local function checkResult(handle, ...)\
11091 if ... == nil and handle._autoclose and not handle._closed then handle:close() end\
11092 return ...\
11093end\
11094\
11095local handleMetatable\
11096handleMetatable = {\
11097 __name = \"FILE*\",\
11098 __tostring = function(self)\
11099 if self._closed then\
11100 return \"file (closed)\"\
11101 else\
11102 local hash = tostring(self._handle):match(\"table: (%x+)\")\
11103 return \"file (\" .. hash .. \")\"\
11104 end\
11105 end,\
11106 __index = {\
11107 close = function(self)\
11108 if typeOf(self) ~= \"table\" or getmetatable(self) ~= handleMetatable then\
11109 error(\"bad argument #1 (FILE expected, got \" .. typeOf(self) .. \")\", 2)\
11110 end\
11111 if self._closed then error(\"attempt to use a closed file\", 2) end\
11112\
11113 local handle = self._handle\
11114 if handle.close then\
11115 self._closed = true\
11116 handle.close()\
11117 return true\
11118 else\
11119 return nil, \"attempt to close standard stream\"\
11120 end\
11121 end,\
11122 flush = function(self)\
11123 if typeOf(self) ~= \"table\" or getmetatable(self) ~= handleMetatable then\
11124 error(\"bad argument #1 (FILE expected, got \" .. typeOf(self) .. \")\", 2)\
11125 end\
11126 if self._closed then error(\"attempt to use a closed file\", 2) end\
11127\
11128 local handle = self._handle\
11129 if handle.flush then handle.flush() end\
11130 end,\
11131 lines = function(self, ...)\
11132 if typeOf(self) ~= \"table\" or getmetatable(self) ~= handleMetatable then\
11133 error(\"bad argument #1 (FILE expected, got \" .. typeOf(self) .. \")\", 2)\
11134 end\
11135 if self._closed then error(\"attempt to use a closed file\", 2) end\
11136\
11137 local handle = self._handle\
11138 if not handle.read then return nil, \"file is not readable\" end\
11139\
11140 local args = table.pack(...)\
11141 return function() return checkResult(self, self:read(table.unpack(args, 1, args.n))) end\
11142 end,\
11143 read = function(self, ...)\
11144 if typeOf(self) ~= \"table\" or getmetatable(self) ~= handleMetatable then\
11145 error(\"bad argument #1 (FILE expected, got \" .. typeOf(self) .. \")\", 2)\
11146 end\
11147 if self._closed then error(\"attempt to use a closed file\", 2) end\
11148\
11149 local handle = self._handle\
11150 if not handle.read and not handle.readLine then return nil, \"Not opened for reading\" end\
11151\
11152 local n = select('#', ...)\
11153 local output = {}\
11154 for i = 1, n do\
11155 local arg = select(i, ...)\
11156 local res\
11157 if typeOf(arg) == \"number\" then\
11158 if handle.read then res = handle.read(arg) end\
11159 elseif typeOf(arg) == \"string\" then\
11160 local format = arg:gsub(\"^%*\", \"\"):sub(1, 1)\
11161\
11162 if format == \"l\" then\
11163 if handle.readLine then res = handle.readLine() end\
11164 elseif format == \"L\" and handle.readLine then\
11165 if handle.readLine then res = handle.readLine(true) end\
11166 elseif format == \"a\" then\
11167 if handle.readAll then res = handle.readAll() or \"\" end\
11168 elseif format == \"n\" then\
11169 res = nil -- Skip this format as we can't really handle it\
11170 else\
11171 error(\"bad argument #\" .. i .. \" (invalid format)\", 2)\
11172 end\
11173 else\
11174 error(\"bad argument #\" .. i .. \" (expected string, got \" .. typeOf(arg) .. \")\", 2)\
11175 end\
11176\
11177 output[i] = res\
11178 if not res then break end\
11179 end\
11180\
11181 -- Default to \"l\" if possible\
11182 if n == 0 and handle.readLine then return handle.readLine() end\
11183 return table.unpack(output, 1, n)\
11184 end,\
11185 seek = function(self, whence, offset)\
11186 if typeOf(self) ~= \"table\" or getmetatable(self) ~= handleMetatable then\
11187 error(\"bad argument #1 (FILE expected, got \" .. typeOf(self) .. \")\", 2)\
11188 end\
11189 if self._closed then error(\"attempt to use a closed file\", 2) end\
11190\
11191 local handle = self._handle\
11192 if not handle.seek then return nil, \"file is not seekable\" end\
11193\
11194 -- It's a tail call, so error positions are preserved\
11195 return handle.seek(whence, offset)\
11196 end,\
11197 setvbuf = function(self, mode, size) end,\
11198 write = function(self, ...)\
11199 if typeOf(self) ~= \"table\" or getmetatable(self) ~= handleMetatable then\
11200 error(\"bad argument #1 (FILE expected, got \" .. typeOf(self) .. \")\", 2)\
11201 end\
11202 if self._closed then error(\"attempt to use a closed file\", 2) end\
11203\
11204 local handle = self._handle\
11205 if not handle.write then return nil, \"file is not writable\" end\
11206\
11207 local n = select(\"#\", ...)\
11208 for i = 1, n do handle.write(select(i, ...)) end\
11209 return self\
11210 end,\
11211 },\
11212}\
11213\
11214local defaultInput = setmetatable({\
11215 _handle = { readLine = _G.read }\
11216}, handleMetatable)\
11217\
11218local defaultOutput = setmetatable({\
11219 _handle = { write = _G.write }\
11220}, handleMetatable)\
11221\
11222local defaultError = setmetatable({\
11223 _handle = {\
11224 write = function(...)\
11225 local oldColour\
11226 if term.isColour() then\
11227 oldColour = term.getTextColour()\
11228 term.setTextColour(colors.red)\
11229 end\
11230 _G.write(...)\
11231 if term.isColour() then term.setTextColour(oldColour) end\
11232 end,\
11233 }\
11234}, handleMetatable)\
11235\
11236local currentInput = defaultInput\
11237local currentOutput = defaultOutput\
11238\
11239stdin = defaultInput\
11240stdout = defaultOutput\
11241stderr = defaultError\
11242\
11243function close(_file)\
11244 if _file == nil then return currentOutput:close() end\
11245\
11246 if typeOf(_file) ~= \"table\" or getmetatable(_file) ~= handleMetatable then\
11247 error(\"bad argument #1 (FILE expected, got \" .. typeOf(_file) .. \")\", 2)\
11248 end\
11249 return _file:close()\
11250end\
11251\
11252function flush()\
11253 return currentOutput:flush()\
11254end\
11255\
11256function input(_arg)\
11257 if typeOf(_arg) == \"string\" then\
11258 local res, err = open(_arg, \"rb\")\
11259 if not res then error(err, 2) end\
11260 currentInput = res\
11261 elseif typeOf(_arg) == \"table\" and getmetatable(_arg) == handleMetatable then\
11262 currentInput = _arg\
11263 elseif _arg ~= nil then\
11264 error(\"bad argument #1 (FILE expected, got \" .. typeOf(_arg) .. \")\", 2)\
11265 end\
11266\
11267 return currentInput\
11268end\
11269\
11270function lines(_sFileName)\
11271 if _sFileName ~= nil and typeOf(_sFileName) ~= \"string\" then\
11272 error(\"bad argument #1 (expected string, got \" .. typeOf(_sFileName) .. \")\", 2)\
11273 end\
11274 if _sFileName then\
11275 local ok, err = open(_sFileName, \"rb\")\
11276 if not ok then error(err, 2) end\
11277\
11278 -- We set this magic flag to mark this file as being opened by io.lines and so should be\
11279 -- closed automatically\
11280 ok._autoclose = true\
11281 return ok:lines()\
11282 else\
11283 return currentInput:lines()\
11284 end\
11285end\
11286\
11287function open(_sPath, _sMode)\
11288 if typeOf(_sPath) ~= \"string\" then\
11289 error(\"bad argument #1 (expected string, got \" .. typeOf(_sPath) .. \")\", 2)\
11290 end\
11291 if _sMode ~= nil and typeOf(_sMode) ~= \"string\" then\
11292 error(\"bad argument #2 (expected string, got \" .. typeOf(_sMode) .. \")\", 2)\
11293 end\
11294\
11295 local sMode = _sMode and _sMode:gsub(\"%+\", \"\") or \"rb\"\
11296 local file, err = fs.open(_sPath, sMode)\
11297 if not file then return nil, err end\
11298\
11299 return setmetatable({ _handle = file }, handleMetatable)\
11300end\
11301\
11302function output(_arg)\
11303 if typeOf(_arg) == \"string\" then\
11304 local res, err = open(_arg, \"w\")\
11305 if not res then error(err, 2) end\
11306 currentOutput = res\
11307 elseif typeOf(_arg) == \"table\" and getmetatable(_arg) == handleMetatable then\
11308 currentOutput = _arg\
11309 elseif _arg ~= nil then\
11310 error(\"bad argument #1 (FILE expected, got \" .. typeOf(_arg) .. \")\", 2)\
11311 end\
11312\
11313 return currentOutput\
11314end\
11315\
11316function read(...)\
11317 return currentInput:read(...)\
11318end\
11319\
11320function type(handle)\
11321 if typeOf(handle) == \"table\" and getmetatable(handle) == handleMetatable then\
11322 if handle._closed then\
11323 return \"closed file\"\
11324 else\
11325 return \"file\"\
11326 end\
11327 end\
11328 return nil\
11329end\
11330\
11331function write(...)\
11332 return currentOutput:write(...)\
11333end",
11334 [ "help/rs.txt" ] = "Functions in the Redstone API:\
11335rs.getSides( )\
11336rs.getInput( side )\
11337rs.setOutput( side, boolean )\
11338rs.getOutput( side )\
11339rs.getAnalogInput( side )\
11340rs.setAnalogOutput( side, number )\
11341rs.getAnalogOutput( side )\
11342\
11343Functions in the Redstone API for working with RedPower bundled cables:\
11344rs.getBundledInput( side )\
11345rs.testBundledInput( side, color )\
11346rs.setBundledOutput( side, colors )\
11347rs.getBundledOutput( side )\
11348Type \"help bundled\" for usage examples.\
11349\
11350Events emitted by the redstone API:\
11351\"redstone\", when the state of any redstone input changes. Use getInput() or getBundledInput() to inspect the changes\
11352Type \"help events\" to learn about the event system.",
11353 [ "help/http.txt" ] = "Functions in the HTTP API:\
11354http.checkURL( url )\
11355http.checkURLAsync( url )\
11356http.request( url, [postData], [headers] )\
11357http.get( url, [headers] )\
11358http.post( url, postData, [headers] )\
11359\
11360The HTTP API may be disabled in ComputerCraft.cfg\
11361A 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.",
11362 [ "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.",
11363 [ "help/bg.txt" ] = "bg is a program for Advanced Computers which opens a new tab in the background.\
11364\
11365ex:\
11366\"bg\" will open a background tab running the shell\
11367\"bg worm\" will open a background tab running the \"worm\" program",
11368 [ "help/gpsapi.txt" ] = "Functions in the GPS API:\
11369gps.locate( timeout )\
11370\
11371The 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.",
11372 [ "help/multishell.txt" ] = "multishell is the toplevel program on Advanced Computers which manages background tabs.\
11373Type \"help shellapi\" for information about the shell lua api.",
11374 [ "help/vector.txt" ] = "Functions in the 3D Vector Math API:\
11375vector.new( x,y,z )\
11376\
11377Vectors returned by vector.new() have the following fields and methods:\
11378vector.x\
11379vector.y\
11380vector.z\
11381vector:add( vector )\
11382vector:sub( vector )\
11383vector:mul( number )\
11384vector:dot( vector )\
11385vector:cross( vector )\
11386vector:length()\
11387vector:normalize()\
11388vector:round()\
11389vector:tostring()\
11390The +, - and * operators can also be used on vectors.",
11391 [ "help/alias.txt" ] = "alias assigns shell commands to run other programs.\
11392\
11393ex:\
11394\"alias dir ls\" will make the \"dir\" command run the \"ls\" program\
11395\"alias dir\" will remove the alias set on \"dir\"\
11396\"alias\" will list all current aliases.",
11397 [ "help/shellapi.txt" ] = "Functions in the Shell API:\
11398shell.exit()\
11399shell.dir()\
11400shell.setDir( path )\
11401shell.path()\
11402shell.setPath( path )\
11403shell.resolve( localpath )\
11404shell.resolveProgram( name )\
11405shell.aliases()\
11406shell.setAlias( alias, command )\
11407shell.clearAlias( alias )\
11408shell.programs()\
11409shell.run( program, arguments )\
11410shell.getRunningProgram()\
11411shell.complete( line )\
11412shell.completeProgram( program )\
11413shell.setCompletionFunction( program, fnComplete )\
11414shell.openTab( program, arguments ) (Advanced Computer required)\
11415shell.switchTab( n ) (Advanced Computer required)",
11416 [ "programs/turtle/tunnel.lua" ] = "\
11417local tArgs = { ... }\
11418if #tArgs ~= 1 then\
11419 print( \"Usage: tunnel <length>\" )\
11420 return\
11421end\
11422\
11423-- Mine in a quarry pattern until we hit something we can't dig\
11424local length = tonumber( tArgs[1] )\
11425if length < 1 then\
11426 print( \"Tunnel length must be positive\" )\
11427 return\
11428end\
11429\
11430local depth = 0\
11431local collected = 0\
11432\
11433local function collect()\
11434 collected = collected + 1\
11435 if math.fmod(collected, 25) == 0 then\
11436 print( \"Mined \"..collected..\" items.\" )\
11437 end\
11438end\
11439\
11440local function tryDig()\
11441 while turtle.detect() do\
11442 if turtle.dig() then\
11443 collect()\
11444 sleep(0.5)\
11445 else\
11446 return false\
11447 end\
11448 end\
11449 return true\
11450end\
11451\
11452local function tryDigUp()\
11453 while turtle.detectUp() do\
11454 if turtle.digUp() then\
11455 collect()\
11456 sleep(0.5)\
11457 else\
11458 return false\
11459 end\
11460 end\
11461 return true\
11462end\
11463\
11464local function tryDigDown()\
11465 while turtle.detectDown() do\
11466 if turtle.digDown() then\
11467 collect()\
11468 sleep(0.5)\
11469 else\
11470 return false\
11471 end\
11472 end\
11473 return true\
11474end\
11475\
11476local function refuel()\
11477 local fuelLevel = turtle.getFuelLevel()\
11478 if fuelLevel == \"unlimited\" or fuelLevel > 0 then\
11479 return\
11480 end\
11481\
11482 local function tryRefuel()\
11483 for n=1,16 do\
11484 if turtle.getItemCount(n) > 0 then\
11485 turtle.select(n)\
11486 if turtle.refuel(1) then\
11487 turtle.select(1)\
11488 return true\
11489 end\
11490 end\
11491 end\
11492 turtle.select(1)\
11493 return false\
11494 end\
11495\
11496 if not tryRefuel() then\
11497 print( \"Add more fuel to continue.\" )\
11498 while not tryRefuel() do\
11499 os.pullEvent( \"turtle_inventory\" )\
11500 end\
11501 print( \"Resuming Tunnel.\" )\
11502 end\
11503end\
11504\
11505local function tryUp()\
11506 refuel()\
11507 while not turtle.up() do\
11508 if turtle.detectUp() then\
11509 if not tryDigUp() then\
11510 return false\
11511 end\
11512 elseif turtle.attackUp() then\
11513 collect()\
11514 else\
11515 sleep( 0.5 )\
11516 end\
11517 end\
11518 return true\
11519end\
11520\
11521local function tryDown()\
11522 refuel()\
11523 while not turtle.down() do\
11524 if turtle.detectDown() then\
11525 if not tryDigDown() then\
11526 return false\
11527 end\
11528 elseif turtle.attackDown() then\
11529 collect()\
11530 else\
11531 sleep( 0.5 )\
11532 end\
11533 end\
11534 return true\
11535end\
11536\
11537local function tryForward()\
11538 refuel()\
11539 while not turtle.forward() do\
11540 if turtle.detect() then\
11541 if not tryDig() then\
11542 return false\
11543 end\
11544 elseif turtle.attack() then\
11545 collect()\
11546 else\
11547 sleep( 0.5 )\
11548 end\
11549 end\
11550 return true\
11551end\
11552\
11553print( \"Tunnelling...\" )\
11554\
11555for n=1,length do\
11556 turtle.placeDown()\
11557 tryDigUp()\
11558 turtle.turnLeft()\
11559 tryDig()\
11560 tryUp()\
11561 tryDig()\
11562 turtle.turnRight()\
11563 turtle.turnRight()\
11564 tryDig()\
11565 tryDown()\
11566 tryDig()\
11567 turtle.turnLeft()\
11568\
11569 if n<length then\
11570 tryDig()\
11571 if not tryForward() then\
11572 print( \"Aborting Tunnel.\" )\
11573 break\
11574 end\
11575 else\
11576 print( \"Tunnel complete.\" )\
11577 end\
11578\
11579end\
11580\
11581--[[\
11582print( \"Returning to start...\" )\
11583\
11584-- Return to where we started\
11585turtle.turnLeft()\
11586turtle.turnLeft()\
11587while depth > 0 do\
11588 if turtle.forward() then\
11589 depth = depth - 1\
11590 else\
11591 turtle.dig()\
11592 end\
11593end\
11594turtle.turnRight()\
11595turtle.turnRight()\
11596]]\
11597\
11598print( \"Tunnel complete.\" )\
11599print( \"Mined \"..collected..\" items total.\" )",
11600 [ "apis/disk.lua" ] = "\
11601local function isDrive( name )\
11602 if type( name ) ~= \"string\" then\
11603 error( \"bad argument #1 (expected string, got \" .. type( name ) .. \")\", 3 )\
11604 end\
11605 return peripheral.getType( name ) == \"drive\"\
11606end\
11607\
11608function isPresent( name )\
11609 if isDrive( name ) then\
11610 return peripheral.call( name, \"isDiskPresent\" )\
11611 end\
11612 return false\
11613end\
11614\
11615function getLabel( name )\
11616 if isDrive( name ) then\
11617 return peripheral.call( name, \"getDiskLabel\" )\
11618 end\
11619 return nil\
11620end\
11621\
11622function setLabel( name, label )\
11623 if isDrive( name ) then\
11624 peripheral.call( name, \"setDiskLabel\", label )\
11625 end\
11626end\
11627\
11628function hasData( name )\
11629 if isDrive( name ) then\
11630 return peripheral.call( name, \"hasData\" )\
11631 end\
11632 return false\
11633end\
11634\
11635function getMountPath( name )\
11636 if isDrive( name ) then\
11637 return peripheral.call( name, \"getMountPath\" )\
11638 end\
11639 return nil\
11640end\
11641\
11642function hasAudio( name )\
11643 if isDrive( name ) then\
11644 return peripheral.call( name, \"hasAudio\" )\
11645 end\
11646 return false\
11647end\
11648\
11649function getAudioTitle( name )\
11650 if isDrive( name ) then\
11651 return peripheral.call( name, \"getAudioTitle\" )\
11652 end\
11653 return nil\
11654end\
11655\
11656function playAudio( name )\
11657 if isDrive( name ) then\
11658 peripheral.call( name, \"playAudio\" )\
11659 end\
11660end\
11661\
11662function stopAudio( name )\
11663 if not name then\
11664 for n,sName in ipairs( peripheral.getNames() ) do\
11665 stopAudio( sName )\
11666 end\
11667 else\
11668 if isDrive( name ) then\
11669 peripheral.call( name, \"stopAudio\" )\
11670 end\
11671 end\
11672end\
11673\
11674function eject( name )\
11675 if isDrive( name ) then\
11676 peripheral.call( name, \"ejectDisk\" )\
11677 end\
11678end\
11679\
11680function getID( name )\
11681 if isDrive( name ) then\
11682 return peripheral.call( name, \"getDiskID\" )\
11683 end\
11684 return nil\
11685end\
11686",
11687 [ "help/craft.txt" ] = "craft is a program for Crafty Turtles. Craft will craft a stack of items using the current inventory.\
11688\
11689ex:\
11690\"craft\" will craft as many items as possible\
11691\"craft 5\" will craft at most 5 times",
11692 [ "help/redstoneapi.txt" ] = "Functions in the Redstone API:\
11693redstone.getSides( )\
11694redstone.getInput( side )\
11695redstone.setOutput( side, boolean )\
11696redstone.getOutput( side )\
11697redstone.getAnalogInput( side )\
11698redstone.setAnalogOutput( side, number )\
11699redstone.getAnalogOutput( side )\
11700\
11701Functions in the Redstone API for working with bundled cables:\
11702redstone.getBundledInput( side )\
11703redstone.testBundledInput( side, color )\
11704redstone.setBundledOutput( side, colors )\
11705redstone.getBundledOutput( side )\
11706Type \"help bundled\" for usage examples.\
11707\
11708Events emitted by the redstone API:\
11709\"redstone\", when the state of any redstone input changes. Use getInput() or getBundledInput() to inspect the changes\
11710Type \"help events\" to learn about the event system.",
11711 [ "help/peripherals.txt" ] = "The \"peripherals\" program will list all of the peripheral devices accessible from this computer.\
11712Peripherals are external devices which CraftOS Computers and Turtles can interact with using the peripheral API.\
11713Type \"help peripheral\" to learn about using the peripheral API.\
11714Type \"help drives\" to learn about using Disk Drives.\
11715Type \"help modems\" to learn about using Modems.\
11716Type \"help monitors\" to learn about using Monitors.\
11717Type \"help printers\" to learn about using Printers.",
11718 [ "autorun/.ignoreme" ] = "--[[\
11719Alright then, don't ignore me. This file is to ensure the existence of the \"autorun\" folder, files placed in this folder\
11720using resource packs will always run when computers startup.\
11721]]",
11722 [ "help/earth.txt" ] = "Mostly harmless.",
11723 [ "programs/turtle/refuel.lua" ] = "\
11724local tArgs = { ... }\
11725local nLimit = 1\
11726if #tArgs > 1 then\
11727 print( \"Usage: refuel [number]\" )\
11728 return\
11729elseif #tArgs > 0 then\
11730 if tArgs[1] == \"all\" then\
11731 nLimit = nil\
11732 else\
11733 nLimit = tonumber( tArgs[1] )\
11734 if not nLimit then\
11735 print(\"Invalid limit, expected a number or \\\"all\\\"\")\
11736 return\
11737 end\
11738 end\
11739end\
11740\
11741if turtle.getFuelLevel() ~= \"unlimited\" then\
11742 for n = 1, 16 do\
11743 -- Stop if we've reached the limit, or are fully refuelled.\
11744 if (nLimit and nLimit <= 0) or turtle.getFuelLevel() >= turtle.getFuelLimit() then\
11745 break\
11746 end\
11747\
11748 local nCount = turtle.getItemCount(n)\
11749 if nCount > 0 then\
11750 turtle.select( n )\
11751 if turtle.refuel( nLimit ) and nLimit then\
11752 local nNewCount = turtle.getItemCount(n)\
11753 nLimit = nLimit - (nCount - nNewCount)\
11754 end\
11755 end\
11756 end\
11757 print( \"Fuel level is \"..turtle.getFuelLevel() )\
11758 if turtle.getFuelLevel() == turtle.getFuelLimit() then\
11759 print( \"Fuel limit reached\" )\
11760 end\
11761else\
11762 print( \"Fuel level is unlimited\" )\
11763end",
11764 [ "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.\
11765\
11766ex:\
11767\"edit mario\" opens an image called \"mario\" for editing.",
11768 [ "help/bit.txt" ] = "Functions in the bit manipulation API (NOTE: This API will be removed in a future version. Use bit32 instead):\
11769bit.bnot(n) -- bitwise not (~n)\
11770bit.band(m, n) -- bitwise and (m & n)\
11771bit.bor(m, n) -- bitwise or (m | n)\
11772bit.bxor(m, n) -- bitwise xor (m ^ n)\
11773bit.brshift(n, bits) -- right shift (n >> bits)\
11774bit.blshift(n, bits) -- left shift (n << bits)",
11775 [ "help/drive.txt" ] = "drive tells you which disk drive the current or specified directory is located in.\
11776\
11777ex:\
11778\"drive\" tell you the disk drive of the current directory.\
11779\"drive foo\" tells you the disk drive of the subdirectory \"foo\"",
11780 [ "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.\
11781\
11782Some events which can occur are:\
11783\"char\" when text is typed on the keyboard. Argument is the character typed.\
11784\"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.\
11785\"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.\
11786\"paste\" when text is pasted from the users keyboard. Argument is the line of text pasted.\
11787\
11788Events only on advanced computers:\
11789\"mouse_click\" when a user clicks the mouse. Arguments are button, xPos, yPos.\
11790\"mouse_drag\" when a user moves the mouse when held. Arguments are button, xPos, yPos.\
11791\"mouse_up\" when a user releases the mouse button. Arguments are button, xPos, yPos.\
11792\"mouse_scroll\" when a user uses the scrollwheel on the mouse. Arguments are direction, xPos, yPos.\
11793\
11794Other APIs and peripherals will emit their own events. See their respective help pages for details.",
11795 [ "help/help.txt" ] = "help is the help tool you're currently using.\
11796Type \"help index\" to see all help topics.\
11797Type \"help\" to see the help intro.\
11798Type \"help helpapi\" for information on the help Lua API.",
11799 [ "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\".\
11800\
11801Methods exposed by Modems:\
11802open( channel )\
11803isOpen( channel )\
11804close( channel )\
11805closeAll()\
11806transmit( channel, replyChannel, message )\
11807isWireless()\
11808\
11809Events fired by Modems:\
11810\"modem_message\" when a message is received on an open channel. Arguments are name, channel, replyChannel, message, distance",
11811 [ "help/keys.txt" ] = "The keys API contains constants for all the key codes that can be returned by the \"key\" event:\
11812\
11813Example usage:\
11814local sEvent, nKey = os.pullEvent()\
11815if sEvent == \"key\" and nKey == keys.enter then\
11816 -- Do something \
11817end\
11818\
11819See http://www.minecraftwiki.net/wiki/Key_codes, or the source code, for a complete reference.",
11820 [ "modules/turtle/.ignoreme" ] = "--[[\
11821Alright then, don't ignore me. This file is to ensure the existence of the \"modules/turtle\" folder.\
11822You can use this folder to add modules who can be loaded with require() to your Resourcepack.\
11823]]",
11824 [ "apis/window.lua" ] = "\
11825local tHex = {\
11826 [ colors.white ] = \"0\",\
11827 [ colors.orange ] = \"1\",\
11828 [ colors.magenta ] = \"2\",\
11829 [ colors.lightBlue ] = \"3\",\
11830 [ colors.yellow ] = \"4\",\
11831 [ colors.lime ] = \"5\",\
11832 [ colors.pink ] = \"6\",\
11833 [ colors.gray ] = \"7\",\
11834 [ colors.lightGray ] = \"8\",\
11835 [ colors.cyan ] = \"9\",\
11836 [ colors.purple ] = \"a\",\
11837 [ colors.blue ] = \"b\",\
11838 [ colors.brown ] = \"c\",\
11839 [ colors.green ] = \"d\",\
11840 [ colors.red ] = \"e\",\
11841 [ colors.black ] = \"f\",\
11842}\
11843\
11844local type = type\
11845local string_rep = string.rep\
11846local string_sub = string.sub\
11847local table_unpack = table.unpack\
11848\
11849function create( parent, nX, nY, nWidth, nHeight, bStartVisible )\
11850 if type( parent ) ~= \"table\" then error( \"bad argument #1 (expected table, got \" .. type( parent ) .. \")\", 2 ) end\
11851 if type( nX ) ~= \"number\" then error( \"bad argument #2 (expected number, got \" .. type( nX ) .. \")\", 2 ) end\
11852 if type( nY ) ~= \"number\" then error( \"bad argument #3 (expected number, got \" .. type( nY ) .. \")\", 2 ) end\
11853 if type( nWidth ) ~= \"number\" then error( \"bad argument #4 (expected number, got \" .. type( nWidth ) .. \")\", 2 ) end\
11854 if type( nHeight ) ~= \"number\" then error( \"bad argument #5 (expected number, got \" .. type( nHeight ) .. \")\", 2 ) end\
11855 if bStartVisible ~= nil and type( bStartVisible ) ~= \"boolean\" then error( \"bad argument #6 (expected boolean, got \" .. type( bStartVisible ) .. \")\", 2 ) end\
11856\
11857 if parent == term then\
11858 error( \"term is not a recommended window parent, try term.current() instead\", 2 )\
11859 end\
11860\
11861 local sEmptySpaceLine\
11862 local tEmptyColorLines = {}\
11863 local function createEmptyLines( nWidth )\
11864 sEmptySpaceLine = string_rep( \" \", nWidth )\
11865 for n=0,15 do\
11866 local nColor = 2^n\
11867 local sHex = tHex[nColor]\
11868 tEmptyColorLines[nColor] = string_rep( sHex, nWidth )\
11869 end\
11870 end\
11871\
11872 createEmptyLines( nWidth )\
11873\
11874 -- Setup\
11875 local bVisible = (bStartVisible ~= false)\
11876 local nCursorX = 1\
11877 local nCursorY = 1\
11878 local bCursorBlink = false\
11879 local nTextColor = colors.white\
11880 local nBackgroundColor = colors.black\
11881 local tLines = {}\
11882 local tPalette = {}\
11883 do\
11884 local sEmptyText = sEmptySpaceLine\
11885 local sEmptyTextColor = tEmptyColorLines[ nTextColor ]\
11886 local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ]\
11887 for y=1,nHeight do\
11888 tLines[y] = {\
11889 text = sEmptyText,\
11890 textColor = sEmptyTextColor,\
11891 backgroundColor = sEmptyBackgroundColor,\
11892 }\
11893 end\
11894\
11895 for i=0,15 do\
11896 local c = 2 ^ i\
11897 tPalette[c] = { parent.getPaletteColour( c ) }\
11898 end\
11899 end\
11900\
11901 -- Helper functions\
11902 local function updateCursorPos()\
11903 if nCursorX >= 1 and nCursorY >= 1 and\
11904 nCursorX <= nWidth and nCursorY <= nHeight then\
11905 parent.setCursorPos( nX + nCursorX - 1, nY + nCursorY - 1 )\
11906 else\
11907 parent.setCursorPos( 0, 0 )\
11908 end\
11909 end\
11910\
11911 local function updateCursorBlink()\
11912 parent.setCursorBlink( bCursorBlink )\
11913 end\
11914\
11915 local function updateCursorColor()\
11916 parent.setTextColor( nTextColor )\
11917 end\
11918\
11919 local function redrawLine( n )\
11920 local tLine = tLines[ n ]\
11921 parent.setCursorPos( nX, nY + n - 1 )\
11922 parent.blit( tLine.text, tLine.textColor, tLine.backgroundColor )\
11923 end\
11924\
11925 local function redraw()\
11926 for n=1,nHeight do\
11927 redrawLine( n )\
11928 end\
11929 end\
11930\
11931 local function updatePalette()\
11932 for k,v in pairs( tPalette ) do\
11933 parent.setPaletteColour( k, v[1], v[2], v[3] )\
11934 end\
11935 end\
11936\
11937 local function internalBlit( sText, sTextColor, sBackgroundColor )\
11938 local nStart = nCursorX\
11939 local nEnd = nStart + #sText - 1\
11940 if nCursorY >= 1 and nCursorY <= nHeight then\
11941 if nStart <= nWidth and nEnd >= 1 then\
11942 -- Modify line\
11943 local tLine = tLines[ nCursorY ]\
11944 if nStart == 1 and nEnd == nWidth then\
11945 tLine.text = sText\
11946 tLine.textColor = sTextColor\
11947 tLine.backgroundColor = sBackgroundColor\
11948 else\
11949 local sClippedText, sClippedTextColor, sClippedBackgroundColor\
11950 if nStart < 1 then\
11951 local nClipStart = 1 - nStart + 1\
11952 local nClipEnd = nWidth - nStart + 1\
11953 sClippedText = string_sub( sText, nClipStart, nClipEnd )\
11954 sClippedTextColor = string_sub( sTextColor, nClipStart, nClipEnd )\
11955 sClippedBackgroundColor = string_sub( sBackgroundColor, nClipStart, nClipEnd )\
11956 elseif nEnd > nWidth then\
11957 local nClipEnd = nWidth - nStart + 1\
11958 sClippedText = string_sub( sText, 1, nClipEnd )\
11959 sClippedTextColor = string_sub( sTextColor, 1, nClipEnd )\
11960 sClippedBackgroundColor = string_sub( sBackgroundColor, 1, nClipEnd )\
11961 else\
11962 sClippedText = sText\
11963 sClippedTextColor = sTextColor\
11964 sClippedBackgroundColor = sBackgroundColor\
11965 end\
11966\
11967 local sOldText = tLine.text\
11968 local sOldTextColor = tLine.textColor\
11969 local sOldBackgroundColor = tLine.backgroundColor\
11970 local sNewText, sNewTextColor, sNewBackgroundColor\
11971 if nStart > 1 then\
11972 local nOldEnd = nStart - 1\
11973 sNewText = string_sub( sOldText, 1, nOldEnd ) .. sClippedText\
11974 sNewTextColor = string_sub( sOldTextColor, 1, nOldEnd ) .. sClippedTextColor\
11975 sNewBackgroundColor = string_sub( sOldBackgroundColor, 1, nOldEnd ) .. sClippedBackgroundColor\
11976 else\
11977 sNewText = sClippedText\
11978 sNewTextColor = sClippedTextColor\
11979 sNewBackgroundColor = sClippedBackgroundColor\
11980 end\
11981 if nEnd < nWidth then\
11982 local nOldStart = nEnd + 1\
11983 sNewText = sNewText .. string_sub( sOldText, nOldStart, nWidth )\
11984 sNewTextColor = sNewTextColor .. string_sub( sOldTextColor, nOldStart, nWidth )\
11985 sNewBackgroundColor = sNewBackgroundColor .. string_sub( sOldBackgroundColor, nOldStart, nWidth )\
11986 end\
11987\
11988 tLine.text = sNewText\
11989 tLine.textColor = sNewTextColor\
11990 tLine.backgroundColor = sNewBackgroundColor\
11991 end\
11992\
11993 -- Redraw line\
11994 if bVisible then\
11995 redrawLine( nCursorY )\
11996 end\
11997 end\
11998 end\
11999\
12000 -- Move and redraw cursor\
12001 nCursorX = nEnd + 1\
12002 if bVisible then\
12003 updateCursorColor()\
12004 updateCursorPos()\
12005 end\
12006 end\
12007\
12008 -- Terminal implementation\
12009 local window = {}\
12010\
12011 function window.write( sText )\
12012 sText = tostring( sText )\
12013 internalBlit( sText, string_rep( tHex[ nTextColor ], #sText ), string_rep( tHex[ nBackgroundColor ], #sText ) )\
12014 end\
12015\
12016 function window.blit( sText, sTextColor, sBackgroundColor )\
12017 if type( sText ) ~= \"string\" then error( \"bad argument #1 (expected string, got \" .. type( sText ) .. \")\", 2 ) end\
12018 if type( sTextColor ) ~= \"string\" then error( \"bad argument #2 (expected string, got \" .. type( sTextColor ) .. \")\", 2 ) end\
12019 if type( sBackgroundColor ) ~= \"string\" then error( \"bad argument #3 (expected string, got \" .. type( sBackgroundColor ) .. \")\", 2 ) end\
12020 if #sTextColor ~= #sText or #sBackgroundColor ~= #sText then\
12021 error( \"Arguments must be the same length\", 2 )\
12022 end\
12023 internalBlit( sText, sTextColor, sBackgroundColor )\
12024 end\
12025\
12026 function window.clear()\
12027 local sEmptyText = sEmptySpaceLine\
12028 local sEmptyTextColor = tEmptyColorLines[ nTextColor ]\
12029 local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ]\
12030 for y=1,nHeight do\
12031 tLines[y] = {\
12032 text = sEmptyText,\
12033 textColor = sEmptyTextColor,\
12034 backgroundColor = sEmptyBackgroundColor,\
12035 }\
12036 end\
12037 if bVisible then\
12038 redraw()\
12039 updateCursorColor()\
12040 updateCursorPos()\
12041 end\
12042 end\
12043\
12044 function window.clearLine()\
12045 if nCursorY >= 1 and nCursorY <= nHeight then\
12046 local sEmptyText = sEmptySpaceLine\
12047 local sEmptyTextColor = tEmptyColorLines[ nTextColor ]\
12048 local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ]\
12049 tLines[ nCursorY ] = {\
12050 text = sEmptyText,\
12051 textColor = sEmptyTextColor,\
12052 backgroundColor = sEmptyBackgroundColor,\
12053 }\
12054 if bVisible then\
12055 redrawLine( nCursorY )\
12056 updateCursorColor()\
12057 updateCursorPos()\
12058 end\
12059 end\
12060 end\
12061\
12062 function window.getCursorPos()\
12063 return nCursorX, nCursorY\
12064 end\
12065\
12066 function window.setCursorPos( x, y )\
12067 if type( x ) ~= \"number\" then error( \"bad argument #1 (expected number, got \" .. type( x ) .. \")\", 2 ) end\
12068 if type( y ) ~= \"number\" then error( \"bad argument #2 (expected number, got \" .. type( y ) .. \")\", 2 ) end\
12069 nCursorX = math.floor( x )\
12070 nCursorY = math.floor( y )\
12071 if bVisible then\
12072 updateCursorPos()\
12073 end\
12074 end\
12075\
12076 function window.setCursorBlink( blink )\
12077 if type( blink ) ~= \"boolean\" then error( \"bad argument #1 (expected boolean, got \" .. type( blink ) .. \")\", 2 ) end\
12078 bCursorBlink = blink\
12079 if bVisible then\
12080 updateCursorBlink()\
12081 end\
12082 end\
12083\
12084 function window.getCursorBlink()\
12085 return bCursorBlink\
12086 end\
12087\
12088 local function isColor()\
12089 return parent.isColor()\
12090 end\
12091\
12092 function window.isColor()\
12093 return isColor()\
12094 end\
12095\
12096 function window.isColour()\
12097 return isColor()\
12098 end\
12099\
12100 local function setTextColor( color )\
12101 if type( color ) ~= \"number\" then\
12102 error( \"bad argument #1 (expected number, got \" .. type( color ) .. \")\", 2 )\
12103 elseif tHex[color] == nil then\
12104 error( \"Invalid color (got \" .. color .. \")\" , 2 )\
12105 end\
12106 nTextColor = color\
12107 if bVisible then\
12108 updateCursorColor()\
12109 end\
12110 end\
12111\
12112 window.setTextColor = setTextColor\
12113 window.setTextColour = setTextColor\
12114\
12115 function window.setPaletteColour( colour, r, g, b )\
12116 if type( colour ) ~= \"number\" then error( \"bad argument #1 (expected number, got \" .. type( colour ) .. \")\", 2 ) end\
12117\
12118 if tHex[colour] == nil then\
12119 error( \"Invalid color (got \" .. colour .. \")\" , 2 )\
12120 end\
12121\
12122 local tCol\
12123 if type(r) == \"number\" and g == nil and b == nil then\
12124 tCol = { colours.unpackRGB( r ) }\
12125 tPalette[ colour ] = tCol\
12126 else\
12127 if type( r ) ~= \"number\" then error( \"bad argument #2 (expected number, got \" .. type( r ) .. \")\", 2 ) end\
12128 if type( g ) ~= \"number\" then error( \"bad argument #3 (expected number, got \" .. type( g ) .. \")\", 2 ) end\
12129 if type( b ) ~= \"number\" then error( \"bad argument #4 (expected number, got \" .. type( b ) .. \")\", 2 ) end\
12130\
12131 tCol = tPalette[ colour ]\
12132 tCol[1] = r\
12133 tCol[2] = g\
12134 tCol[3] = b\
12135 end\
12136\
12137 if bVisible then\
12138 return parent.setPaletteColour( colour, tCol[1], tCol[2], tCol[3] )\
12139 end\
12140 end\
12141\
12142 window.setPaletteColor = window.setPaletteColour\
12143\
12144 function window.getPaletteColour( colour )\
12145 if type( colour ) ~= \"number\" then error( \"bad argument #1 (expected number, got \" .. type( colour ) .. \")\", 2 ) end\
12146 if tHex[colour] == nil then\
12147 error( \"Invalid color (got \" .. colour .. \")\" , 2 )\
12148 end\
12149 local tCol = tPalette[ colour ]\
12150 return tCol[1], tCol[2], tCol[3]\
12151 end\
12152\
12153 window.getPaletteColor = window.getPaletteColour\
12154\
12155 local function setBackgroundColor( color )\
12156 if type( color ) ~= \"number\" then\
12157 error( \"bad argument #1 (expected number, got \" .. type( color ) .. \")\", 2 )\
12158 elseif tHex[color] == nil then\
12159 error( \"Invalid color (got \" .. color .. \")\", 2 )\
12160 end\
12161 nBackgroundColor = color\
12162 end\
12163\
12164 window.setBackgroundColor = setBackgroundColor\
12165 window.setBackgroundColour = setBackgroundColor\
12166\
12167 function window.getSize()\
12168 return nWidth, nHeight\
12169 end\
12170\
12171 function window.scroll( n )\
12172 if type( n ) ~= \"number\" then error( \"bad argument #1 (expected number, got \" .. type( n ) .. \")\", 2 ) end\
12173 if n ~= 0 then\
12174 local tNewLines = {}\
12175 local sEmptyText = sEmptySpaceLine\
12176 local sEmptyTextColor = tEmptyColorLines[ nTextColor ]\
12177 local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ]\
12178 for newY=1,nHeight do\
12179 local y = newY + n\
12180 if y >= 1 and y <= nHeight then\
12181 tNewLines[newY] = tLines[y]\
12182 else\
12183 tNewLines[newY] = {\
12184 text = sEmptyText,\
12185 textColor = sEmptyTextColor,\
12186 backgroundColor = sEmptyBackgroundColor,\
12187 }\
12188 end\
12189 end\
12190 tLines = tNewLines\
12191 if bVisible then\
12192 redraw()\
12193 updateCursorColor()\
12194 updateCursorPos()\
12195 end\
12196 end\
12197 end\
12198\
12199 function window.getTextColor()\
12200 return nTextColor\
12201 end\
12202\
12203 function window.getTextColour()\
12204 return nTextColor\
12205 end\
12206\
12207 function window.getBackgroundColor()\
12208 return nBackgroundColor\
12209 end\
12210\
12211 function window.getBackgroundColour()\
12212 return nBackgroundColor\
12213 end\
12214\
12215 -- Other functions\
12216 function window.setVisible( bVis )\
12217 if type( bVis ) ~= \"boolean\" then error( \"bad argument #1 (expected boolean, got \" .. type( bVis ) .. \")\", 2 ) end\
12218 if bVisible ~= bVis then\
12219 bVisible = bVis\
12220 if bVisible then\
12221 window.redraw()\
12222 end\
12223 end\
12224 end\
12225\
12226 function window.redraw()\
12227 if bVisible then\
12228 redraw()\
12229 updatePalette()\
12230 updateCursorBlink()\
12231 updateCursorColor()\
12232 updateCursorPos()\
12233 end\
12234 end\
12235\
12236 function window.restoreCursor()\
12237 if bVisible then\
12238 updateCursorBlink()\
12239 updateCursorColor()\
12240 updateCursorPos()\
12241 end\
12242 end\
12243\
12244 function window.getPosition()\
12245 return nX, nY\
12246 end\
12247\
12248 function window.reposition( nNewX, nNewY, nNewWidth, nNewHeight )\
12249 if type( nNewX ) ~= \"number\" then error( \"bad argument #1 (expected number, got \" .. type( nNewX ) .. \")\", 2 ) end\
12250 if type( nNewY ) ~= \"number\" then error( \"bad argument #2 (expected number, got \" .. type( nNewY ) .. \")\", 2 ) end\
12251 if nNewWidth ~= nil or nNewHeight ~= nil then\
12252 if type( nNewWidth ) ~= \"number\" then error( \"bad argument #3 (expected number, got \" .. type( nNewWidth ) .. \")\", 2 ) end\
12253 if type( nNewHeight ) ~= \"number\" then error( \"bad argument #4 (expected number, got \" .. type( nNewHeight ) .. \")\", 2 ) end\
12254 end\
12255\
12256 nX = nNewX\
12257 nY = nNewY\
12258 if nNewWidth and nNewHeight then\
12259 local tNewLines = {}\
12260 createEmptyLines( nNewWidth )\
12261 local sEmptyText = sEmptySpaceLine\
12262 local sEmptyTextColor = tEmptyColorLines[ nTextColor ]\
12263 local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ]\
12264 for y=1,nNewHeight do\
12265 if y > nHeight then\
12266 tNewLines[y] = {\
12267 text = sEmptyText,\
12268 textColor = sEmptyTextColor,\
12269 backgroundColor = sEmptyBackgroundColor\
12270 }\
12271 else\
12272 local tOldLine = tLines[y]\
12273 if nNewWidth == nWidth then\
12274 tNewLines[y] = tOldLine\
12275 elseif nNewWidth < nWidth then\
12276 tNewLines[y] = {\
12277 text = string_sub( tOldLine.text, 1, nNewWidth ),\
12278 textColor = string_sub( tOldLine.textColor, 1, nNewWidth ),\
12279 backgroundColor = string_sub( tOldLine.backgroundColor, 1, nNewWidth ),\
12280 }\
12281 else\
12282 tNewLines[y] = {\
12283 text = tOldLine.text .. string_sub( sEmptyText, nWidth + 1, nNewWidth ),\
12284 textColor = tOldLine.textColor .. string_sub( sEmptyTextColor, nWidth + 1, nNewWidth ),\
12285 backgroundColor = tOldLine.backgroundColor .. string_sub( sEmptyBackgroundColor, nWidth + 1, nNewWidth ),\
12286 }\
12287 end\
12288 end\
12289 end\
12290 nWidth = nNewWidth\
12291 nHeight = nNewHeight\
12292 tLines = tNewLines\
12293 end\
12294 if bVisible then\
12295 window.redraw()\
12296 end\
12297 end\
12298\
12299 if bVisible then\
12300 window.redraw()\
12301 end\
12302 return window\
12303end",
12304 },
12305}