Advertisement
HydrantHunter

gtRemote

Apr 8th, 2014
3,633
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 85.15 KB | None | 0 0
  1. --[[     gtRemote      ]]--
  2. --[[      by Dog       ]]--
  3. --[[ aka HydrantHunter ]]--
  4. --[[  with assistance  ]]--
  5. --[[   from CometWolf  ]]--
  6. --[[ pastebin XQQsRyLX ]]--
  7. local gtRver = "2.0.05"
  8. --[[
  9. Tested with/requires:
  10.   - Minecraft 1.6.4+
  11.   - ComputerCraft 1.63+
  12.     - 1 Advanced Wireless Pocket Computer
  13.     - gtHost running on one or more Wireless Turtles (standard or advanced)
  14.  
  15. Special thanks to: Anavrins       (pbkdf2/sha256 hashing)
  16.                    SquidDev       (AES encryption/decryption)
  17.                    Alex Kloss     (base64 encoder/decoder)
  18. ]]--
  19. --# AUTOMATIC/STATIC CONFIGURATION
  20. --# Default Settings
  21. local termX, termY = term.getSize()
  22. local netSide, runState, tDirection, thisCC = "none", "init", "Forward", tostring(os.getComputerID())
  23. local kernelState, timerDelay, inputting = true, false, false
  24. local netReceive, drawCLI, drawHeader, turtleInventory, turtleControlScreen, userInput, pollTimer, tempState
  25. --# Turtle List
  26. local allTurtles, filteredTurtles = { }, { }
  27. local numPages, pageNum = 1, 1
  28. local fuelFilter, showFuel = false, false
  29. local gtHost, thisTurtle
  30. local colorBurst = {
  31.   G = { order = 1, text = "Green", color = colors.green };
  32.   S = { order = 2, text = "Sky", color = colors.lightBlue };
  33.   B = { order = 3, text = "Blue", color = colors.blue };
  34.   P = { order = 4, text = "Purple", color = colors.purple };
  35.   R = { order = 5, text = "Red", color = colors.red };
  36.   O = { order = 6, text = "Orange", color = colors.orange };
  37.   N = { order = 7, text = "Brown", color = colors.brown };
  38.   I = { order = 8, text = "Silver", color = colors.lightGray };
  39. }
  40. --# Color Definitions
  41. local white = colors.white
  42. local black = colors.black
  43. local silver = colors.lightGray
  44. local gray = colors.gray
  45. local brown = colors.brown
  46. local yellow = colors.yellow
  47. local orange = colors.orange
  48. local red = colors.red
  49. local magenta = colors.magenta
  50. local purple = colors.purple
  51. local blue = colors.blue
  52. local sky = colors.lightBlue
  53. local cyan = colors.cyan
  54. local lime = colors.lime
  55. local green = colors.green
  56. --# END AUTOMATIC/STATIC CONFIGURATION
  57.  
  58. -- Lua 5.1+ base64 v3.0 (c) 2009 by Alex Kloss <alexthkloss@web.de>
  59. -- licensed under the terms of the LGPL2
  60. -- http://lua-users.org/wiki/BaseSixtyFour
  61. -- character table string
  62. local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
  63. -- encoding
  64. function encode(data)
  65.   return ((data:gsub('.', function(x)
  66.     local r,b='',x:byte()
  67.     for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
  68.     return r;
  69.   end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
  70.     if (#x < 6) then return '' end
  71.     local c=0
  72.     for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
  73.     return b:sub(c+1,c+1)
  74.   end)..({ '', '==', '=' })[#data%3+1])
  75. end
  76. -- decoding
  77. function decode(data)
  78.   data = string.gsub(data, '[^'..b..'=]', '')
  79.   return (data:gsub('.', function(x)
  80.     if (x == '=') then return '' end
  81.     local r,f='',(b:find(x)-1)
  82.     for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
  83.     return r;
  84.   end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
  85.     if (#x ~= 8) then return '' end
  86.     local c=0
  87.     for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
  88.     return string.char(c)
  89.   end))
  90. end
  91.  
  92. -- AES Lua implementation by SquidDev
  93. -- https://gist.github.com/SquidDev/86925e07cbabd70773e53d781bd8b2fe
  94. local encrypt, decrypt
  95. do
  96.   local function _W(f) local e=setmetatable({}, {__index = _ENV or getfenv()}) if setfenv then setfenv(f, e) end return f(e) or e end
  97.   local bit=_W(function(_ENV, ...)
  98.   --[[
  99.     This bit API is designed to cope with unsigned integers instead of normal integers
  100.     To do this we add checks for overflows: (x > 2^31 ? x - 2 ^ 32 : x)
  101.     These are written in long form because no constant folding.
  102.   ]]
  103.   local floor = math.floor
  104.   local lshift, rshift
  105.  
  106.   rshift = function(a,disp)
  107.     return floor(a % 4294967296 / 2^disp)
  108.   end
  109.  
  110.   lshift = function(a,disp)
  111.     return (a * 2^disp) % 4294967296
  112.   end
  113.  
  114.   return {
  115.     -- bit operations
  116.     bnot = bit32 and bit32.bnot or bit.bnot,
  117.     band = bit32 and bit32.band or bit.band,
  118.     bor  = bit32 and bit32.bor or bit.bor,
  119.     bxor = bit32 and bit32.bxor or bit.bxor,
  120.     rshift = rshift,
  121.     lshift = lshift,
  122.   }
  123.   end)
  124.  
  125.   local gf=_W(function(_ENV, ...)
  126.   -- finite field with base 2 and modulo irreducible polynom x^8+x^4+x^3+x+1 = 0x11d
  127.   local bxor = bit32 and bit32.bxor or bit.bxor
  128.   local lshift = bit.lshift
  129.   -- private data of gf
  130.   local n = 0x100
  131.   local ord = 0xff
  132.   local irrPolynom = 0x11b
  133.   local exp = {}
  134.   local log = {}
  135.   --
  136.   -- add two polynoms (its simply xor)
  137.   --
  138.   local function add(operand1, operand2)
  139.     return bxor(operand1,operand2)
  140.   end
  141.   --
  142.   -- subtract two polynoms (same as addition)
  143.   --
  144.   local function sub(operand1, operand2)
  145.     return bxor(operand1,operand2)
  146.   end
  147.   --
  148.   -- inverts element
  149.   -- a^(-1) = g^(order - log(a))
  150.   --
  151.   local function invert(operand)
  152.     -- special case for 1
  153.     if (operand == 1) then
  154.       return 1
  155.     end
  156.     -- normal invert
  157.     local exponent = ord - log[operand]
  158.     return exp[exponent]
  159.   end
  160.   --
  161.   -- multiply two elements using a logarithm table
  162.   -- a*b = g^(log(a)+log(b))
  163.   --
  164.   local function mul(operand1, operand2)
  165.     if (operand1 == 0 or operand2 == 0) then
  166.       return 0
  167.     end
  168.     local exponent = log[operand1] + log[operand2]
  169.     if (exponent >= ord) then
  170.       exponent = exponent - ord
  171.     end
  172.     return exp[exponent]
  173.   end
  174.   --
  175.   -- divide two elements
  176.   -- a/b = g^(log(a)-log(b))
  177.   --
  178.   local function div(operand1, operand2)
  179.     if (operand1 == 0)  then
  180.       return 0
  181.     end
  182.     -- TODO: exception if operand2 == 0
  183.     local exponent = log[operand1] - log[operand2]
  184.     if (exponent < 0) then
  185.       exponent = exponent + ord
  186.     end
  187.     return exp[exponent]
  188.   end
  189.   --
  190.   -- print logarithmic table
  191.   --
  192.   local function printLog()
  193.     for i = 1, n do
  194.       print("log(", i-1, ")=", log[i-1])
  195.     end
  196.   end
  197.   --
  198.   -- print exponentiation table
  199.   --
  200.   local function printExp()
  201.     for i = 1, n do
  202.       print("exp(", i-1, ")=", exp[i-1])
  203.     end
  204.   end
  205.   --
  206.   -- calculate logarithmic and exponentiation table
  207.   --
  208.   local function initMulTable()
  209.     local a = 1
  210.     for i = 0,ord-1 do
  211.       exp[i] = a
  212.       log[a] = i
  213.       -- multiply with generator x+1 -> left shift + 1
  214.       a = bxor(lshift(a, 1), a)
  215.       -- if a gets larger than order, reduce modulo irreducible polynom
  216.       if a > ord then
  217.         a = sub(a, irrPolynom)
  218.       end
  219.     end
  220.   end
  221.  
  222.   initMulTable()
  223.  
  224.   return {
  225.     add = add,
  226.     sub = sub,
  227.     invert = invert,
  228.     mul = mul,
  229.     div = div,
  230.     printLog = printLog,
  231.     printExp = printExp,
  232.   }
  233.   end)
  234.  
  235.   util=_W(function(_ENV, ...)
  236.   -- Cache some bit operators
  237.   local bxor = bit.bxor
  238.   local rshift = bit.rshift
  239.   local band = bit.band
  240.   local lshift = bit.lshift
  241.   local sleepCheckIn
  242.   --
  243.   -- calculate the parity of one byte
  244.   --
  245.   local function byteParity(byte)
  246.     byte = bxor(byte, rshift(byte, 4))
  247.     byte = bxor(byte, rshift(byte, 2))
  248.     byte = bxor(byte, rshift(byte, 1))
  249.     return band(byte, 1)
  250.   end
  251.   --
  252.   -- get byte at position index
  253.   --
  254.   local function getByte(number, index)
  255.     return index == 0 and band(number,0xff) or band(rshift(number, index*8),0xff)
  256.   end
  257.   --
  258.   -- put number into int at position index
  259.   --
  260.   local function putByte(number, index)
  261.     return index == 0 and band(number,0xff) or lshift(band(number,0xff),index*8)
  262.   end
  263.   --
  264.   -- convert byte array to int array
  265.   --
  266.   local function bytesToInts(bytes, start, n)
  267.     local ints = {}
  268.     for i = 0, n - 1 do
  269.       ints[i + 1] =
  270.           putByte(bytes[start + (i*4)], 3) +
  271.           putByte(bytes[start + (i*4) + 1], 2) +
  272.           putByte(bytes[start + (i*4) + 2], 1) +
  273.           putByte(bytes[start + (i*4) + 3], 0)
  274.       if n % 10000 == 0 then sleepCheckIn() end
  275.     end
  276.     return ints
  277.   end
  278.   --
  279.   -- convert int array to byte array
  280.   --
  281.   local function intsToBytes(ints, output, outputOffset, n)
  282.     n = n or #ints
  283.     for i = 0, n - 1 do
  284.       for j = 0,3 do
  285.         output[outputOffset + i*4 + (3 - j)] = getByte(ints[i + 1], j)
  286.       end
  287.       if n % 10000 == 0 then sleepCheckIn() end
  288.     end
  289.     return output
  290.   end
  291.   --
  292.   -- convert bytes to hexString
  293.   --
  294.   local function bytesToHex(bytes)
  295.     local hexBytes = ""
  296.     for i,byte in ipairs(bytes) do
  297.       hexBytes = hexBytes .. string.format("%02x ", byte)
  298.     end
  299.     return hexBytes
  300.   end
  301.  
  302.   local function hexToBytes(bytes)
  303.     local out = {}
  304.     for i = 1, #bytes, 2 do
  305.       out[#out + 1] = tonumber(bytes:sub(i, i + 1), 16)
  306.     end
  307.     return out
  308.   end
  309.   --
  310.   -- convert data to hex string
  311.   --
  312.   local function toHexString(data)
  313.     local type = type(data)
  314.     if (type == "number") then
  315.       return string.format("%08x",data)
  316.     elseif (type == "table") then
  317.       return bytesToHex(data)
  318.     elseif (type == "string") then
  319.       local bytes = {string.byte(data, 1, #data)}
  320.       return bytesToHex(bytes)
  321.     else
  322.       return data
  323.     end
  324.   end
  325.  
  326.   local function padByteString(data)
  327.     local dataLength = #data
  328.     local random1 = math.random(0,255)
  329.     local random2 = math.random(0,255)
  330.     local prefix = string.char(random1,
  331.       random2,
  332.       random1,
  333.       random2,
  334.       getByte(dataLength, 3),
  335.       getByte(dataLength, 2),
  336.       getByte(dataLength, 1),
  337.       getByte(dataLength, 0)
  338.     )
  339.     data = prefix .. data
  340.     local padding, paddingLength = "", math.ceil(#data/16)*16 - #data
  341.     for i=1,paddingLength do
  342.       padding = padding .. string.char(math.random(0,255))
  343.     end
  344.     return data .. padding
  345.   end
  346.  
  347.   local function properlyDecrypted(data)
  348.     local random = {string.byte(data,1,4)}
  349.  
  350.     if (random[1] == random[3] and random[2] == random[4]) then
  351.       return true
  352.     end
  353.  
  354.     return false
  355.   end
  356.  
  357.   local function unpadByteString(data)
  358.     if (not properlyDecrypted(data)) then
  359.       return nil
  360.     end
  361.     local dataLength = putByte(string.byte(data,5), 3)
  362.              + putByte(string.byte(data,6), 2)
  363.              + putByte(string.byte(data,7), 1)
  364.              + putByte(string.byte(data,8), 0)
  365.     return string.sub(data,9,8+dataLength)
  366.   end
  367.  
  368.   local function xorIV(data, iv)
  369.     for i = 1,16 do
  370.       data[i] = bxor(data[i], iv[i])
  371.     end
  372.   end
  373.  
  374.   local function increment(data)
  375.     local i = 16
  376.     while true do
  377.       local value = data[i] + 1
  378.       if value >= 256 then
  379.         data[i] = value - 256
  380.         i = (i - 2) % 16 + 1
  381.       else
  382.         data[i] = value
  383.         break
  384.       end
  385.     end
  386.   end
  387.  
  388.   -- Called every encryption cycle
  389.   local push, pull, time = os.queueEvent, coroutine.yield, os.time
  390.   local oldTime = time()
  391.   local function sleepCheckIn()
  392.     local newTime = time()
  393.     if newTime - oldTime >= 0.03 then -- (0.020 * 1.5)
  394.       oldTime = newTime
  395.       push("sleep")
  396.       pull("sleep")
  397.     end
  398.   end
  399.  
  400.   local function getRandomData(bytes)
  401.     local char, random, sleep, insert = string.char, math.random, sleepCheckIn, table.insert
  402.     local result = {}
  403.     for i=1,bytes do
  404.       insert(result, random(0,255))
  405.       if i % 10240 == 0 then sleep() end
  406.     end
  407.     return result
  408.   end
  409.  
  410.   local function getRandomString(bytes)
  411.     local char, random, sleep, insert = string.char, math.random, sleepCheckIn, table.insert
  412.     local result = {}
  413.     for i=1,bytes do
  414.       insert(result, char(random(0,255)))
  415.       if i % 10240 == 0 then sleep() end
  416.     end
  417.     return table.concat(result)
  418.   end
  419.  
  420.   return {
  421.     byteParity = byteParity,
  422.     getByte = getByte,
  423.     putByte = putByte,
  424.     bytesToInts = bytesToInts,
  425.     intsToBytes = intsToBytes,
  426.     bytesToHex = bytesToHex,
  427.     hexToBytes = hexToBytes,
  428.     toHexString = toHexString,
  429.     padByteString = padByteString,
  430.     properlyDecrypted = properlyDecrypted,
  431.     unpadByteString = unpadByteString,
  432.     xorIV = xorIV,
  433.     increment = increment,
  434.     sleepCheckIn = sleepCheckIn,
  435.     getRandomData = getRandomData,
  436.     getRandomString = getRandomString,
  437.   }
  438.   end)
  439.  
  440.   aes=_W(function(_ENV, ...)
  441.   -- Implementation of AES with nearly pure lua
  442.   -- AES with lua is slow, really slow :-)
  443.   local putByte = util.putByte
  444.   local getByte = util.getByte
  445.   -- some constants
  446.   local ROUNDS = 'rounds'
  447.   local KEY_TYPE = "type"
  448.   local ENCRYPTION_KEY=1
  449.   local DECRYPTION_KEY=2
  450.   -- aes SBOX
  451.   local SBox = {}
  452.   local iSBox = {}
  453.   -- aes tables
  454.   local table0 = {}
  455.   local table1 = {}
  456.   local table2 = {}
  457.   local table3 = {}
  458.   local tableInv0 = {}
  459.   local tableInv1 = {}
  460.   local tableInv2 = {}
  461.   local tableInv3 = {}
  462.   -- round constants
  463.   local rCon = {
  464.     0x01000000,
  465.     0x02000000,
  466.     0x04000000,
  467.     0x08000000,
  468.     0x10000000,
  469.     0x20000000,
  470.     0x40000000,
  471.     0x80000000,
  472.     0x1b000000,
  473.     0x36000000,
  474.     0x6c000000,
  475.     0xd8000000,
  476.     0xab000000,
  477.     0x4d000000,
  478.     0x9a000000,
  479.     0x2f000000,
  480.   }
  481.   --
  482.   -- affine transformation for calculating the S-Box of AES
  483.   --
  484.   local function affinMap(byte)
  485.     mask = 0xf8
  486.     result = 0
  487.     for i = 1,8 do
  488.       result = bit.lshift(result,1)
  489.       parity = util.byteParity(bit.band(byte,mask))
  490.       result = result + parity
  491.       -- simulate roll
  492.       lastbit = bit.band(mask, 1)
  493.       mask = bit.band(bit.rshift(mask, 1),0xff)
  494.       mask = lastbit ~= 0 and bit.bor(mask, 0x80) or bit.band(mask, 0x7f)
  495.     end
  496.     return bit.bxor(result, 0x63)
  497.   end
  498.   --
  499.   -- calculate S-Box and inverse S-Box of AES
  500.   -- apply affine transformation to inverse in finite field 2^8
  501.   --
  502.   local function calcSBox()
  503.     for i = 0, 255 do
  504.       inverse = i ~= 0 and gf.invert(i) or i
  505.       mapped = affinMap(inverse)
  506.       SBox[i] = mapped
  507.       iSBox[mapped] = i
  508.     end
  509.   end
  510.   --
  511.   -- Calculate round tables
  512.   -- round tables are used to calculate shiftRow, MixColumn and SubBytes
  513.   -- with 4 table lookups and 4 xor operations.
  514.   --
  515.   local function calcRoundTables()
  516.     for x = 0,255 do
  517.       byte = SBox[x]
  518.       table0[x] = putByte(gf.mul(0x03, byte), 0)
  519.                 + putByte(             byte , 1)
  520.                 + putByte(             byte , 2)
  521.                 + putByte(gf.mul(0x02, byte), 3)
  522.       table1[x] = putByte(             byte , 0)
  523.                 + putByte(             byte , 1)
  524.                 + putByte(gf.mul(0x02, byte), 2)
  525.                 + putByte(gf.mul(0x03, byte), 3)
  526.       table2[x] = putByte(             byte , 0)
  527.                 + putByte(gf.mul(0x02, byte), 1)
  528.                 + putByte(gf.mul(0x03, byte), 2)
  529.                 + putByte(             byte , 3)
  530.       table3[x] = putByte(gf.mul(0x02, byte), 0)
  531.                 + putByte(gf.mul(0x03, byte), 1)
  532.                 + putByte(             byte , 2)
  533.                 + putByte(             byte , 3)
  534.     end
  535.   end
  536.   --
  537.   -- Calculate inverse round tables
  538.   -- does the inverse of the normal roundtables for the equivalent
  539.   -- decryption algorithm.
  540.   --
  541.   local function calcInvRoundTables()
  542.     for x = 0,255 do
  543.       byte = iSBox[x]
  544.       tableInv0[x] = putByte(gf.mul(0x0b, byte), 0)
  545.                  + putByte(gf.mul(0x0d, byte), 1)
  546.                  + putByte(gf.mul(0x09, byte), 2)
  547.                  + putByte(gf.mul(0x0e, byte), 3)
  548.       tableInv1[x] = putByte(gf.mul(0x0d, byte), 0)
  549.                  + putByte(gf.mul(0x09, byte), 1)
  550.                  + putByte(gf.mul(0x0e, byte), 2)
  551.                  + putByte(gf.mul(0x0b, byte), 3)
  552.       tableInv2[x] = putByte(gf.mul(0x09, byte), 0)
  553.                  + putByte(gf.mul(0x0e, byte), 1)
  554.                  + putByte(gf.mul(0x0b, byte), 2)
  555.                  + putByte(gf.mul(0x0d, byte), 3)
  556.       tableInv3[x] = putByte(gf.mul(0x0e, byte), 0)
  557.                  + putByte(gf.mul(0x0b, byte), 1)
  558.                  + putByte(gf.mul(0x0d, byte), 2)
  559.                  + putByte(gf.mul(0x09, byte), 3)
  560.     end
  561.   end
  562.   --
  563.   -- rotate word: 0xaabbccdd gets 0xbbccddaa
  564.   -- used for key schedule
  565.   --
  566.   local function rotWord(word)
  567.     local tmp = bit.band(word,0xff000000)
  568.     return (bit.lshift(word,8) + bit.rshift(tmp,24))
  569.   end
  570.   --
  571.   -- replace all bytes in a word with the SBox.
  572.   -- used for key schedule
  573.   --
  574.   local function subWord(word)
  575.     return putByte(SBox[getByte(word,0)],0)
  576.       + putByte(SBox[getByte(word,1)],1)
  577.       + putByte(SBox[getByte(word,2)],2)
  578.       + putByte(SBox[getByte(word,3)],3)
  579.   end
  580.   --
  581.   -- generate key schedule for aes encryption
  582.   --
  583.   -- returns table with all round keys and
  584.   -- the necessary number of rounds saved in [ROUNDS]
  585.   --
  586.   local function expandEncryptionKey(key)
  587.     local keySchedule = {}
  588.     local keyWords = math.floor(#key / 4)
  589.     if ((keyWords ~= 4 and keyWords ~= 6 and keyWords ~= 8) or (keyWords * 4 ~= #key)) then
  590.       error("Invalid key size: " .. tostring(keyWords))
  591.       return nil
  592.     end
  593.     keySchedule[ROUNDS] = keyWords + 6
  594.     keySchedule[KEY_TYPE] = ENCRYPTION_KEY
  595.     for i = 0,keyWords - 1 do
  596.       keySchedule[i] = putByte(key[i*4+1], 3)
  597.                + putByte(key[i*4+2], 2)
  598.                + putByte(key[i*4+3], 1)
  599.                + putByte(key[i*4+4], 0)
  600.     end
  601.     for i = keyWords, (keySchedule[ROUNDS] + 1)*4 - 1 do
  602.       local tmp = keySchedule[i-1]
  603.       if ( i % keyWords == 0) then
  604.         tmp = rotWord(tmp)
  605.         tmp = subWord(tmp)
  606.         local index = math.floor(i/keyWords)
  607.         tmp = bit.bxor(tmp,rCon[index])
  608.       elseif (keyWords > 6 and i % keyWords == 4) then
  609.         tmp = subWord(tmp)
  610.       end
  611.       keySchedule[i] = bit.bxor(keySchedule[(i-keyWords)],tmp)
  612.     end
  613.     return keySchedule
  614.   end
  615.   --
  616.   -- Inverse mix column
  617.   -- used for key schedule of decryption key
  618.   --
  619.   local function invMixColumnOld(word)
  620.     local b0 = getByte(word,3)
  621.     local b1 = getByte(word,2)
  622.     local b2 = getByte(word,1)
  623.     local b3 = getByte(word,0)
  624.     return putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b1),
  625.                          gf.mul(0x0d, b2)),
  626.                          gf.mul(0x09, b3)),
  627.                          gf.mul(0x0e, b0)),3)
  628.        + putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b2),
  629.                          gf.mul(0x0d, b3)),
  630.                          gf.mul(0x09, b0)),
  631.                          gf.mul(0x0e, b1)),2)
  632.        + putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b3),
  633.                          gf.mul(0x0d, b0)),
  634.                          gf.mul(0x09, b1)),
  635.                          gf.mul(0x0e, b2)),1)
  636.        + putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b0),
  637.                          gf.mul(0x0d, b1)),
  638.                          gf.mul(0x09, b2)),
  639.                          gf.mul(0x0e, b3)),0)
  640.   end
  641.   --
  642.   -- Optimized inverse mix column
  643.   -- look at http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.311.pdf
  644.   -- TODO: make it work
  645.   --
  646.   local function invMixColumn(word)
  647.     local b0 = getByte(word,3)
  648.     local b1 = getByte(word,2)
  649.     local b2 = getByte(word,1)
  650.     local b3 = getByte(word,0)
  651.     local t = bit.bxor(b3,b2)
  652.     local u = bit.bxor(b1,b0)
  653.     local v = bit.bxor(t,u)
  654.     v = bit.bxor(v,gf.mul(0x08,v))
  655.     w = bit.bxor(v,gf.mul(0x04, bit.bxor(b2,b0)))
  656.     v = bit.bxor(v,gf.mul(0x04, bit.bxor(b3,b1)))
  657.     return putByte( bit.bxor(bit.bxor(b3,v), gf.mul(0x02, bit.bxor(b0,b3))), 0)
  658.        + putByte( bit.bxor(bit.bxor(b2,w), gf.mul(0x02, t              )), 1)
  659.        + putByte( bit.bxor(bit.bxor(b1,v), gf.mul(0x02, bit.bxor(b0,b3))), 2)
  660.        + putByte( bit.bxor(bit.bxor(b0,w), gf.mul(0x02, u              )), 3)
  661.   end
  662.   --
  663.   -- generate key schedule for aes decryption
  664.   --
  665.   -- uses key schedule for aes encryption and transforms each
  666.   -- key by inverse mix column.
  667.   --
  668.   local function expandDecryptionKey(key)
  669.     local keySchedule = expandEncryptionKey(key)
  670.     if (keySchedule == nil) then
  671.       return nil
  672.     end
  673.     keySchedule[KEY_TYPE] = DECRYPTION_KEY
  674.     for i = 4, (keySchedule[ROUNDS] + 1)*4 - 5 do
  675.       keySchedule[i] = invMixColumnOld(keySchedule[i])
  676.     end
  677.     return keySchedule
  678.   end
  679.   --
  680.   -- xor round key to state
  681.   --
  682.   local function addRoundKey(state, key, round)
  683.     for i = 0, 3 do
  684.       state[i + 1] = bit.bxor(state[i + 1], key[round*4+i])
  685.     end
  686.   end
  687.   --
  688.   -- do encryption round (ShiftRow, SubBytes, MixColumn together)
  689.   --
  690.   local function doRound(origState, dstState)
  691.     dstState[1] =  bit.bxor(bit.bxor(bit.bxor(
  692.           table0[getByte(origState[1],3)],
  693.           table1[getByte(origState[2],2)]),
  694.           table2[getByte(origState[3],1)]),
  695.           table3[getByte(origState[4],0)])
  696.     dstState[2] =  bit.bxor(bit.bxor(bit.bxor(
  697.           table0[getByte(origState[2],3)],
  698.           table1[getByte(origState[3],2)]),
  699.           table2[getByte(origState[4],1)]),
  700.           table3[getByte(origState[1],0)])
  701.     dstState[3] =  bit.bxor(bit.bxor(bit.bxor(
  702.           table0[getByte(origState[3],3)],
  703.           table1[getByte(origState[4],2)]),
  704.           table2[getByte(origState[1],1)]),
  705.           table3[getByte(origState[2],0)])
  706.     dstState[4] =  bit.bxor(bit.bxor(bit.bxor(
  707.           table0[getByte(origState[4],3)],
  708.           table1[getByte(origState[1],2)]),
  709.           table2[getByte(origState[2],1)]),
  710.           table3[getByte(origState[3],0)])
  711.   end
  712.   --
  713.   -- do last encryption round (ShiftRow and SubBytes)
  714.   --
  715.   local function doLastRound(origState, dstState)
  716.     dstState[1] = putByte(SBox[getByte(origState[1],3)], 3)
  717.           + putByte(SBox[getByte(origState[2],2)], 2)
  718.           + putByte(SBox[getByte(origState[3],1)], 1)
  719.           + putByte(SBox[getByte(origState[4],0)], 0)
  720.     dstState[2] = putByte(SBox[getByte(origState[2],3)], 3)
  721.           + putByte(SBox[getByte(origState[3],2)], 2)
  722.           + putByte(SBox[getByte(origState[4],1)], 1)
  723.           + putByte(SBox[getByte(origState[1],0)], 0)
  724.     dstState[3] = putByte(SBox[getByte(origState[3],3)], 3)
  725.           + putByte(SBox[getByte(origState[4],2)], 2)
  726.           + putByte(SBox[getByte(origState[1],1)], 1)
  727.           + putByte(SBox[getByte(origState[2],0)], 0)
  728.     dstState[4] = putByte(SBox[getByte(origState[4],3)], 3)
  729.           + putByte(SBox[getByte(origState[1],2)], 2)
  730.           + putByte(SBox[getByte(origState[2],1)], 1)
  731.           + putByte(SBox[getByte(origState[3],0)], 0)
  732.   end
  733.   --
  734.   -- do decryption round
  735.   --
  736.   local function doInvRound(origState, dstState)
  737.     dstState[1] =  bit.bxor(bit.bxor(bit.bxor(
  738.           tableInv0[getByte(origState[1],3)],
  739.           tableInv1[getByte(origState[4],2)]),
  740.           tableInv2[getByte(origState[3],1)]),
  741.           tableInv3[getByte(origState[2],0)])
  742.     dstState[2] =  bit.bxor(bit.bxor(bit.bxor(
  743.           tableInv0[getByte(origState[2],3)],
  744.           tableInv1[getByte(origState[1],2)]),
  745.           tableInv2[getByte(origState[4],1)]),
  746.           tableInv3[getByte(origState[3],0)])
  747.     dstState[3] =  bit.bxor(bit.bxor(bit.bxor(
  748.           tableInv0[getByte(origState[3],3)],
  749.           tableInv1[getByte(origState[2],2)]),
  750.           tableInv2[getByte(origState[1],1)]),
  751.           tableInv3[getByte(origState[4],0)])
  752.     dstState[4] =  bit.bxor(bit.bxor(bit.bxor(
  753.           tableInv0[getByte(origState[4],3)],
  754.           tableInv1[getByte(origState[3],2)]),
  755.           tableInv2[getByte(origState[2],1)]),
  756.           tableInv3[getByte(origState[1],0)])
  757.   end
  758.   --
  759.   -- do last decryption round
  760.   --
  761.   local function doInvLastRound(origState, dstState)
  762.     dstState[1] = putByte(iSBox[getByte(origState[1],3)], 3)
  763.           + putByte(iSBox[getByte(origState[4],2)], 2)
  764.           + putByte(iSBox[getByte(origState[3],1)], 1)
  765.           + putByte(iSBox[getByte(origState[2],0)], 0)
  766.     dstState[2] = putByte(iSBox[getByte(origState[2],3)], 3)
  767.           + putByte(iSBox[getByte(origState[1],2)], 2)
  768.           + putByte(iSBox[getByte(origState[4],1)], 1)
  769.           + putByte(iSBox[getByte(origState[3],0)], 0)
  770.     dstState[3] = putByte(iSBox[getByte(origState[3],3)], 3)
  771.           + putByte(iSBox[getByte(origState[2],2)], 2)
  772.           + putByte(iSBox[getByte(origState[1],1)], 1)
  773.           + putByte(iSBox[getByte(origState[4],0)], 0)
  774.     dstState[4] = putByte(iSBox[getByte(origState[4],3)], 3)
  775.           + putByte(iSBox[getByte(origState[3],2)], 2)
  776.           + putByte(iSBox[getByte(origState[2],1)], 1)
  777.           + putByte(iSBox[getByte(origState[1],0)], 0)
  778.   end
  779.   --
  780.   -- encrypts 16 Bytes
  781.   -- key           encryption key schedule
  782.   -- input         array with input data
  783.   -- inputOffset   start index for input
  784.   -- output        array for encrypted data
  785.   -- outputOffset  start index for output
  786.   --
  787.   local function encrypt(key, input, inputOffset, output, outputOffset)
  788.     --default parameters
  789.     inputOffset = inputOffset or 1
  790.     output = output or {}
  791.     outputOffset = outputOffset or 1
  792.     local state = {}
  793.     local tmpState = {}
  794.     if (key[KEY_TYPE] ~= ENCRYPTION_KEY) then
  795.       error("No encryption key: " .. tostring(key[KEY_TYPE]) .. ", expected " .. ENCRYPTION_KEY)
  796.       return
  797.     end
  798.     state = util.bytesToInts(input, inputOffset, 4)
  799.     addRoundKey(state, key, 0)
  800.     local round = 1
  801.     while (round < key[ROUNDS] - 1) do
  802.       -- do a double round to save temporary assignments
  803.       doRound(state, tmpState)
  804.       addRoundKey(tmpState, key, round)
  805.       round = round + 1
  806.       doRound(tmpState, state)
  807.       addRoundKey(state, key, round)
  808.       round = round + 1
  809.     end
  810.     doRound(state, tmpState)
  811.     addRoundKey(tmpState, key, round)
  812.     round = round +1
  813.     doLastRound(tmpState, state)
  814.     addRoundKey(state, key, round)
  815.     util.sleepCheckIn()
  816.     return util.intsToBytes(state, output, outputOffset)
  817.   end
  818.   --
  819.   -- decrypt 16 bytes
  820.   -- key           decryption key schedule
  821.   -- input         array with input data
  822.   -- inputOffset   start index for input
  823.   -- output        array for decrypted data
  824.   -- outputOffset  start index for output
  825.   ---
  826.   local function decrypt(key, input, inputOffset, output, outputOffset)
  827.     -- default arguments
  828.     inputOffset = inputOffset or 1
  829.     output = output or {}
  830.     outputOffset = outputOffset or 1
  831.     local state = {}
  832.     local tmpState = {}
  833.     if (key[KEY_TYPE] ~= DECRYPTION_KEY) then
  834.       error("No decryption key: " .. tostring(key[KEY_TYPE]))
  835.       return
  836.     end
  837.     state = util.bytesToInts(input, inputOffset, 4)
  838.     addRoundKey(state, key, key[ROUNDS])
  839.     local round = key[ROUNDS] - 1
  840.     while (round > 2) do
  841.       -- do a double round to save temporary assignments
  842.       doInvRound(state, tmpState)
  843.       addRoundKey(tmpState, key, round)
  844.       round = round - 1
  845.       doInvRound(tmpState, state)
  846.       addRoundKey(state, key, round)
  847.       round = round - 1
  848.     end
  849.     doInvRound(state, tmpState)
  850.     addRoundKey(tmpState, key, round)
  851.     round = round - 1
  852.     doInvLastRound(tmpState, state)
  853.     addRoundKey(state, key, round)
  854.     util.sleepCheckIn()
  855.     return util.intsToBytes(state, output, outputOffset)
  856.   end
  857.  
  858.   -- calculate all tables when loading this file
  859.   calcSBox()
  860.   calcRoundTables()
  861.   calcInvRoundTables()
  862.  
  863.   return {
  864.     ROUNDS = ROUNDS,
  865.     KEY_TYPE = KEY_TYPE,
  866.     ENCRYPTION_KEY = ENCRYPTION_KEY,
  867.     DECRYPTION_KEY = DECRYPTION_KEY,
  868.     expandEncryptionKey = expandEncryptionKey,
  869.     expandDecryptionKey = expandDecryptionKey,
  870.     encrypt = encrypt,
  871.     decrypt = decrypt,
  872.   }
  873.   end)
  874.  
  875.   local buffer=_W(function(_ENV, ...)
  876.   local function new ()
  877.     return {}
  878.   end
  879.  
  880.   local function addString (stack, s)
  881.     table.insert(stack, s)
  882.   end
  883.  
  884.   local function toString (stack)
  885.     return table.concat(stack)
  886.   end
  887.  
  888.   return {
  889.     new = new,
  890.     addString = addString,
  891.     toString = toString,
  892.   }
  893.   end)
  894.  
  895.   ciphermode=_W(function(_ENV, ...)
  896.   local public = {}
  897.   --
  898.   -- Encrypt strings
  899.   -- key - byte array with key
  900.   -- string - string to encrypt
  901.   -- modefunction - function for cipher mode to use
  902.   --
  903.   local random, unpack = math.random, unpack or table.unpack
  904.   function public.encryptString(key, data, modeFunction, iv)
  905.     if iv then
  906.       local ivCopy = {}
  907.       for i = 1, 16 do ivCopy[i] = iv[i] end
  908.       iv = ivCopy
  909.     else
  910.       iv = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
  911.     end
  912.     local keySched = aes.expandEncryptionKey(key)
  913.     local encryptedData = buffer.new()
  914.     for i = 1, #data/16 do
  915.       local offset = (i-1)*16 + 1
  916.       local byteData = {string.byte(data,offset,offset +15)}
  917.       iv = modeFunction(keySched, byteData, iv)
  918.       buffer.addString(encryptedData, string.char(unpack(byteData)))
  919.     end
  920.     return buffer.toString(encryptedData)
  921.   end
  922.   --
  923.   -- the following 4 functions can be used as
  924.   -- modefunction for encryptString
  925.   --
  926.   -- Electronic code book mode encrypt function
  927.   function public.encryptECB(keySched, byteData, iv)
  928.     aes.encrypt(keySched, byteData, 1, byteData, 1)
  929.   end
  930.  
  931.   -- Cipher block chaining mode encrypt function
  932.   function public.encryptCBC(keySched, byteData, iv)
  933.     util.xorIV(byteData, iv)
  934.     aes.encrypt(keySched, byteData, 1, byteData, 1)
  935.     return byteData
  936.   end
  937.  
  938.   -- Output feedback mode encrypt function
  939.   function public.encryptOFB(keySched, byteData, iv)
  940.     aes.encrypt(keySched, iv, 1, iv, 1)
  941.     util.xorIV(byteData, iv)
  942.     return iv
  943.   end
  944.  
  945.   -- Cipher feedback mode encrypt function
  946.   function public.encryptCFB(keySched, byteData, iv)
  947.     aes.encrypt(keySched, iv, 1, iv, 1)
  948.     util.xorIV(byteData, iv)
  949.     return byteData
  950.   end
  951.  
  952.   function public.encryptCTR(keySched, byteData, iv)
  953.     local nextIV = {}
  954.     for j = 1, 16 do nextIV[j] = iv[j] end
  955.     aes.encrypt(keySched, iv, 1, iv, 1)
  956.     util.xorIV(byteData, iv)
  957.     util.increment(nextIV)
  958.     return nextIV
  959.   end
  960.   --
  961.   -- Decrypt strings
  962.   -- key - byte array with key
  963.   -- string - string to decrypt
  964.   -- modefunction - function for cipher mode to use
  965.   --
  966.   function public.decryptString(key, data, modeFunction, iv)
  967.     if iv then
  968.       local ivCopy = {}
  969.       for i = 1, 16 do ivCopy[i] = iv[i] end
  970.       iv = ivCopy
  971.     else
  972.       iv = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
  973.     end
  974.     local keySched
  975.     if modeFunction == public.decryptOFB or modeFunction == public.decryptCFB or modeFunction == public.decryptCTR then
  976.       keySched = aes.expandEncryptionKey(key)
  977.     else
  978.       keySched = aes.expandDecryptionKey(key)
  979.     end
  980.     local decryptedData = buffer.new()
  981.     for i = 1, #data/16 do
  982.       local offset = (i-1)*16 + 1
  983.       local byteData = {string.byte(data,offset,offset +15)}
  984.       iv = modeFunction(keySched, byteData, iv)
  985.       buffer.addString(decryptedData, string.char(unpack(byteData)))
  986.     end
  987.     return buffer.toString(decryptedData)
  988.   end
  989.   --
  990.   -- the following 4 functions can be used as
  991.   -- modefunction for decryptString
  992.   --
  993.   -- Electronic code book mode decrypt function
  994.   function public.decryptECB(keySched, byteData, iv)
  995.     aes.decrypt(keySched, byteData, 1, byteData, 1)
  996.     return iv
  997.   end
  998.  
  999.   -- Cipher block chaining mode decrypt function
  1000.   function public.decryptCBC(keySched, byteData, iv)
  1001.     local nextIV = {}
  1002.     for j = 1, 16 do nextIV[j] = byteData[j] end
  1003.     aes.decrypt(keySched, byteData, 1, byteData, 1)
  1004.     util.xorIV(byteData, iv)
  1005.     return nextIV
  1006.   end
  1007.  
  1008.   -- Output feedback mode decrypt function
  1009.   function public.decryptOFB(keySched, byteData, iv)
  1010.     aes.encrypt(keySched, iv, 1, iv, 1)
  1011.     util.xorIV(byteData, iv)
  1012.     return iv
  1013.   end
  1014.  
  1015.   -- Cipher feedback mode decrypt function
  1016.   function public.decryptCFB(keySched, byteData, iv)
  1017.     local nextIV = {}
  1018.     for j = 1, 16 do nextIV[j] = byteData[j] end
  1019.     aes.encrypt(keySched, iv, 1, iv, 1)
  1020.     util.xorIV(byteData, iv)
  1021.     return nextIV
  1022.   end
  1023.  
  1024.   public.decryptCTR = public.encryptCTR
  1025.   return public
  1026.   end)
  1027.  
  1028.   -- Simple API for encrypting strings.
  1029.   --
  1030.   AES128 = 16
  1031.   AES192 = 24
  1032.   AES256 = 32
  1033.   ECBMODE = 1
  1034.   CBCMODE = 2
  1035.   OFBMODE = 3
  1036.   CFBMODE = 4
  1037.   CTRMODE = 4
  1038.  
  1039.   local function pwToKey(password, keyLength, iv)
  1040.     local padLength = keyLength
  1041.     if (keyLength == AES192) then
  1042.       padLength = 32
  1043.     end
  1044.     if (padLength > #password) then
  1045.       local postfix = ""
  1046.       for i = 1,padLength - #password do
  1047.         postfix = postfix .. string.char(0)
  1048.       end
  1049.       password = password .. postfix
  1050.     else
  1051.       password = string.sub(password, 1, padLength)
  1052.     end
  1053.     local pwBytes = {string.byte(password,1,#password)}
  1054.     password = ciphermode.encryptString(pwBytes, password, ciphermode.encryptCBC, iv)
  1055.     password = string.sub(password, 1, keyLength)
  1056.     return {string.byte(password,1,#password)}
  1057.   end
  1058.   --
  1059.   -- Encrypts string data with password password.
  1060.   -- password  - the encryption key is generated from this string
  1061.   -- data      - string to encrypt (must not be too large)
  1062.   -- keyLength - length of aes key: 128(default), 192 or 256 Bit
  1063.   -- mode      - mode of encryption: ecb, cbc(default), ofb, cfb
  1064.   --
  1065.   -- mode and keyLength must be the same for encryption and decryption.
  1066.   --
  1067.   function encrypt(password, data, keyLength, mode, iv)
  1068.     assert(password ~= nil, "Empty password.")
  1069.     assert(data ~= nil, "Empty data.")
  1070.     local mode = mode or CBCMODE
  1071.     local keyLength = keyLength or AES128
  1072.     local key = pwToKey(password, keyLength, iv)
  1073.     local paddedData = util.padByteString(data)
  1074.     if mode == ECBMODE then
  1075.       return ciphermode.encryptString(key, paddedData, ciphermode.encryptECB, iv)
  1076.     elseif mode == CBCMODE then
  1077.       return ciphermode.encryptString(key, paddedData, ciphermode.encryptCBC, iv)
  1078.     elseif mode == OFBMODE then
  1079.       return ciphermode.encryptString(key, paddedData, ciphermode.encryptOFB, iv)
  1080.     elseif mode == CFBMODE then
  1081.       return ciphermode.encryptString(key, paddedData, ciphermode.encryptCFB, iv)
  1082.     elseif mode == CTRMODE then
  1083.       return ciphermode.encryptString(key, paddedData, ciphermode.encryptCTR, iv)
  1084.     else
  1085.       error("Unknown mode", 2)
  1086.     end
  1087.   end
  1088.   --
  1089.   -- Decrypts string data with password password.
  1090.   -- password  - the decryption key is generated from this string
  1091.   -- data      - string to encrypt
  1092.   -- keyLength - length of aes key: 128(default), 192 or 256 Bit
  1093.   -- mode      - mode of decryption: ecb, cbc(default), ofb, cfb
  1094.   --
  1095.   -- mode and keyLength must be the same for encryption and decryption.
  1096.   --
  1097.   function decrypt(password, data, keyLength, mode, iv)
  1098.     local mode = mode or CBCMODE
  1099.     local keyLength = keyLength or AES128
  1100.     local key = pwToKey(password, keyLength, iv)
  1101.     local plain
  1102.     if mode == ECBMODE then
  1103.       plain = ciphermode.decryptString(key, data, ciphermode.decryptECB, iv)
  1104.     elseif mode == CBCMODE then
  1105.       plain = ciphermode.decryptString(key, data, ciphermode.decryptCBC, iv)
  1106.     elseif mode == OFBMODE then
  1107.       plain = ciphermode.decryptString(key, data, ciphermode.decryptOFB, iv)
  1108.     elseif mode == CFBMODE then
  1109.       plain = ciphermode.decryptString(key, data, ciphermode.decryptCFB, iv)
  1110.     elseif mode == CTRMODE then
  1111.       plain = ciphermode.decryptString(key, data, ciphermode.decryptCTR, iv)
  1112.     else
  1113.       error("Unknown mode", 2)
  1114.     end
  1115.     result = util.unpadByteString(plain)
  1116.     if (result == nil) then
  1117.       return nil
  1118.     end
  1119.     return result
  1120.   end
  1121. end
  1122.  
  1123. -- SHA-256, HMAC and PBKDF2 functions in ComputerCraft
  1124. -- By Anavrins
  1125. -- For help and details, you can PM me on the CC forums
  1126. -- http://www.computercraft.info/forums2/index.php?/user/12870-anavrins
  1127. -- Pastebin: http://pastebin.com/6UV4qfNF
  1128. -- You may use this code in your projects without asking me, as long as credit is given and this header is kept intact
  1129. local digest, hmac, pbkdf2
  1130. do
  1131.   local mod32 = 2^32
  1132.   local sha_hashlen = 32
  1133.   local sha_blocksize = 64
  1134.   local band    = bit32 and bit32.band or bit.band
  1135.   local bnot    = bit32 and bit32.bnot or bit.bnot
  1136.   local bxor    = bit32 and bit32.bxor or bit.bxor
  1137.   local blshift = bit32 and bit32.lshift or bit.blshift
  1138.   local upack   = unpack
  1139.  
  1140.   local function rrotate(n, b)
  1141.     local s = n/(2^b)
  1142.     local f = s%1
  1143.     return (s-f) + f*mod32
  1144.   end
  1145.  
  1146.   local function brshift(int, by) -- Thanks bit32 for bad rshift
  1147.     local s = int / (2^by)
  1148.     return s - s%1
  1149.   end
  1150.  
  1151.   local H = {
  1152.     0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
  1153.     0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
  1154.   }
  1155.  
  1156.   local K = {
  1157.     0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
  1158.     0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
  1159.     0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
  1160.     0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
  1161.     0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
  1162.     0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
  1163.     0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
  1164.     0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
  1165.   }
  1166.  
  1167.   local function counter(incr)
  1168.     local t1, t2 = 0, 0
  1169.     if 0xFFFFFFFF - t1 < incr then
  1170.       t2 = t2 + 1
  1171.       t1 = incr - (0xFFFFFFFF - t1) - 1    
  1172.     else t1 = t1 + incr
  1173.     end
  1174.     return t2, t1
  1175.   end
  1176.  
  1177.   local function BE_toInt(bs, i)
  1178.     return blshift((bs[i] or 0), 24) + blshift((bs[i+1] or 0), 16) + blshift((bs[i+2] or 0), 8) + (bs[i+3] or 0)
  1179.   end
  1180.  
  1181.   local function preprocess(data)
  1182.     local len = #data
  1183.     local proc = {}
  1184.     data[#data+1] = 0x80
  1185.     while #data%64~=56 do data[#data+1] = 0 end
  1186.     local blocks = math.ceil(#data/64)
  1187.     for i = 1, blocks do
  1188.       proc[i] = {}
  1189.       for j = 1, 16 do
  1190.         proc[i][j] = BE_toInt(data, 1+((i-1)*64)+((j-1)*4))
  1191.       end
  1192.     end
  1193.     proc[blocks][15], proc[blocks][16] = counter(len*8)
  1194.     return proc
  1195.   end
  1196.  
  1197.   local function digestblock(w, C)
  1198.     for j = 17, 64 do
  1199.       local v = w[j-15]
  1200.       local s0 = bxor(bxor(rrotate(w[j-15], 7), rrotate(w[j-15], 18)), brshift(w[j-15], 3))
  1201.       local s1 = bxor(bxor(rrotate(w[j-2], 17), rrotate(w[j-2], 19)), brshift(w[j-2], 10))
  1202.       w[j] = (w[j-16] + s0 + w[j-7] + s1)%mod32
  1203.     end
  1204.     local a, b, c, d, e, f, g, h = upack(C)
  1205.     for j = 1, 64 do
  1206.       local S1 = bxor(bxor(rrotate(e, 6), rrotate(e, 11)), rrotate(e, 25))
  1207.       local ch = bxor(band(e, f), band(bnot(e), g))
  1208.       local temp1 = (h + S1 + ch + K[j] + w[j])%mod32
  1209.       local S0 = bxor(bxor(rrotate(a, 2), rrotate(a, 13)), rrotate(a, 22))
  1210.       local maj = bxor(bxor(band(a, b), band(a, c)), band(b, c))
  1211.       local temp2 = (S0 + maj)%mod32
  1212.       h, g, f, e, d, c, b, a = g, f, e, (d+temp1)%mod32, c, b, a, (temp1+temp2)%mod32
  1213.     end
  1214.     C[1] = (C[1] + a)%mod32
  1215.     C[2] = (C[2] + b)%mod32
  1216.     C[3] = (C[3] + c)%mod32
  1217.     C[4] = (C[4] + d)%mod32
  1218.     C[5] = (C[5] + e)%mod32
  1219.     C[6] = (C[6] + f)%mod32
  1220.     C[7] = (C[7] + g)%mod32
  1221.     C[8] = (C[8] + h)%mod32
  1222.     return C
  1223.   end
  1224.  
  1225.   local mt = {
  1226.     __tostring = function(a) return string.char(unpack(a)) end,
  1227.     __index = {
  1228.       toHex = function(self, s) return ("%02x"):rep(#self):format(unpack(self)) end,
  1229.       isEqual = function(self, t)
  1230.         if type(t) ~= "table" then return false end
  1231.         if #self ~= #t then return false end
  1232.         local ret = 0
  1233.         for i = 1, #self do
  1234.           ret = bit32.bor(ret, bxor(self[i], t[i]))
  1235.         end
  1236.         return ret == 0
  1237.       end
  1238.     }
  1239.   }
  1240.  
  1241.   local function toBytes(t, n)
  1242.     local b = {}
  1243.     for i = 1, n do
  1244.       b[(i-1)*4+1] = band(brshift(band(t[i], 0xFF000000), 24), 0xFF)
  1245.       b[(i-1)*4+2] = band(brshift(band(t[i], 0xFF0000), 16), 0xFF)
  1246.       b[(i-1)*4+3] = band(brshift(band(t[i], 0xFF00), 8), 0xFF)
  1247.       b[(i-1)*4+4] = band(t[i], 0xFF)
  1248.     end
  1249.     return setmetatable(b, mt)
  1250.   end
  1251.  
  1252.   digest = function(data)
  1253.     data = data or ""
  1254.     data = type(data) == "string" and {data:byte(1,-1)} or data
  1255.     data = preprocess(data)
  1256.     local C = {upack(H)}
  1257.     for i = 1, #data do C = digestblock(data[i], C) end
  1258.     return toBytes(C, 8)
  1259.   end
  1260.  
  1261.   hmac = function(data, key)
  1262.     local data = type(data) == "table" and {upack(data)} or {tostring(data):byte(1,-1)}
  1263.     local key = type(key) == "table" and {upack(key)} or {tostring(key):byte(1,-1)}
  1264.     local blocksize = sha_blocksize
  1265.     key = #key > blocksize and digest(key) or key
  1266.     local ipad = {}
  1267.     local opad = {}
  1268.     local padded_key = {}
  1269.     for i = 1, blocksize do
  1270.       ipad[i] = bxor(0x36, key[i] or 0)
  1271.       opad[i] = bxor(0x5C, key[i] or 0)
  1272.     end
  1273.     for i = 1, #data do
  1274.       ipad[blocksize+i] = data[i]
  1275.     end
  1276.     ipad = digest(ipad)
  1277.     for i = 1, blocksize do
  1278.       padded_key[i] = opad[i]
  1279.       padded_key[blocksize+i] = ipad[i]
  1280.     end
  1281.     return digest(padded_key)
  1282.   end
  1283.  
  1284.   pbkdf2 = function(pass, salt, iter, dklen)
  1285.     local out = {}
  1286.     local hashlen = sha_hashlen
  1287.     local block = 1
  1288.     dklen = dklen or 32
  1289.     while dklen > 0 do
  1290.       local ikey = {}
  1291.       local isalt = type(salt) == "table" and {upack(salt)} or {tostring(salt):byte(1,-1)}
  1292.       local clen = dklen > hashlen and hashlen or dklen
  1293.       local iCount = #isalt
  1294.       isalt[iCount+1] = band(brshift(band(block, 0xFF000000), 24), 0xFF)
  1295.       isalt[iCount+2] = band(brshift(band(block, 0xFF0000), 16), 0xFF)
  1296.       isalt[iCount+3] = band(brshift(band(block, 0xFF00), 8), 0xFF)
  1297.       isalt[iCount+4] = band(block, 0xFF)
  1298.       for j = 1, iter do
  1299.         isalt = hmac(isalt, pass)
  1300.         for k = 1, clen do ikey[k] = bxor(isalt[k], ikey[k] or 0) end
  1301.         if j % 200 == 0 then os.queueEvent("PBKDF2", j) coroutine.yield("PBKDF2") end
  1302.       end
  1303.       dklen = dklen - clen
  1304.       block = block+1
  1305.       for k = 1, clen do out[#out+1] = ikey[k] end
  1306.     end
  1307.     return setmetatable(out, mt)
  1308.   end
  1309. end
  1310.  
  1311. local function filterTurtleList()
  1312.   for i = #filteredTurtles, 1, -1 do
  1313.     filteredTurtles[i] = nil
  1314.   end
  1315.   local turtleCount = 0
  1316.   for i = 1, #allTurtles do
  1317.     if (type(fuelFilter) == "boolean" and fuelFilter and allTurtles[i].fuelState) or (not fuelFilter) or (type(fuelFilter) == "string" and not allTurtles[i].fuelState) then
  1318.       turtleCount = turtleCount + 1
  1319.       filteredTurtles[turtleCount] = { }
  1320.       for k, v in pairs(allTurtles[i]) do
  1321.         filteredTurtles[turtleCount][k] = v
  1322.       end
  1323.       filteredTurtles[turtleCount].atList = i
  1324.     end
  1325.   end
  1326.   numPages = math.max(1, math.ceil(#filteredTurtles / 24))
  1327.   pageNum = math.min(pageNum, numPages)
  1328. end
  1329.  
  1330. do
  1331.   local function updateTurtleList(newSettings)
  1332.     local turtleCount = #allTurtles
  1333.     if turtleCount == 0 then                --# the list is empty
  1334.       allTurtles[1] = { }
  1335.       for k, v in pairs(newSettings) do     --# add this turtle
  1336.         allTurtles[1][k] = v
  1337.       end
  1338.     else
  1339.       local nsName, filterCount, done = newSettings.name, #filteredTurtles, false
  1340.       for i = 1, turtleCount do
  1341.         if gtHost == allTurtles[i].cc then    --# we're already on the list
  1342.           for k, v in pairs(newSettings) do   --# update entry with current state of host
  1343.             allTurtles[i][k] = v
  1344.           end
  1345.           for j = 1, filterCount do
  1346.             if filteredTurtles[j].atList == i then
  1347.               for k, v in pairs(newSettings) do
  1348.                 filteredTurtles[j][k] = v
  1349.               end
  1350.               done = true
  1351.               break
  1352.             end
  1353.             if done then break end
  1354.           end
  1355.           return
  1356.         end
  1357.       end
  1358.       for i = 1, turtleCount do
  1359.         if nsName < allTurtles[i].name then --# alphabetize
  1360.           table.insert(allTurtles, i, newSettings) --# insert
  1361.           break
  1362.         end
  1363.         if i == turtleCount then            --# we've reached the end of the list
  1364.           turtleCount = turtleCount + 1
  1365.           allTurtles[turtleCount] = { }     --# tack it on
  1366.           for k, v in pairs(newSettings) do
  1367.             allTurtles[turtleCount][k] = v
  1368.           end
  1369.           break
  1370.         end
  1371.       end
  1372.     end
  1373.     filterTurtleList()
  1374.   end
  1375.  
  1376.   netReceive = function()
  1377.     local id, success, encKey, message, encryptedMessage, decryptedMessage, decodedMessage
  1378.     while true do
  1379.       if not rednet.isOpen(netSide) then rednet.open(netSide) end
  1380.       id, encryptedMessage = rednet.receive("gtRemote")
  1381.       if type(encryptedMessage) == "string" then
  1382.         success, decodedMessage = pcall(decode, encryptedMessage)
  1383.         if success and type(decodedMessage) == "string" then
  1384.           encKey = thisCC .. "gt!Remote" .. tostring(id)
  1385.           success, decryptedMessage = pcall(decrypt, encKey, decodedMessage)
  1386.           if success and type(decryptedMessage) == "string" then
  1387.             success, message = pcall(textutils.unserialize, decryptedMessage)
  1388.             if success and type(message) == "table" and message.program and message.program == "gtRemoteHost" then
  1389.               gtHost = id
  1390.               updateTurtleList(message)
  1391.               if (((runState == "Inventory" or runState == "Remote") and gtHost == allTurtles[thisTurtle].cc) or runState == "List") and not inputting then
  1392.                 if runState == "Inventory" then
  1393.                   drawHeader()
  1394.                   turtleInventory()
  1395.                 elseif runState == "Remote" then
  1396.                   turtleControlScreen()
  1397.                 else
  1398.                   drawCLI()
  1399.                 end
  1400.               end
  1401.             end
  1402.           end
  1403.         end
  1404.       end
  1405.     end
  1406.   end
  1407. end
  1408.  
  1409. local function netSend(targetHost, cmd1, act1)
  1410.   local dataPack = textutils.serialize({ program = "gtRemote", cc = tonumber(thisCC), cmd = cmd1, action = act1 })
  1411.   if not rednet.isOpen(netSide) then rednet.open(netSide) end
  1412.   if targetHost == "ALL" then
  1413.     local encKey = thisCC .. "gt!Remote_Broadcast" .. thisCC
  1414.     local encryptedData = encode(encrypt(encKey, dataPack))
  1415.     rednet.broadcast(encryptedData, "gtRemote")
  1416.   else
  1417.     local encKey = tostring(targetHost) .. "gt!Remote" .. thisCC
  1418.     local encryptedData = encode(encrypt(encKey, dataPack))
  1419.     rednet.send(targetHost, encryptedData, "gtRemote")
  1420.   end
  1421. end
  1422.  
  1423. local function assignColor(assignment)
  1424.   return colorBurst[assignment].color or silver
  1425. end
  1426.  
  1427. local function drawElement(x, y, w, h, txtColor, bgColor, text)
  1428.   if type(w) == "boolean" then
  1429.     term.setCursorPos(x, y)
  1430.     term.setBackgroundColor(w and green or gray)
  1431.     term.write("  ")
  1432.     term.setBackgroundColor(w and gray or red)
  1433.     term.write("  ")
  1434.   else
  1435.     text = text and tostring(text) or ""
  1436.     local txtLen = #text
  1437.     w = math.max(w, txtLen)
  1438.     local spacer = (w - txtLen) / 2
  1439.     local txtLine = string.rep(" ", math.floor(spacer)) .. text .. string.rep(" ", math.ceil(spacer))
  1440.     if txtColor then term.setTextColor(txtColor) end
  1441.     if bgColor then term.setBackgroundColor(bgColor) end
  1442.     if h == 1 then
  1443.       term.setCursorPos(x, y)
  1444.       term.write(txtLine)
  1445.     else
  1446.       local line, textRow = string.rep(" ", w), y + math.floor(h / 2)
  1447.       for i = y, y + h - 1 do
  1448.         term.setCursorPos(x, i)        
  1449.         term.write(i == textRow and txtLine or line) --# Draw one line of the 'element' (box/rectangle/line-seg)
  1450.       end
  1451.     end
  1452.   end
  1453. end
  1454.  
  1455. drawHeader = function()
  1456.   local hColor = (runState == "Remote" or runState == "Inventory" or runState == "color") and assignColor(allTurtles[thisTurtle].color) or blue
  1457.   local hText = runState == "Help" and "gtRemote  " .. gtRver or ((runState == "Remote" or runState == "Inventory" or runState == "color") and allTurtles[thisTurtle].name .. " (cc# " .. tostring(allTurtles[thisTurtle].cc) .. ")" or "gtRemote")
  1458.   drawElement(1, 1, termX, 1, white, hColor, hText) --# title bar
  1459.   if runState == "List" or runState == "goPage" then
  1460.     drawElement(1, 1, 3, 1, nil, nil, "[ ]")
  1461.     local fColor = fuelFilter and green or gray
  1462.     drawElement(2, 1, 1, 1, type(fuelFilter) == "boolean" and fColor or orange, nil, "F")
  1463.     drawElement(termX - 2, 1, 3, 1, white, nil, "[ ]")
  1464.     drawElement(termX - 1, 1, 1, 1, red, nil, "X")
  1465.     drawElement(1, 2, 1, 1, green, gray, string.rep(" ", math.floor(termX / 4) - 2) .. "All ON" .. string.rep(" ", math.ceil(termX / 4) - 2))
  1466.     drawElement(math.ceil(termX / 2), 2, 1, 1, red, nil, string.rep(" ", math.floor(termX / 4) - 2) .. "All OFF" .. string.rep(" ", math.ceil(termX / 4) - 2))
  1467.   elseif runState == "Remote" or runState == "Inventory" or runState == "color" or runState == "Help" then
  1468.     drawElement(1, 2, termX, 1, red, gray, "Close")
  1469.   end
  1470. end
  1471.  
  1472. local function drawColorList(rating)
  1473.   local color
  1474.   drawElement(8, 4, 9, 8, nil, gray)                      --# menu body
  1475.   for k, v in pairs(colorBurst) do
  1476.     if rating == k then
  1477.       color = v.color
  1478.       drawElement(16, v.order + 3, 1, 1, nil, color, " ") --# selected color pip
  1479.     else
  1480.       color = silver
  1481.     end
  1482.     drawElement(7, v.order + 3, 1, 1, nil, v.color, " ")  --# rating color pips
  1483.     if rating == "I" and k == "I" then color = white end
  1484.     drawElement(9, v.order + 3, 1, 1, color, gray, v.text)
  1485.   end
  1486. end
  1487.  
  1488. turtleInventory = function()
  1489.   local currentSlot, selectedSlot, slotContents, isFuel, sCount, txtColor, bgColor = 0, allTurtles[thisTurtle].slot, allTurtles[thisTurtle].contents
  1490.   for y = 7, 13, 2 do       --# y position
  1491.     for x = 3, 12, 3 do     --# x position
  1492.       currentSlot = currentSlot + 1 --# increment inventory slot
  1493.       isFuel = allTurtles[thisTurtle].inv[currentSlot].isFuel
  1494.       sCount = allTurtles[thisTurtle].inv[currentSlot].count
  1495.       txtColor = currentSlot == selectedSlot and black or (sCount > 0 and sky or silver)
  1496.       txtColor = (currentSlot ~= selectedSlot and isFuel) and yellow or txtColor
  1497.       bgColor = currentSlot == selectedSlot and (isFuel and yellow or (sCount > 0 and sky or silver)) or black
  1498.       drawElement(x, y, 2, 1, txtColor, bgColor, tostring(sCount)) --# write inventory count
  1499.     end
  1500.   end
  1501.   drawElement(8, 16, 1, 1, allTurtles[thisTurtle].inv[selectedSlot].isFuel and yellow or (allTurtles[thisTurtle].inv[selectedSlot].count > 0 and sky or silver), black, slotContents .. string.rep(" ", 18 - #slotContents))
  1502.   drawElement(13, 17, 1, 1, silver, nil, tDirection .. "     ")
  1503. end
  1504.  
  1505. local function staticTurtleInventory()
  1506.   drawHeader()
  1507.   drawElement(2, 4, termX - 2, 1, silver, black, allTurtles[thisTurtle].name .. "'s Inventory")
  1508.   drawElement(2, 6, 13, 9, nil, gray) --# Inventory 'box'
  1509.   drawElement(2, 16, 1, 1, gray, black, "Slot:")
  1510.   drawElement(2, 17, 1, 1, nil, nil, "Direction:")
  1511.   drawElement(16, 7, 9, 1, black, yellow, " Refuel")
  1512.   drawElement(16, 9, 9, 1, nil, green, "Place")
  1513.   drawElement(16, 11, 9, 1, nil, red, "Break")
  1514.   drawElement(16, 13, 9, 1, nil, silver, "Equip")
  1515.   drawElement(math.floor(termX / 2) - 9, termY - 1, 1, 1, white, brown, " Refresh Inventory ")
  1516.   turtleInventory()
  1517. end
  1518.  
  1519. turtleControlScreen = function()
  1520.   runState = "Remote"
  1521.   drawHeader()
  1522.   if thisTurtle <= #allTurtles then
  1523.     drawElement(2, 4, 1, 1, assignColor(allTurtles[thisTurtle].color), black, allTurtles[thisTurtle].name) --# Name
  1524.     drawElement(12, 4, 1, 1, red, black, "Redstone")     --# Redstone Output
  1525.     drawElement(22, 4, allTurtles[thisTurtle].redstone)  --# Redstone Output Switch
  1526.     drawElement(2, 6, 1, 1, silver, black, allTurtles[thisTurtle].note) --# Short description
  1527.     local dCheck, tFwd, tUp, tDown = allTurtles[thisTurtle].dirCheck, allTurtles[thisTurtle].forward, allTurtles[thisTurtle].up, allTurtles[thisTurtle].down
  1528.     local bColor = (tFwd and dCheck) and red or black    --# Direction buttons
  1529.     drawElement(5, 8, 2, 1, bColor, white, "/\\")   --# Forward
  1530.     drawElement(5, 9, 2, 1)                         --#
  1531.     drawElement(5, 12, 2, 2, black, nil, "\\/")     --# Back
  1532.     drawElement(3, 10, 2, 1, nil, nil, "/ ")        --# Left
  1533.     drawElement(3, 11, 2, 1, nil, nil, "\\ ")       --#
  1534.     drawElement(7, 10, 2, 1, nil, nil, " \\")       --# Right
  1535.     drawElement(7, 11, 2, 1, nil, nil, " /")        --#
  1536.     drawElement(5, 10, 2, 1, white, black, "..")    --# Center
  1537.     drawElement(5, 11, 2, 1, nil, nil, "..")        --#
  1538.     bColor = (tUp and dCheck) and red or black
  1539.     drawElement(3, 8, 2, 1, bColor, gray, "/\\")    --# Up
  1540.     drawElement(3, 9, 2, 1)                         --#
  1541.     bColor = (tDown and dCheck) and red or black
  1542.     drawElement(3, 12, 2, 2, bColor, gray, "\\/")   --# Down
  1543.     if dCheck then
  1544.       if (tDirection == "Up" and tUp) or (tDirection == "Down" and tDown) or (tDirection == "Forward" and tFwd) then
  1545.         drawElement(7, 8, 2, 1, black, gray, "PL")  --# Place/Break
  1546.         drawElement(7, 9, 2, 1, nil, red, "BR")
  1547.       else
  1548.         drawElement(7, 8, 2, 1, black, green, "PL") --# Place/Break
  1549.         drawElement(7, 9, 2, 1, nil, gray, "BR")
  1550.       end
  1551.     else
  1552.       drawElement(7, 8, 2, 1, black, gray, "PL")    --# Place/Break
  1553.       drawElement(7, 9, 2, 1, nil, nil, "BR")
  1554.     end
  1555.     drawElement(7, 12, 2, 1, black, dCheck and gray or red, "OB")
  1556.     drawElement(7, 13, 2, 1, nil, dCheck and green or gray, "CK")
  1557.     drawElement(12, 8, 1, 1, gray, black, "Fuel")        --# Fuel Gauge
  1558.     local fuelPercent = allTurtles[thisTurtle].fuelPercent
  1559.     local fuelColor = fuelPercent > 49 and green or orange
  1560.     drawElement(17, 8, 1, 1, fuelPercent < 10 and red or fuelColor, nil, fuelPercent < 101 and tostring(fuelPercent) or "Unlimited")
  1561.     if fuelPercent < 101 then
  1562.       term.setTextColor(gray)
  1563.       term.write("%  ")
  1564.       drawElement(12, 9, 1, 1, nil, nil, showFuel and "Units " or "Coal ")
  1565.       term.setTextColor(silver)
  1566.       term.write(showFuel and (tostring(allTurtles[thisTurtle].fuelAmount) .. "   ") or (tostring(allTurtles[thisTurtle].coal) .. "   "))
  1567.     end
  1568.     drawElement(12, 11, 1, 1, gray, nil, "PLBR")         --# Place/Break direction
  1569.     drawElement(17, 11, 1, 1, silver, nil, tDirection .. "     ")
  1570.     drawElement(12, 12, 1, 1, gray, nil, "Slot")         --# Slot selection
  1571.     local selectedSlot = allTurtles[thisTurtle].slot
  1572.     drawElement(17, 12, 1, 1, silver, nil, tostring(selectedSlot) .. " | " .. tostring(allTurtles[thisTurtle].inv[selectedSlot].count) .. "  ")
  1573.     drawElement(12, 13, 14, 1, nil, nil, "<            >")
  1574.     drawElement(14, 13, 10, 1, nil, gray)
  1575.     drawElement(14, 13, 10, 1, allTurtles[thisTurtle].inv[selectedSlot].isFuel and yellow or (allTurtles[thisTurtle].inv[selectedSlot].count > 0 and sky or silver), nil, allTurtles[thisTurtle].contents:sub(1, 10)) --# Selected slot contents
  1576.     drawElement(16, 15, 9, 1, black, nil, "Refresh")     --# Turtle location (Refresh GPS fix button)
  1577.     drawElement(16, 16, 9, 1, nil, nil, "GPS Fix")
  1578.     if allTurtles[thisTurtle].loc.x ~= "No GPS Fix" then --# pgps export (export to pocketgps button)
  1579.       drawElement(16, 17, 9, 1, nil, silver, "Export")
  1580.       drawElement(16, 18, 9, 1, nil, nil, "to pgps")
  1581.     end
  1582.     drawElement(2, 15, 1, 1, silver, black, "Location:") --# Turtle location (x/y/z)
  1583.     drawElement(2, 16, 1, 1, nil, nil, "x:")
  1584.     drawElement(2, 17, 1, 1, nil, nil, "y:")
  1585.     drawElement(2, 18, 1, 1, nil, nil, "z:")
  1586.     drawElement(5, 16, 1, 1, sky, nil, tostring(allTurtles[thisTurtle].loc.x))
  1587.     drawElement(5, 17, 1, 1, nil, nil, tostring(allTurtles[thisTurtle].loc.y))
  1588.     drawElement(5, 18, 1, 1, nil, nil, tostring(allTurtles[thisTurtle].loc.z))
  1589.   end
  1590. end
  1591.  
  1592. local function drawHelpUI()
  1593.   drawElement(1, 3, termX, termY - 2, nil, white)
  1594.   drawHeader()
  1595.   if tempState == "List" then
  1596.     drawElement(2, 4, termX - 1, 1, black, white, "Left click a turtle to")
  1597.     drawElement(2, 5, termX - 1, 1, nil, nil, "control and manage it")
  1598.     drawElement(2, 7, termX - 1, 1, nil, nil, "Middle click a turtle to")
  1599.     drawElement(2, 8, termX - 1, 1, nil, nil, "lock it")
  1600.     drawElement(2, 11, termX - 1, 1, nil, nil, "'All ON / All OFF'")
  1601.     drawElement(2, 12, termX - 1, 1, nil, nil, "controls redstone output")
  1602.     drawElement(2, 13, termX - 1, 1, nil, nil, "on turtles in range")
  1603.     drawElement(2, 15, termX - 1, 1, nil, nil, "[F] = Fuel Filter")
  1604.     drawElement(2, 16, termX - 1, 1, nil, nil, "Filters turtles based")
  1605.     drawElement(2, 17, termX - 1, 1, nil, nil, "on fueled status")
  1606.   elseif tempState == "Remote" then
  1607.     drawElement(2, 4, termX - 1, 1, black, white, "Click arrows to drive")
  1608.     drawElement(2, 5, termX - 1, 1, nil, nil, "or use [W, A, S, D, Q, E]")
  1609.     drawElement(2, 7, termX - 1, 1, nil, nil, "PL/BR[P] = Place/Break   ")
  1610.     drawElement(2, 8, termX - 1, 1, nil, nil, "OB/CK[O] = Obstacle check")
  1611.     drawElement(2, 10, termX - 1, 1, nil, nil, "Left click name or note")
  1612.     drawElement(2, 11, termX - 1, 1, nil, nil, "to edit")
  1613.     drawElement(2, 12, termX - 1, 1, nil, nil, "Right click name to")
  1614.     drawElement(2, 13, termX - 1, 1, nil, nil, "change color")
  1615.     drawElement(2, 15, termX - 1, 1, nil, nil, "Redstone [R] controls")
  1616.     drawElement(2, 16, termX - 1, 1, nil, nil, "RS output on the front")
  1617.     drawElement(2, 18, termX - 1, 1, nil, nil, "'Export to pgps' adds")
  1618.     drawElement(2, 19, termX - 1, 1, nil, nil, "turtle to pgps .places")
  1619.   elseif tempState == "Inventory" then
  1620.     drawElement(2, 4, termX - 1, 1, black, white, "Click inventory slots")
  1621.     drawElement(2, 5, termX - 1, 1, nil, nil, "to select for action")
  1622.     drawElement(2, 7, termX - 1, 1, nil, nil, "Click action button")
  1623.     drawElement(2, 8, termX - 1, 1, nil, nil, "to carry out action")
  1624.     drawElement(2, 10, termX - 1, 1, nil, nil, "Right click 'Place' to")
  1625.     drawElement(2, 11, termX - 1, 1, nil, nil, "engrave a sign")
  1626.     drawElement(2, 13, termX - 1, 1, nil, nil, "Right click 'Break' to")
  1627.     drawElement(2, 14, termX - 1, 1, nil, nil, "attack")
  1628.     drawElement(2, 16, termX - 1, 1, nil, nil, "Left click the displayed")
  1629.     drawElement(2, 17, termX - 1, 1, nil, nil, "direction to change the")
  1630.     drawElement(2, 18, termX - 1, 1, nil, nil, "direction of action")
  1631.   end
  1632. end
  1633.  
  1634. local function drawNaviUI()
  1635.   local pNum = tostring(pageNum)
  1636.   if pageNum < 100 then pNum = "0" .. pNum end --# Add a "0" before double digit page numbers
  1637.   if pageNum < 10 then pNum = "0" .. pNum end  --# Add another "0" before single digit page numbers
  1638.   drawElement(math.floor(termX / 2) - 10, termY, 7, 1, gray, black, pageNum > 1 and "<< BACK" or "       ")
  1639.   drawElement(math.floor(termX / 2) + 4, termY, 7, 1, nil, nil, pageNum < numPages and "NEXT >>" or "       ")
  1640.   drawElement(math.floor((termX - #pNum) / 2) + 1, termY, 3, 1, silver, nil, pNum) --# Page Number
  1641. end
  1642.  
  1643. local function drawMainUI() --# Turtle 'Address Book'
  1644.   local xPos, yPos, tName, tFuelState, tColor, spacer = 1, 4
  1645.   local magicNumber = ((pageNum - 1) * 23) + pageNum
  1646.   for i = magicNumber, math.min(#filteredTurtles, pageNum * 24) do
  1647.     term.setCursorPos(xPos, yPos)
  1648.     tFuelState, tColor = filteredTurtles[i].fuelState, filteredTurtles[i].color
  1649.     if not filteredTurtles[i].lockState then
  1650.       term.setTextColor(tFuelState and white or assignColor(tColor))
  1651.       term.setBackgroundColor(tFuelState and assignColor(tColor) or black)
  1652.     else
  1653.       term.setTextColor(tFuelState and silver or gray)
  1654.       term.setBackgroundColor(tFuelState and gray or black)
  1655.     end
  1656.     tName = filteredTurtles[i].name
  1657.     spacer = (8 - #tName) / 2
  1658.     term.write(string.rep(" ", math.floor(spacer)) .. tName .. string.rep(" ", math.ceil(spacer)))
  1659.     yPos = yPos + 2
  1660.     if yPos > 19 then yPos = 4 xPos = xPos + 9 end
  1661.   end
  1662. end
  1663.  
  1664. do
  1665.   local runStates = {
  1666.     List = function() drawMainUI() drawNaviUI() end;
  1667.     Remote = function() turtleControlScreen() end;
  1668.     Inventory = function() staticTurtleInventory() end;
  1669.   }
  1670.  
  1671.   drawCLI = function() --# Client Interface 'decider'
  1672.     if not inputting then
  1673.       drawHeader()
  1674.       if runStates[runState] then runStates[runState]() end
  1675.     end
  1676.   end
  1677. end
  1678.  
  1679. local function readInput(cX, cY, cO, bG, limit, mask) --# cursor X, Y, text color, bg color, character limit, character mask
  1680.   local word, pos = "", 0
  1681.   local curX, curY = cX, cY
  1682.   inputting, timerDelay = true, true
  1683.   os.cancelTimer(pollTimer)
  1684.   bG = bG or black
  1685.   limit = (limit and type(limit) == "number" and limit > 0) and limit or 21
  1686.   term.setCursorPos(curX, curY)
  1687.   term.setTextColor(cO)
  1688.   term.setBackgroundColor(bG)
  1689.   term.setCursorBlink(true)
  1690.   while true do
  1691.     local event, data, mX, mY = os.pullEvent()
  1692.     if event == "key" then
  1693.       if data == keys.backspace then
  1694.         if curX > cX then
  1695.           curX = math.max(cX, curX - 1)
  1696.           pos = math.max(0, pos - 1)
  1697.           word = word:sub(1, #word - 1)
  1698.         end
  1699.         drawElement(curX, curY, 1, 1, cO, bG, " ")
  1700.         term.setCursorPos(curX, curY)
  1701.       elseif data == keys.enter or data == keys.numPadEnter then
  1702.         break
  1703.       end
  1704.     elseif event == "char" and pos < limit then
  1705.       drawElement(curX, curY, 1, 1, cO, bG, mask or data)
  1706.       word = word .. data
  1707.       curX = curX + 1
  1708.       pos = pos + 1
  1709.     elseif event == "paste" and pos < limit then
  1710.       if pos + #data > limit then
  1711.         data = data:sub(1, limit - pos)
  1712.       end
  1713.       drawElement(curX, curY, 1, 1, cO, bG, mask and string.rep(mask, #data) or data)
  1714.       word = word .. data
  1715.       curX = curX + #data
  1716.       pos = pos + #data
  1717.     elseif event == "mouse_click" then
  1718.       if mY ~= curY or mX < cX or mX >= cX + limit then
  1719.         break
  1720.       end
  1721.     end
  1722.   end
  1723.   term.setCursorBlink(false)
  1724.   inputting = false
  1725.   return word
  1726. end
  1727.  
  1728. do
  1729.   local function toggleFuelFilter()
  1730.     if type(fuelFilter) == "boolean" then
  1731.       fuelFilter = fuelFilter and "noFuel" or true
  1732.     else
  1733.       fuelFilter = false
  1734.     end
  1735.     filterTurtleList()
  1736.     drawElement(1, 3, termX, termY - 2, nil, black)
  1737.     drawCLI()
  1738.   end
  1739.  
  1740.   local function execPLBR(check)
  1741.     if check then
  1742.       if (tDirection == "Up" and allTurtles[thisTurtle].up) or (tDirection == "Down" and allTurtles[thisTurtle].down) or (tDirection == "Forward" and allTurtles[thisTurtle].forward) then
  1743.         drawElement(7, 8, 2, 1, white, red, "PL")   --# Place/Break
  1744.         drawElement(7, 9, 2, 1, nil, nil, "BR")
  1745.         sleep(0.1)
  1746.         drawElement(7, 8, 2, 1, black, gray, "PL")  --# Place/Break
  1747.         drawElement(7, 9, 2, 1, nil, red, "BR")
  1748.       else
  1749.         drawElement(7, 8, 2, 1, white, green, "PL") --# Place/Break
  1750.         drawElement(7, 9, 2, 1, nil, nil, "BR")
  1751.         sleep(0.1)
  1752.         drawElement(7, 8, 2, 1, black, nil, "PL")   --# Place/Break
  1753.         drawElement(7, 9, 2, 1, nil, gray, "BR")
  1754.       end
  1755.     else
  1756.       drawElement(7, 8, 2, 1, black, white, "PL")   --# Place/Break
  1757.       drawElement(7, 9, 2, 1, nil, nil, "BR")
  1758.       sleep(0.1)
  1759.       drawElement(7, 8, 2, 1, nil, gray, "PL")      --# Place/Break
  1760.       drawElement(7, 9, 2, 1, nil, nil, "BR")
  1761.     end
  1762.     if not check or ((tDirection == "Up" and allTurtles[thisTurtle].up) or (tDirection == "Down" and allTurtles[thisTurtle].down) or (tDirection == "Forward" and allTurtles[thisTurtle].forward)) then
  1763.       netSend(allTurtles[thisTurtle].cc, "dig", tDirection)
  1764.     else
  1765.       netSend(allTurtles[thisTurtle].cc, "put", tDirection)
  1766.     end
  1767.   end
  1768.  
  1769.   local function inputArrow(direction)
  1770.     if direction == "up" then
  1771.       drawElement(3, 8, 2, 1, black, white, "/\\")  --# Up
  1772.       drawElement(3, 9, 2, 1)
  1773.       sleep(0.1)
  1774.       drawElement(3, 8, 2, 1, black, gray, "/\\")   --# Up
  1775.       drawElement(3, 9, 2, 1)
  1776.       netSend(allTurtles[thisTurtle].cc, "move", "up")
  1777.     elseif direction == "down" then
  1778.       drawElement(3, 12, 2, 2, black, white, "\\/") --# Down
  1779.       sleep(0.1)
  1780.       drawElement(3, 12, 2, 2, nil, gray, "\\/")    --# Down
  1781.       netSend(allTurtles[thisTurtle].cc, "move", "down")
  1782.     elseif direction == "forward" then
  1783.       drawElement(5, 8, 2, 1, white, gray, "/\\")   --# Forward
  1784.       drawElement(5, 9, 2, 1)
  1785.       sleep(0.1)
  1786.       drawElement(5, 8, 2, 1, black, white, "/\\")  --# Forward
  1787.       drawElement(5, 9, 2, 1)
  1788.       netSend(allTurtles[thisTurtle].cc, "move", "forward")
  1789.     elseif direction == "back" then
  1790.       drawElement(5, 12, 2, 2, white, gray, "\\/")  --# Back
  1791.       sleep(0.1)
  1792.       drawElement(5, 12, 2, 2, black, white, "\\/") --# Back
  1793.       netSend(allTurtles[thisTurtle].cc, "move", "back")
  1794.     elseif direction == "left" then
  1795.       drawElement(3, 10, 2, 1, white, gray, "/ ")   --# Left
  1796.       drawElement(3, 11, 2, 1, nil, nil, "\\ ")     --#
  1797.       sleep(0.1)
  1798.       drawElement(3, 10, 2, 1, black, white, "/ ")  --# Left
  1799.       drawElement(3, 11, 2, 1, nil, nil, "\\ ")     --#
  1800.       netSend(allTurtles[thisTurtle].cc, "move", "left")
  1801.     elseif direction == "right" then
  1802.       drawElement(7, 10, 2, 1, white, gray, " \\")  --# Right
  1803.       drawElement(7, 11, 2, 1, nil, nil, " /")      --#
  1804.       sleep(0.1)
  1805.       drawElement(7, 10, 2, 1, black, white, " \\") --# Right
  1806.       drawElement(7, 11, 2, 1, nil, nil, " /")      --#
  1807.       netSend(allTurtles[thisTurtle].cc, "move", "right")
  1808.     end
  1809.   end
  1810.  
  1811.   local directions = {
  1812.     Up = "Down";
  1813.     Down = "Forward";
  1814.     Forward = "Up";
  1815.   }
  1816.  
  1817.   local invSelect = {
  1818.     [3] = { [7] = 1, [9] = 5, [11] = 9, [13] = 13 }; --# [xCoord] = { [yCoord] = slot, [yCoord] = slot, etc. }
  1819.     [4] = { [7] = 1, [9] = 5, [11] = 9, [13] = 13 };
  1820.     [6] = { [7] = 2, [9] = 6, [11] = 10, [13] = 14 };
  1821.     [7] = { [7] = 2, [9] = 6, [11] = 10, [13] = 14 };
  1822.     [9] = { [7] = 3, [9] = 7, [11] = 11, [13] = 15 };
  1823.     [10] = { [7] = 3, [9] = 7, [11] = 11, [13] = 15 };
  1824.     [12] = { [7] = 4, [9] = 8, [11] = 12, [13] = 16 };
  1825.     [13] = { [7] = 4, [9] = 8, [11] = 12, [13] = 16 };
  1826.   }
  1827.  
  1828.   local keyList = {
  1829.     [16] = function() inputArrow("down") end;    --# Q (down)
  1830.     [17] = function() inputArrow("forward") end; --# W (forward)
  1831.     [18] = function() inputArrow("up") end;      --# E (up)
  1832.     [19] = function() netSend(allTurtles[thisTurtle].cc, "rds", not allTurtles[thisTurtle].redstone) end; --# R (redstone)
  1833.     [24] = function() netSend(allTurtles[thisTurtle].cc, "dcToggle", not allTurtles[thisTurtle].dirCheck) end; --# O (Obstacle check)
  1834.     [25] = function() execPLBR(allTurtles[thisTurtle].dirCheck) end; --# P (Place/Break)
  1835.     [30] = function() inputArrow("left") end;    --# A (left)
  1836.     [31] = function() inputArrow("back") end;    --# S (back)
  1837.     [32] = function() inputArrow("right") end;   --# D (right)
  1838.   }
  1839.  
  1840.   local function inputMain()
  1841.     local event, mButton, mcX, mcY, xPos, yPos, magicNumber
  1842.     while true do
  1843.       event, mButton, mcX, mcY = os.pullEvent()
  1844.       if event == "mouse_click" then
  1845.         if runState == "Help" then
  1846.           if mcY == 2 then
  1847.             drawElement(1, 2, termX, termY - 1, nil, black)
  1848.             runState = tempState
  1849.             drawCLI()
  1850.           end
  1851.         elseif runState == "Remote" then
  1852.           if mcY == 2 then                      --# Exit Remote/Edit Screen
  1853.             drawElement(2, 2, termX, termY, nil, black)
  1854.             runState = "List"
  1855.             drawCLI()
  1856.           elseif mcY == 4 then
  1857.             if mcX > 1 and mcX < 10 and mButton ~= 3 then
  1858.               if mButton == 1 then              --# Edit Turtle Name
  1859.                 drawElement(2, 4, 1, 1, gray, black, allTurtles[thisTurtle].name)
  1860.                 runState = "EditName"
  1861.               else                              --# Change color assignment
  1862.                 drawColorList(allTurtles[thisTurtle].color)
  1863.                 runState = "color"
  1864.               end
  1865.               return
  1866.             elseif mcX > 21 and mcX < 26 and mButton == 1 then --# Redstone output
  1867.               netSend(allTurtles[thisTurtle].cc, "rds", not allTurtles[thisTurtle].redstone)
  1868.             end
  1869.           elseif mcY == 6 and mButton == 1 then --# Edit Turtle Note
  1870.             if mcX > 1 then
  1871.               drawElement(2, 6, 1, 1, gray, black, allTurtles[thisTurtle].note)
  1872.               term.setBackgroundColor(black)
  1873.               runState = "EditNote"
  1874.               return
  1875.             end
  1876.           elseif mcY == 8 and mButton == 1 then --# Movement / Actions
  1877.             if mcX > 2 and mcX < 5 then         --# UP
  1878.               inputArrow("up")
  1879.             elseif mcX > 4 and mcX < 7 then     --# Forward
  1880.               inputArrow("forward")
  1881.             elseif mcX > 6 and mcX < 9 then     --# Place/Break
  1882.               execPLBR(allTurtles[thisTurtle].dirCheck)
  1883.             end
  1884.           elseif mcY == 9 and mButton == 1 then
  1885.             if mcX > 2 and mcX < 5 then         --# UP
  1886.               inputArrow("up")
  1887.             elseif mcX > 4 and mcX < 7 then     --# Forward
  1888.               inputArrow("forward")
  1889.             elseif mcX > 6 and mcX < 9 then     --# Tunnel
  1890.               execPLBR(allTurtles[thisTurtle].dirCheck)
  1891.             elseif mcX > 11 and mcX < termX and allTurtles[thisTurtle].fuelPercent < 101 then --# Fuel/Coal filter
  1892.               showFuel = not showFuel
  1893.               drawElement(12, 9, 1, 1, gray, black, showFuel and "Units " or "Coal ")
  1894.               term.setTextColor(silver)
  1895.               term.write(showFuel and (tostring(allTurtles[thisTurtle].fuelAmount)) or (tostring(allTurtles[thisTurtle].coal) .. "     "))
  1896.             end
  1897.           elseif mcY == 10 and mButton == 1 then
  1898.             if mcX > 2 and mcX < 5 then         --# Left
  1899.               inputArrow("left")
  1900.             elseif mcX > 4 and mcX < 7 then     --# Center
  1901.               runState = "shellCmd"
  1902.               return
  1903.             elseif mcX > 6 and mcX < 9 then     --# Right
  1904.               inputArrow("right")
  1905.             end
  1906.           elseif mcY == 11 and mButton == 1 then
  1907.             if mcX > 2 and mcX < 5 then         --# Left
  1908.               inputArrow("left")
  1909.             elseif mcX > 4 and mcX < 7 then     --# Center
  1910.               runState = "shellCmd"
  1911.               return
  1912.             elseif mcX > 6 and mcX < 9 then     --# Right
  1913.               inputArrow("right")
  1914.             elseif mcX > 11 and mcX < termX - 1 then --# Change direction of action
  1915.               tDirection = directions[tDirection]
  1916.               drawElement(17, 11, 1, 1, silver, black, tDirection .. "     ")
  1917.               if allTurtles[thisTurtle].dirCheck then
  1918.                 if (tDirection == "Up" and allTurtles[thisTurtle].up) or (tDirection == "Down" and allTurtles[thisTurtle].down) or (tDirection == "Forward" and allTurtles[thisTurtle].forward) then
  1919.                   drawElement(7, 8, 2, 1, black, gray, "PL")  --# Place/Break
  1920.                   drawElement(7, 9, 2, 1, nil, red, "BR")
  1921.                 else
  1922.                   drawElement(7, 8, 2, 1, black, green, "PL") --# Place/Break
  1923.                   drawElement(7, 9, 2, 1, nil, gray, "BR")
  1924.                 end
  1925.               end
  1926.             end
  1927.           elseif mcY == 12 and mButton == 1 then
  1928.             if mcX > 2 and mcX < 5 then         --# DOWN
  1929.               inputArrow("down")
  1930.             elseif mcX > 4 and mcX < 7 then     --# Back
  1931.               inputArrow("back")
  1932.             elseif mcX > 6 and mcX < 9 then     --# Obstacle check
  1933.               netSend(allTurtles[thisTurtle].cc, "dcToggle", not allTurtles[thisTurtle].dirCheck)
  1934.             end
  1935.           elseif mcY == 13 and mButton == 1 then
  1936.             if mcX > 2 and mcX < 5 then         --# DOWN
  1937.               inputArrow("down")
  1938.             elseif mcX > 4 and mcX < 7 then     --# Back
  1939.               inputArrow("back")
  1940.             elseif mcX > 6 and mcX < 9 then     --# Obstacle check
  1941.               netSend(allTurtles[thisTurtle].cc, "dcToggle", not allTurtles[thisTurtle].dirCheck)
  1942.             elseif mcX == 12 or mcX == termX - 1 then --# Select inventory slot
  1943.               local selectedSlot = allTurtles[thisTurtle].slot
  1944.               selectedSlot = mcX == 12 and selectedSlot - 1 or selectedSlot + 1
  1945.               if selectedSlot < 1 then selectedSlot = 16 end
  1946.               if selectedSlot > 16 then selectedSlot = 1 end
  1947.               netSend(allTurtles[thisTurtle].cc, "sel", selectedSlot)
  1948.             elseif mcX > 13 and mcX < termX - 2 then --# Open inventory screen
  1949.               netSend(allTurtles[thisTurtle].cc, "inv", "inv")
  1950.               drawElement(1, 2, termX, termY - 1, nil, black)
  1951.               runState = "Inventory"
  1952.               drawCLI()
  1953.             end
  1954.           elseif (mcY == 15 or mcY == 16) and mButton == 1 then --# Refresh GPS fix
  1955.             if mcX > 15 and mcX < 25 then
  1956.               drawElement(16, 15, 9, 1, white, gray, "Refresh")
  1957.               drawElement(16, 16, 9, 1, nil, nil, "GPS Fix")
  1958.               sleep(0.1)
  1959.               drawElement(16, 15, 9, 1, black, nil, "Refresh")
  1960.               drawElement(16, 16, 9, 1, nil, nil, "GPS Fix")
  1961.               netSend(allTurtles[thisTurtle].cc, "gpsLoc")
  1962.             end
  1963.           elseif (mcY == 17 or mcY == 18) and mButton == 1 then
  1964.             if mcX > 15 and mcX < 25 and allTurtles[thisTurtle].loc.x ~= "No GPS Fix" then --# Export to Lyqyd's pocketgps
  1965.               drawElement(16, 17, 9, 1, white, silver, "Export")
  1966.               drawElement(16, 18, 9, 1, nil, nil, "to pgps")
  1967.               sleep(0.1)
  1968.               drawElement(16, 17, 9, 1, black, nil, "Export")
  1969.               drawElement(16, 18, 9, 1, nil, nil, "to pgps")
  1970.               local pgpsPlaces = fs.open("/.places", fs.exists("/.places") and "a" or "w")
  1971.               pgpsPlaces.writeLine(allTurtles[thisTurtle].loc.x .. ", " .. allTurtles[thisTurtle].loc.y .. ", " .. allTurtles[thisTurtle].loc.z .. ", " .. allTurtles[thisTurtle].name)
  1972.               pgpsPlaces.close()
  1973.             end
  1974.           end
  1975.         elseif runState == "Inventory" then
  1976.           if mcY == 2 and mButton == 1 then --# Close
  1977.             drawElement(1, 2, termX, termY - 1, nil, black)
  1978.             runState = "Remote"
  1979.             drawCLI()
  1980.           elseif mcY == 17 and mButton == 1 then
  1981.             if mcX > 12 and mcX < 20 then   --# Choose direction of action
  1982.               tDirection = directions[tDirection]
  1983.               drawElement(13, 17, 1, 1, silver, black, tDirection .. "     ")
  1984.             end
  1985.           elseif mcY == termY - 1 and mButton == 1 then --# Refresh inventory
  1986.             drawElement(math.floor(termX / 2) - 9, termY - 1, 1, 1, black, silver, " Refresh Inventory ")
  1987.             sleep(0.1)
  1988.             drawElement(math.floor(termX / 2) - 9, termY - 1, 1, 1, white, brown, " Refresh Inventory ")
  1989.             netSend(allTurtles[thisTurtle].cc, "inv", "inv")
  1990.           end
  1991.           if mcX < 15 and mButton == 1 then --# Inventory
  1992.             if invSelect[mcX] and invSelect[mcX][mcY] then
  1993.               netSend(allTurtles[thisTurtle].cc, "sel", invSelect[mcX][mcY])
  1994.             end
  1995.           elseif mcX > 14 then              --# Refuel/Place/Break/Equip
  1996.             if mcY == 7 then           --# Refuel
  1997.               drawElement(16, 7, 9, 1, white, gray, " Refuel")
  1998.               sleep(0.1)
  1999.               drawElement(16, 7, 9, 1, black, yellow, " Refuel")
  2000.               if mButton == 1 then
  2001.                 netSend(allTurtles[thisTurtle].cc, "refuel", 1)
  2002.               elseif mButton == 2 then
  2003.                 netSend(allTurtles[thisTurtle].cc, "refuel", 10)
  2004.               elseif mButton == 3 then
  2005.                 netSend(allTurtles[thisTurtle].cc, "refuel", allTurtles[thisTurtle].inv[allTurtles[thisTurtle].slot].count)
  2006.               end
  2007.             elseif mcY == 9 and mButton ~= 3 then --# Place or engrave
  2008.               drawElement(16, 9, 9, 1, white, gray, "Place")
  2009.               sleep(0.1)
  2010.               drawElement(16, 9, 9, 1, black, green, "Place")
  2011.               if mButton == 1 then     --# Place
  2012.                 netSend(allTurtles[thisTurtle].cc, "put", tDirection)
  2013.               elseif mButton == 2 and allTurtles[thisTurtle].contents == "sign" then --# Engrave
  2014.                 runState = "engrave"
  2015.                 return
  2016.               end
  2017.             elseif mcY == 11 and mButton ~= 3 then --# All units, break and attack!
  2018.               drawElement(16, 11, 9, 1, white, gray, "Break")
  2019.               sleep(0.1)
  2020.               drawElement(16, 11, 9, 1, black, red, "Break")
  2021.               if mButton == 1 then     --# Break
  2022.                 netSend(allTurtles[thisTurtle].cc, "dig", tDirection)
  2023.               elseif mButton == 2 then --# Attack
  2024.                 netSend(allTurtles[thisTurtle].cc, "atk", tDirection)
  2025.               end
  2026.             elseif mcY == 13 and mButton ~= 3 then --# Equip
  2027.               drawElement(16, 13, 9, 1, white, gray, "Equip")
  2028.               sleep(0.1)
  2029.               drawElement(16, 13, 9, 1, black, silver, "Equip")
  2030.               if mButton == 1 then     --# Equip left
  2031.                 netSend(allTurtles[thisTurtle].cc, "eqp", "left")
  2032.               elseif mButton == 2 then --# Equip right
  2033.                 netSend(allTurtles[thisTurtle].cc, "eqp", "right")
  2034.               end
  2035.             end
  2036.           end
  2037.         elseif runState == "List" then
  2038.           if mcY == 1 and mButton == 1 then
  2039.             if mcX > 0 and mcX < 4 then --# Fuel filter
  2040.               toggleFuelFilter()
  2041.             elseif mcX > termX - 3 and mcX <= termX then --# Quit
  2042.               kernelState = false
  2043.               if rednet.isOpen(netSide) then rednet.close(netSide) end
  2044.               term.setBackgroundColor(black)
  2045.               term.setTextColor(white)
  2046.               term.clear()
  2047.               term.setCursorPos(1, 1)
  2048.               return
  2049.             end
  2050.           elseif mcY == 2 and mButton == 1 then --# ALL ON/OFF
  2051.             netSend("ALL", "rds", mcX < termX / 2)
  2052.           elseif mcY > 3 and mcY < 19 then --# Open a turtle's properties/control screen
  2053.             magicNumber, xPos, yPos = ((pageNum - 1) * 23) + pageNum, 1, 4
  2054.             for i = magicNumber, math.min(#filteredTurtles, pageNum * 24) do
  2055.               if mcX >= xPos and mcX < xPos + 8 and mcY == yPos then
  2056.                 thisTurtle = filteredTurtles[i].atList
  2057.                 if not filteredTurtles[i].lockState then
  2058.                   if mButton == 1 or mButton == 2 then
  2059.                     netSend(allTurtles[thisTurtle].cc, "inv", "inv")
  2060.                     drawElement(1, 2, termX, termY - 1, nil, black)
  2061.                     turtleControlScreen()
  2062.                   elseif mButton == 3 then
  2063.                     netSend(allTurtles[thisTurtle].cc, "lock")
  2064.                   end
  2065.                   break
  2066.                 else
  2067.                   runState = "password"
  2068.                   return
  2069.                 end
  2070.               end
  2071.               yPos = yPos + 2
  2072.               if yPos > 19 then yPos = 4 xPos = xPos + 9 end
  2073.             end
  2074.           elseif mcY == termY and numPages > 1 and mButton == 1 then --# Page Navigation via click
  2075.             if mcX < math.floor(termX / 2) - 3 or mcX > math.floor(termX / 2) + 3 then --# Page Back / Forward
  2076.               pageNum = mcX < math.floor(termX / 2) - 3 and math.max(1, pageNum - 1) or math.min(pageNum + 1, numPages)
  2077.               if pageNum == numPages and numPages > 1 then drawElement(2, 4, termX, termY, nil, black) end
  2078.               drawMainUI()
  2079.               drawNaviUI()
  2080.             elseif mcX > math.floor(termX / 2) - 2 and mcX < math.floor(termX / 2) + 2 then --# Page Numbers (Go To Page dialogue)
  2081.               runState = "goPage"
  2082.               return
  2083.             end
  2084.           end
  2085.         end
  2086.       elseif event == "mouse_scroll" and runState == "List" then
  2087.         pageNum = mButton == 1 and math.min(pageNum + 1, numPages) or math.max(1, pageNum - 1)
  2088.         if pageNum == numPages and numPages > 1 then drawElement(2, 4, termX, termY, nil, black) end
  2089.         drawMainUI()
  2090.         drawNaviUI()
  2091.       elseif event == "key" then
  2092.         if mButton == keys.f1 then --# F1 / Help
  2093.           if runState ~= "Help" then
  2094.             tempState = runState
  2095.             runState = "Help"
  2096.             drawHelpUI()
  2097.           else
  2098.             runState = tempState
  2099.             drawElement(1, 3, termX, termY - 2, nil, black)
  2100.             drawCLI()
  2101.           end
  2102.         end
  2103.         if runState == "List" then
  2104.           if mButton == 33 then --# F / Fuel Filter
  2105.             toggleFuelFilter()
  2106.           end
  2107.         elseif runState == "Remote" then
  2108.           if keyList[mButton] then keyList[mButton]() end
  2109.         end
  2110.       end
  2111.     end
  2112.   end
  2113.  
  2114.   local function colorPicker()
  2115.     local choice = false
  2116.     local _, button, x, y = os.pullEvent("mouse_click")
  2117.     if x > 6 and x < 17 and y > 3 and y < 12 and button == 1 then
  2118.       for colorChoice = 4, 11 do
  2119.         if y == colorChoice then
  2120.           for k, v in pairs(colorBurst) do
  2121.             if (colorChoice - 3) == v.order then
  2122.               netSend(allTurtles[thisTurtle].cc, "color", k)
  2123.               choice = true
  2124.               break
  2125.             end
  2126.           end
  2127.         end
  2128.         if choice then break end
  2129.       end
  2130.     end
  2131.     drawElement(7, 4, 10, 8, nil, black)
  2132.     turtleControlScreen()
  2133.   end
  2134.  
  2135.   local function editEntry()
  2136.     if runState == "EditName" then
  2137.       drawElement(2, 4, 1, 1, gray, black, allTurtles[thisTurtle].name)
  2138.       local newName = readInput(2, 4, yellow, nil, 8)
  2139.       if newName ~= "" then
  2140.         netSend(allTurtles[thisTurtle].cc, "name", newName)
  2141.         drawElement(2, 4, 8, 1)
  2142.       else
  2143.         drawElement(2, 4, 1, 1, assignColor(allTurtles[thisTurtle].color), nil, allTurtles[thisTurtle].name)
  2144.       end
  2145.     elseif runState == "EditNote" then
  2146.       drawElement(2, 6, 1, 1, gray, black, allTurtles[thisTurtle].note)
  2147.       local newNote = readInput(2, 6, white, nil, 21)
  2148.       if newNote ~= "" then
  2149.         netSend(allTurtles[thisTurtle].cc, "note", newNote)
  2150.         drawElement(2, 6, 21, 1)
  2151.       else
  2152.         drawElement(2, 6, 1, 1, silver, nil, allTurtles[thisTurtle].note)
  2153.       end
  2154.     end
  2155.     runState = "Remote"
  2156.   end
  2157.  
  2158.   local function enterPassword()
  2159.     drawElement(math.floor(termX / 2) - 7, 8, 15, 1, white, gray, "   Password:   ")
  2160.     drawElement(math.floor(termX / 2) - 7, 9, 15, 2)
  2161.     drawElement(math.floor(termX / 2) - 6, 9, 13, 1, nil, black) --# input area bg
  2162.     local pass = readInput(math.floor(termX / 2) - 6, 9, lime, nil, 13, "*")
  2163.     if pass ~= "" then
  2164.       local pw = table.concat(pbkdf2(pass, "gt!Remote", 15))
  2165.       netSend(allTurtles[thisTurtle].cc, "unlock", pw)
  2166.     end
  2167.     drawElement(math.floor(termX / 2) - 7, 8, 15, 3)
  2168.     runState = "List"
  2169.     drawMainUI()
  2170.   end
  2171.  
  2172.   local function goToPage()
  2173.     drawElement(math.floor(termX / 2) - 3, termY - 3, 7, 1, white, gray, "Page:")
  2174.     drawElement(math.floor(termX / 2) - 3, termY - 2, 7, 2)
  2175.     drawElement(math.floor(termX / 2) - 2, termY - 2, 5, 1, nil, black) --# input area bg
  2176.     local newPage = tonumber(readInput(math.floor(termX / 2) - 1, termY - 2, lime, nil, 3))
  2177.     pageNum = newPage or pageNum
  2178.     pageNum = math.max(1, math.min(pageNum, numPages))
  2179.     if pageNum == numPages and numPages > 1 then
  2180.       drawElement(1, 4, termX, termY - 3)
  2181.     else
  2182.       drawElement(math.floor(termX / 2) - 3, termY - 3, 7, 3)
  2183.     end
  2184.     runState = "List"
  2185.     drawMainUI()
  2186.     drawNaviUI()
  2187.   end
  2188.  
  2189.   local function getSignText()
  2190.     drawElement(math.floor(termX / 2) - 8, math.floor(termY / 2) - 1, 17, 1, black, silver, "Engrave")
  2191.     drawElement(math.floor(termX / 2) - 8, math.floor(termY / 2), 17, 2)
  2192.     drawElement(math.floor(termX / 2) - 7, math.floor(termY / 2), 15, 1, nil, black) --# input area bg
  2193.     local newText = readInput(math.floor(termX / 2) - 7, math.floor(termY / 2), lime)
  2194.     if newText ~= "" then
  2195.       netSend(allTurtles[thisTurtle].cc, "put", newText)
  2196.     end
  2197.     drawElement(math.floor(termX / 2) - 8, math.floor(termY / 2) - 1, 17, 3)
  2198.     runState = "Inventory"
  2199.     staticTurtleInventory()
  2200.   end
  2201.  
  2202.   local function shellCommand()
  2203.     drawElement(2, 8, termX - 2, 1, white, gray, "Command:")
  2204.     drawElement(2, 9, termX - 2, 2)
  2205.     drawElement(3, 9, termX - 4, 1, nil, black) --# input area bg
  2206.     local sCommand = readInput(3, 9, lime, nil, 22)
  2207.     if sCommand ~= "" then
  2208.       netSend(allTurtles[thisTurtle].cc, "sCmd", sCommand)
  2209.     end
  2210.     drawElement(2, 8, termX - 2, 3)
  2211.     turtleControlScreen()
  2212.   end
  2213.  
  2214.   local runStates = {
  2215.     List = function() inputMain() end;
  2216.     Remote = function() inputMain() end;
  2217.     Inventory = function() inputMain() end;
  2218.     Help = function() inputMain() end;
  2219.     EditName = function() editEntry() end;
  2220.     EditNote = function() editEntry() end;
  2221.     password = function() enterPassword() end;
  2222.     engrave = function() getSignText() end;
  2223.     shellCmd = function() shellCommand() end;
  2224.     goPage = function() goToPage() end;
  2225.     color = function() colorPicker() end;
  2226.   }
  2227.  
  2228.   userInput = function()
  2229.     repeat
  2230.       if runStates[runState] then runStates[runState]() end
  2231.       if kernelState and timerDelay and not inputting then
  2232.         timerDelay = false
  2233.         pollTimer = os.startTimer(0.1)
  2234.       end
  2235.     until not kernelState
  2236.   end
  2237. end
  2238.  
  2239. local function dataPoller()
  2240.   local removal, _, timer = false
  2241.   while true do
  2242.     _, timer = os.pullEvent("timer")
  2243.     if timer == pollTimer then
  2244.       if runState == "List" then
  2245.         for i = #allTurtles, 1, -1 do
  2246.           if allTurtles[i].quietCount > 1 then
  2247.             table.remove(allTurtles, i)
  2248.             removal = true
  2249.           else
  2250.             allTurtles[i].quietCount = allTurtles[i].quietCount + 1
  2251.           end
  2252.         end
  2253.         if removal then
  2254.           removal = false
  2255.           filterTurtleList()
  2256.           drawElement(1, 4, termX, termY - 3, nil, black)
  2257.           drawMainUI()
  2258.           drawNaviUI()
  2259.         end
  2260.       end
  2261.       if not timerDelay then
  2262.         netSend("ALL", "gtrQRY", "gtrQRY")
  2263.         pollTimer = os.startTimer(5)
  2264.       end
  2265.     end
  2266.   end
  2267. end
  2268.  
  2269. term.setBackgroundColor(black)
  2270. term.clear()
  2271. if not term.isColor() or not pocket then term.setCursorPos(1, 1) error("Advanced Wireless Pocket Computer Required", 0) end
  2272. drawElement(2, 2, 1, 1, white, nil, "Initializing . . .")
  2273. if not os.getComputerLabel() then os.setComputerLabel("PocketPC.ID#" .. thisCC) end
  2274. if peripheral.isPresent("back") and peripheral.getType("back") == "modem" and peripheral.call("back", "isWireless") then
  2275.   rednet.open("back")
  2276.   netSide = "back"
  2277. else
  2278.   term.clear()
  2279.   drawElement(2, 2, 1, 1, red, nil, "No wireless")
  2280.   drawElement(2, 3, 1, 1, nil, nil, "modem detected!")
  2281.   drawElement(2, 5, 1, 1, nil, nil, "gtRemote REQUIRES")
  2282.   drawElement(2, 6, 1, 1, nil, nil, "a wireless modem.")
  2283.   term.setCursorPos(1, 9)
  2284.   return
  2285. end
  2286. runState = "List"
  2287. drawElement(2, 4, 1, 1, white, nil, "Searching for hosts . . .")
  2288. netSend("ALL", "gtrQRY", "Full")
  2289. pollTimer = os.startTimer(5)
  2290. term.clear()
  2291. drawCLI()
  2292. parallel.waitForAny(userInput, netReceive, dataPoller)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement