SocksDev

Untitled

Nov 17th, 2024
11
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 48.62 KB | Gaming | 0 0
  1. --Quarry Receiver Version 3.5.4
  2. --Made by Civilwargeeky
  3. --[[
  4. Ideas:
  5.  
  6.    
  7. ]]
  8. --[[
  9. Recent Changes:
  10.   Completely Remade!
  11. ]]
  12.  
  13. local commandHelpParagraph = [[
  14. Stop: Stops the turtle where it is
  15. Return: The turtle will return to its starting point, drop off its load, and stop
  16. Drop: Turtle will immediately go and drop its inventory
  17. Pause: Pauses the turtle
  18. Resume: Resumes paused turtles
  19. Help: This :D
  20. ]]
  21.  
  22.  
  23. --Config
  24. local doDebug = false --For testing purposes
  25. local ySizes = 3 --There are 3 different Y Screen Sizes right now
  26.  
  27. --Initializing Program-Wide Variables
  28. local expectedMessage = "Civil's Quarry" --Expected initial message
  29. local expectedFingerprint = "quarry"
  30. local replyMessage = "Turtle Quarry Receiver" --Message to respond to  handshake with
  31. local replyFingerprint = "quarryReceiver"
  32. local stopMessage = "stop"
  33. local expectedFingerprint = "quarry"
  34. local themeFolder = "quarryResources/receiverThemes/"
  35. local modemSide --User can specify a modem side, but it is not necessary
  36. local modem --This will be the table for the modem
  37. local computer --The main screen is special. It gets defined first :3
  38. local continue = true --This keeps the main while loop going
  39. --These two are used by controller in main loop
  40. local commandString = "" --This will be a command string sent to turtle. This var is stored for display
  41. local queuedMessage --If a command needs to be sent, this gets set
  42. local defaultSide
  43. local defaultCommand
  44.  
  45. local keyMap = {[57] = " ", [11] = "0", [12] = "_", [52] = "."} --This is for command string
  46.  
  47. for i=2,10 do keyMap[i] = tostring(i-1) end --Add numbers
  48. for a,b in pairs(keys) do --Add all letters from keys api
  49.   if #a == 1 then
  50.     keyMap[b] = a:upper()
  51.   end
  52. end
  53. keyMap[keys.enter] = "enter"
  54. keyMap[keys.backspace] = "backspace"
  55. keyMap[keys.space] = " "
  56. keyMap[keys.one] = "1"
  57. keyMap[keys.two] = "2"
  58. keyMap[keys.three] = "3"
  59. keyMap[keys.four] = "4"
  60. keyMap[keys.five] = "5"
  61. keyMap[keys.six] = "6"
  62. keyMap[keys.seven] = "7"
  63. keyMap[keys.eight] = "8"
  64. keyMap[keys.nine] = "9"
  65. keyMap[keys.zero] = "10"
  66.  
  67. --Generic Functions--
  68. local function debug(...)
  69.   --if doDebug then return print(...) end --Basic
  70.   if doDebug then
  71.     print("\nDEBUG: ",...)
  72.     os.pullEvent("char")
  73.   end
  74. end
  75. local function clearScreen(x,y, periph)
  76.   periph, x, y = periph or term, x or 1, y or 1
  77.   periph.clear()
  78.   periph.setCursorPos(x,y)
  79. end
  80.  
  81. local function swapKeyValue(tab)
  82.   for a,b in pairs(tab) do
  83.     tab[b] = a
  84.   end
  85.   return tab
  86. end
  87. local function copyTable(tab)
  88.   local toRet = {}
  89.   for a,b in pairs(tab) do
  90.     toRet[a] = b
  91.   end
  92.   return toRet
  93. end
  94. local function checkChannel(num)
  95.   num = tonumber(num)
  96.   if not num then return false end
  97.   if 1 <= num and num <= 65535 then
  98.     return num
  99.   end
  100.   return false
  101. end
  102. local function align(text, xDim, direction)
  103.   text = tostring(text or "None")
  104.   if #text >= xDim then return text end
  105.   for i=1, xDim-#text do
  106.     if direction == "right" then
  107.       text = " "..text
  108.     elseif direction == "left" then
  109.       text = text.." "
  110.     end
  111.   end
  112.   return text
  113. end
  114. local function alignR(text, xDim)
  115.   return align(text, xDim, "right")
  116. end
  117. local function alignL(text, xDim)
  118.   return align(text, xDim, "left")
  119. end
  120. local function center(text, xDim)
  121.   xDim = xDim or dim[1] --Temp fix
  122.   local a = (xDim-#text)/2
  123.   for i=1, a do
  124.     text = " "..text.." "
  125.   end
  126.   return text  
  127. end
  128. local function roundNegative(num) --Rounds numbers up to 0
  129.   if num >= 0 then return num else return 0 end
  130. end
  131. local function displayHelp()
  132.   print("I am help!")
  133.   print("This will be done later")
  134.   print("For now just check the forum")
  135.   print("Press any key")
  136.   os.pullEvent("key")
  137.   error("",0)
  138. end
  139.  
  140.  
  141. local function testPeripheral(periph, periphFunc)
  142.   if type(periph) ~= "table" then return false end
  143.   if type(periph[periphFunc]) ~= "function" then return false end
  144.   if periph[periphFunc]() == nil then --Expects string because the function could access nil
  145.     return false
  146.   end
  147.   return true
  148. end
  149.  
  150. local function initModem() --Sets up modem, returns true if modem exists
  151.   if not testPeripheral(modem, "isWireless") then
  152.     if peripheral.getType(modemSide or "") == "modem" then
  153.       modem = peripheral.wrap(modemSide)    
  154.       if not modem.isWireless() then --Apparently this is a thing
  155.         modem = nil
  156.         return false
  157.       end
  158.       return true
  159.     end
  160.     if peripheral.find then
  161.       modem = peripheral.find("modem", function(side, obj) return obj.isWireless() end)
  162.     end
  163.     return modem and true or false
  164.   end
  165.   return true
  166. end
  167.  
  168. --COLOR/THEME RELATED
  169. for a, b in pairs(colors) do --This is so commands color commands can be entered in one case
  170.   colors[a:lower()] = b
  171. end
  172.  
  173. local themes = {} --Loaded themes, gives each one a names
  174. local function newTheme(name)
  175.   name = name:lower() or "none"
  176.   local self = {name = name}
  177.   self.addColor = function(self, name, text, back) --Background is optional. Will not change if nil
  178.     name = name or "none"
  179.     self[name] = {text = text, background = back}
  180.     return self --Allows for chaining :)
  181.   end
  182.   themes[name] = self
  183.   return self
  184. end
  185.  
  186. local requiredColors = {"title", "subtitle", "pos", "dim", "extra", "error", "info", "inverse", "command", "help", "background"}
  187.  
  188. --This is how adding colors will work
  189. newTheme("default")
  190.   :addColor("title", colors.green, colors.gray)
  191.   :addColor("subtitle", colors.white, colors.black)
  192.   :addColor("pos", colors.green, colors.black)
  193.   :addColor("dim", colors.lightBlue, colors.black)
  194.   :addColor("extra", colors.lightGray, colors.black)
  195.   :addColor("error", colors.red, colors.white)
  196.   :addColor("info", colors.blue, colors.lightGray)
  197.   :addColor("inverse", colors.yellow, colors.lightGray)
  198.   :addColor("command", colors.lightBlue, colors.black)
  199.   :addColor("help", colors.red, colors.white)
  200.   :addColor("background", colors.white, colors.black)
  201.  
  202. newTheme("random")
  203.   :addColor("title", colors.pink, colors.blue)
  204.   :addColor("subtitle", colors.black, colors.white)
  205.   :addColor("pos", colors.green, colors.black)
  206.   :addColor("dim", colors.lightBlue, colors.black)
  207.   :addColor("extra", colors.lightGray, colors.lightBlue)
  208.   :addColor("error", colors.white, colors.yellow)
  209.   :addColor("info", colors.blue, colors.lightGray)
  210.   :addColor("inverse", colors.yellow, colors.lightGray)
  211.   :addColor("command", colors.green, colors.lightGray)
  212.   :addColor("help", colors.white, colors.yellow)
  213.   :addColor("background", colors.white, colors.red)
  214.  
  215. --If you modify a theme a bunch and want to save it
  216. local function saveTheme(theme, fileName)
  217.   if not theme or not type(fileName) == "string" then return false end
  218.   local file = fs.open(fileName,"w")
  219.   if not file then return false end
  220.   file.writeLine(fileName)
  221.   for a,b in pairs(theme) do
  222.     if type(b) == "table" then --If it contains color objects
  223.       file.writeLine(a.." "..tostring(b.text).." "..tostring(b.background))
  224.     end
  225.   end
  226.   file.close()
  227.   return true
  228. end
  229.  
  230.  
  231. --==SCREEN CLASS FUNCTIONS==
  232. local screenClass = {} --This is the class for all monitor/screen objects
  233. screenClass.screens = {} --A simply numbered list of screens
  234. screenClass.sides = {} --A mapping of screens by their side attached
  235. screenClass.channels = {} --A mapping of receiving channels that have screens attached. Used for the receiver part
  236. screenClass.sizes = {{7,18,29,39,50}, {5,12,19} , computer = {51, 19}, turtle = {39,13}, pocket = {26,20}}
  237.  
  238. screenClass.setTextColor = function(self, color) --Accepts raw color
  239.   if color and self.term.isColor() then
  240.     self.textColor = color
  241.     self.term.setTextColor(color)
  242.     return true
  243.   end
  244.   return false
  245. end
  246. screenClass.setBackgroundColor = function(self, color) --Accepts raw color
  247.   if color and self.term.isColor() then
  248.     self.backgroundColor = color
  249.     self.term.setBackgroundColor(color)
  250.     return true
  251.   end
  252.   return false
  253. end
  254. screenClass.setColor = function(self, color) --Wrapper, accepts themecolor objects
  255.   if type(color) ~= "table" then error("Set color received a non-table",2) end
  256.   return self:setTextColor(color.text) and self:setBackgroundColor(color.background)
  257. end
  258.  
  259. screenClass.themeName = "default" --Setting super for fallback
  260. screenClass.theme = themes.default
  261.  
  262.  
  263. screenClass.new = function(side, receive, themeFile)
  264.   local self = {}
  265.   setmetatable(self, {__index = screenClass}) --Establish Hierarchy
  266.   self.side = side
  267.   if side == "computer" then
  268.     self.term = term
  269.   else
  270.     self.term = peripheral.wrap(side)
  271.     if not (self.term and peripheral.getType(side) == "monitor") then --Don't create an object if it doesn't exist
  272.       if doDebug then
  273.         error("No monitor on side "..tostring(side))
  274.       end
  275.       self = nil --Save memory?
  276.       return false
  277.     end
  278.   end
  279.  
  280.   --Channels and ids
  281.   self.receive = tonumber(receive) --Receive Channel
  282.   self.send = nil --Reply Channel, obtained in handshake
  283.   self.id = #screenClass.screens+1
  284.   --Colors
  285.   self.themeName = nil --Will be set by setTheme
  286.   self.theme = nil
  287.   self.isColor = self.term.isColor() --Just for convenience
  288.   --Other Screen Properties
  289.   self.dim = {self.term.getSize()} --Raw dimensions
  290.   --Initializations
  291.   self.isDone = false --Flag for when the turtle is done transmitting
  292.   self.size = {} --Screen Size, assigned in setSize
  293.   self.textColor = colors.white --Just placeholders until theme is loaded and run
  294.   self.backColor = colors.black
  295.   self.toPrint = {}
  296.   self.isComputer = false
  297.   self.isTurtle = false
  298.   self.isPocket = false
  299.   self.acceptsInput = false
  300.   self.legacy = false --Whether it expects tables or strings
  301.   self.rec = { --Initial values for all displayed numbers
  302.     label = "Quarry Bot",
  303.     id = 1,
  304.     percent = 0,
  305.     relxPos = 0,
  306.     zPos = 0,
  307.     layersDone = 0,
  308.     x = 0,
  309.     z = 0,
  310.     layers = 0,
  311.     openSlots = 0,
  312.     mined = 0,
  313.     moved = 0,
  314.     chestFull = false,
  315.     isAtChest = false,
  316.     isGoingToNextLayer = false,
  317.     foundBedrock = false,
  318.     fuel = 0,
  319.     volume = 0,
  320.     distance = 0,
  321.     yPos = 0
  322.     --Maybe add in some things like if going to then add a field
  323.   }
  324.  
  325.   screenClass.screens[self.id] = self
  326.   screenClass.sides[self.side] = self
  327.   if self.receive then
  328.     modem.open(self.receive) --Modem should be defined by the time anything is open
  329.     screenClass.channels[self.receive] = self --If anyone ever asked, you could have multiple screens per channel, but its silly if no one ever needs it
  330.   end
  331.   self:setSize() --Finish Initialization
  332.   self:setTheme(themeFile)
  333.   return self
  334. end
  335.  
  336. screenClass.remove = function(tab) --Cleanup function
  337.   if type(tab) == "number" then --Expects table, can take id (for no apparent reason)
  338.     tab = screenClass.screens[tab]
  339.   end
  340.   if tab.side == "REMOVED" then return end
  341.   if tab.side == "computer" then error("Tried removing computer screen",2) end --This should never happen
  342.   tab:reset() --Clear screen
  343.   tab:say("Removed", tab.theme.info, 1) --Let everyone know whats up
  344.   screenClass.screens[tab.id] = {side = "REMOVED"} --Not nil because screw up len()
  345.   screenClass.sides[tab.side] = nil
  346.   screenClass.channels[tab.receive] = nil
  347.   if modem and modem.isOpen(tab.receive) then
  348.     modem.close(tab.receive)
  349.   end
  350. end
  351.  
  352. --Init Functions
  353. screenClass.setSize = function(self) --Sets screen size
  354.   if self.side ~= "computer" and not self.term then self.term = peripheral.wrap(self.side) end
  355.   if not self.term.getSize() then --If peripheral is having problems/not there. Don't go further than term, otherwise index nil (maybe?)
  356.     debug("There is no term...")
  357.     self.updateDisplay = function() end --Do nothing on screen update, overrides class
  358.     return true
  359.   elseif not self.receive then
  360.     self:setBrokenDisplay() --This will prompt user to set channel
  361.   elseif self.send then --This allows for class inheritance
  362.     self:init() --In case objects have special updateDisplay methods --Remove function in case it exists, defaults to super
  363.   else --If the screen needs to have a handshake display
  364.     self:setHandshakeDisplay()
  365.   end
  366.   self.dim = { self.term.getSize()}
  367.   local tab = screenClass.sizes
  368.   for a=1, 2 do --Want x and y dim
  369.     for b=1, #tab[a] do --Go through all normal sizes, x and y individually
  370.       if tab[a][b] <= self.dim[a] then --This will set size higher until false
  371.         self.size[a] = b
  372.       end
  373.     end
  374.   end
  375.   local function isThing(toCheck, thing) --E.G. isThing(self.dim,"computer")
  376.     return toCheck[1] == tab[thing][1] and toCheck[2] == tab[thing][2]
  377.   end
  378.   self.isComputer = isThing(self.dim, "computer")
  379.   self.isTurtle = isThing(self.dim, "turtle")
  380.   self.isPocket = isThing(self.dim, "pocket")
  381.   self.acceptsInput = self.isComputer or self.isTurtle or self.isPocket
  382.   return self
  383. end
  384.  
  385. screenClass.setTheme = function(self, themeName, stopReset)
  386.   if not themes[themeName] then --If we don't have it already, try to load it
  387.     local fileName = themeName or ".." --.. returns false and I don't think you can name a file this
  388.     if fs.exists(themeFolder) then fileName = themeFolder..fileName end
  389.     if fs.exists(fileName) then
  390.       debug("Loading theme: ",fileName)
  391.       local file = fs.open(fileName, "r")
  392.       if not file then debug("Could not load theme '",themeName,"' file not found") end
  393.       local addedTheme = newTheme(file.readLine() or "newTheme") --Initializes the new theme
  394.       for line in function() return file.readLine() end do --Go through all the color lines (hopefully not the first one. Requires testing)
  395.         local args = {}
  396.         for word in line:gmatch("%S+") do
  397.           table.insert(args,word)
  398.         end
  399.         addedTheme:addColor(args[1]:match("%a+") or "nothing", tonumber(args[2]) or colors[args[2]], tonumber(args[3]) or colors[args[3]]) --"nothing" will never get used, so its just lazy error prevention
  400.       end
  401.       file.close()
  402.       local flag = true --Make sure a theme has all required elements
  403.       for a,b in ipairs(requiredColors) do
  404.         if not addedTheme[b] then
  405.           flag = false
  406.           debug("Theme is missing color '",b,"'")
  407.         end
  408.       end
  409.       if not flag then
  410.         themes[addedTheme.name] = nil
  411.         debug("Failed to load theme")
  412.         return false
  413.       end
  414.       self.themeName = themeName:lower() --We can now set our themeName to the fileName
  415.     else
  416.       --Resets theme to super
  417.       if not stopReset then --This exists so its possible to set default theme without breaking world
  418.         self.themeName = nil
  419.         self.theme = nil
  420.       end
  421.       return false
  422.     end
  423.    else
  424.     self.themeName = themeName:lower()
  425.    end
  426.    self.theme = themes[self.themeName] --Now the theme is loaded or the function doesn't get here
  427.    return true
  428. end
  429.  
  430. --Adds text to the screen buffer
  431. screenClass.tryAddRaw = function(self, line, text, color, ...) --This will try to add text if Y dimension is a certain size
  432.   local doAdd = {...} --booleans for small, medium, and large
  433.   if type(text) ~= "string" then error("tryAddRaw got "..type(text)..", expected string",2) end
  434.   text = text or "NIL"
  435.   if type(color) ~= "table" then error("tryAddRaw did not get a color",2) end
  436.   --color = color or {text = colors.white}
  437.   for i=1, ySizes do --As of now there are 3 Y sizes
  438.     local test = doAdd[i]
  439.     if test == nil then test = doAdd[#doAdd] end --Set it to the last known setting if doesn't exist
  440.     if test and self.size[2] == i then --If should add this text for this screen size and the monitor is this size
  441.       if #text <= self.dim[1] then
  442.         self.toPrint[line] = {text = text, color = color}
  443.         return true
  444.       else
  445.         debug("Tried adding ",text," on line ",line," but was too long")
  446.       end
  447.     end
  448.   end
  449.   return false
  450. end
  451. screenClass.tryAdd = function(self, text, color,...) --Just a wrapper
  452.   return self:tryAddRaw(#self.toPrint+1, text, color, ...)
  453. end
  454. screenClass.tryAddC = function(self, text, color, ...) --Centered text
  455.   return self:tryAdd(center(text, self.dim[1]), color, ...)
  456. end
  457.  
  458. screenClass.reset = function(self,color)
  459.   color = color or self.theme.background
  460.   self:setColor(color)
  461.   self.term.clear()
  462.   self.term.setCursorPos(1,1)
  463. end
  464. screenClass.say = function(self, text, color, line)
  465.   local currColor = self.backgroundColor
  466.   color = color or debug("Printing ",text," but had no themeColor: ",self.theme.name) or {} --Set default for nice error, alert that errors occur
  467.   self:setColor(color)
  468.   local line = line or ({self.term.getCursorPos()})[2] or self:setSize() or 1 --If current yPos not found, sets screen size and moves cursor to 1
  469.   if doDebug and #text > self.dim[1] then error("Tried printing: '"..text.."', but was too big") end
  470.   self.term.setCursorPos(1,line)
  471.   for i=1, self.dim[1]-#text do --This is so the whole line's background gets filled.
  472.     text = text.." "
  473.   end
  474.   self.term.write(text)
  475.   self.term.setCursorPos(1, line+1)
  476. end
  477. screenClass.pushScreenUpdates = function(self)
  478.   for i=1, self.dim[2] do
  479.     local tab = self.toPrint[i]
  480.     if tab then
  481.       self:say(tab.text, tab.color, i)
  482.     end
  483.   end
  484.   self.term.setCursorPos(1,self.dim[2]) --So we can see errors
  485. end
  486.  
  487. screenClass.updateNormal = function(self) --This is the normal updateDisplay function
  488.   local str = tostring
  489.   self.toPrint = {} --Reset table
  490.   local message, theme = self.rec, self.theme
  491.  
  492.   if not self.isDone then --Normally
  493.     if self.size[1] == 1 then --Small Width Monitor
  494.       if not self:tryAdd(message.label, theme.title, false, false, true) then --This will be a title, basically
  495.         self:tryAdd("Quarry!", theme.title, false, false, true)
  496.       end
  497.      
  498.       self:tryAdd("-Fuel-", theme.subtitle , false, true, true)
  499.       if not self:tryAdd(str(message.fuel), theme.extra, false, true, true) then --The fuel number may be bigger than the screen
  500.         self:tryAdd("A lot", theme.extra, false, true, true)
  501.       end
  502.      
  503.       self:tryAdd("--%%%--", theme.subtitle, false, true, true)
  504.       self:tryAdd(alignR(str(message.percent).."%", 7), theme.pos , false, true, true) --This can be an example. Print (receivedMessage).percent in blue on all different screen sizes
  505.       self:tryAdd(center(str(message.percent).."%", self.dim[1]), theme.pos, true, false) --I want it to be centered on 1x1
  506.      
  507.       self:tryAdd("--Pos--", theme.subtitle, false, true, true)
  508.       self:tryAdd("X:"..alignR(str(message.relxPos), 5), theme.pos, true)
  509.       self:tryAdd("Z:"..alignR(str(message.zPos), 5), theme.pos , true)
  510.       self:tryAdd("Y:"..alignR(str(message.layersDone), 5), theme.pos , true)
  511.      
  512.       if not self:tryAdd(str(message.x).."x"..str(message.z).."x"..str(message.layers), theme.dim , true, false) then --If you can't display the y, then don't
  513.         self:tryAdd(str(message.x).."x"..str(message.z), theme.dim , true, false)
  514.       end
  515.       self:tryAdd("--Dim--", theme.subtitle, false, true, true)
  516.       self:tryAdd("X:"..alignR(str(message.x), 5), theme.dim, false, true, true)
  517.       self:tryAdd("Z:"..alignR(str(message.z), 5), theme.dim, false, true, true)
  518.       self:tryAdd("Y:"..alignR(str(message.layers), 5), theme.dim, false, true, true)
  519.      
  520.       self:tryAdd("-Extra-", theme.subtitle, false, false, true)
  521.       self:tryAdd(alignR(textutils.formatTime(os.time()):gsub(" ","").."", 7), theme.extra, false, false, true) --Adds the current time, formatted, without spaces.
  522.       self:tryAdd("Open:"..alignR(str(message.openSlots),2), theme.extra, false, false, true)
  523.       self:tryAdd("Dug"..alignR(str(message.mined), 4), theme.extra, false, false, true)
  524.       self:tryAdd("Mvd"..alignR(str(message.moved), 4), theme.extra, false, false, true)
  525.       if message.chestFull then
  526.         self:tryAdd("ChstFll", theme.error, false, false, true)
  527.       end
  528.      
  529.     end
  530.     if self.size[1] == 2 then --Medium Monitor
  531.       if not self:tryAdd(message.label, theme.title, false, false, true) then --This will be a title, basically
  532.         self:tryAdd("Quarry!", theme.title, false, false, true)
  533.       end
  534.      
  535.       self:tryAdd("-------Fuel-------", theme.subtitle , false, true, true)
  536.       if not self:tryAdd(str(message.fuel), theme.extra, false, true, true) then --The fuel number may be bigger than the screen
  537.         self.toPrint[#self.toPrint] = nil
  538.         self:tryAdd("A lot", theme.extra, false, true, true)
  539.       end
  540.      
  541.       self:tryAdd(str(message.percent).."% Complete", theme.pos , true) --This can be an example. Print (receivedMessage).percent in blue on all different screen sizes
  542.      
  543.       self:tryAdd("-------Pos--------", theme.subtitle, false, true, true)
  544.       self:tryAdd("X Coordinate:"..alignR(str(message.relxPos), 5), theme.pos, true)
  545.       self:tryAdd("Z Coordinate:"..alignR(str(message.zPos), 5), theme.pos , true)
  546.       self:tryAdd("On Layer:"..alignR(str(message.layersDone), 9), theme.pos , true)
  547.      
  548.       if not self:tryAdd("Size: "..str(message.x).."x"..str(message.z).."x"..str(message.layers), theme.dim , true, false) then --This is already here... I may as well give an alternative for those people with 1000^3quarries
  549.         self:tryAdd(str(message.x).."x"..str(message.z).."x"..str(message.layers), theme.dim , true, false)
  550.       end
  551.       self:tryAdd("-------Dim--------", theme.subtitle, false, true, true)
  552.       self:tryAdd("Total X:"..alignR(str(message.x), 10), theme.dim, false, true, true)
  553.       self:tryAdd("Total Z:"..alignR(str(message.z), 10), theme.dim, false, true, true)
  554.       self:tryAdd("Total Layers:"..alignR(str(message.layers), 5), theme.dim, false, true, true)
  555.       self:tryAdd("Volume"..alignR(str(message.volume),12), theme.dim, false, false, true)
  556.      
  557.       self:tryAdd("------Extras------", theme.subtitle, false, false, true)
  558.       self:tryAdd("Time: "..alignR(textutils.formatTime(os.time()):gsub(" ","").."", 12), theme.extra, false, false, true) --Adds the current time, formatted, without spaces.
  559.       self:tryAdd("Used Slots:"..alignR(str(16-message.openSlots),7), theme.extra, false, false, true)
  560.       self:tryAdd("Blocks Mined:"..alignR(str(message.mined), 5), theme.extra, false, false, true)
  561.       self:tryAdd("Spaces Moved:"..alignR(str(message.moved), 5), theme.extra, false, false, true)
  562.       if message.chestFull then
  563.         self:tryAdd("Chest Full, Fix It", theme.error, false, true, true)
  564.       end
  565.     end
  566.     if self.size[1] >= 3 then --Large or larger screens
  567.       if not self:tryAdd(message.label..alignR(" Turtle #"..str(message.id),self.dim[1]-#message.label), theme.title, true) then
  568.         self:tryAdd("Your turtle's name is long...", theme.title, true)
  569.       end
  570.       self:tryAdd("Fuel: "..alignR(str(message.fuel),self.dim[1]-6), theme.extra, true)
  571.      
  572.       self:tryAdd("Percentage Done: "..alignR(str(message.percent).."%",self.dim[1]-17), theme.pos, true)
  573.      
  574.       local var1 = math.max(#str(message.x), #str(message.z), #str(message.layers))
  575.       local var2 = (self.dim[1]-6-var1+3)/3
  576.       self:tryAdd("Pos: "..alignR(" X:"..alignR(str(message.relxPos),var1),var2)..alignR(" Z:"..alignR(str(message.zPos),var1),var2)..alignR(" Y:"..alignR(str(message.layersDone),var1),var2), theme.pos, true)
  577.       self:tryAdd("Size:"..alignR(" X:"..alignR(str(message.x),var1),var2)..alignR(" Z:"..alignR(str(message.z),var1),var2)..alignR(" Y:"..alignR(str(message.layers),var1),var2), theme.dim, true)
  578.       self:tryAdd("Volume: "..str(message.volume), theme.dim, false, true, true)
  579.       self:tryAdd("",{}, false, false, true)
  580.       self:tryAdd(center("____---- EXTRAS ----____",self.dim[1]), theme.subtitle, false, false, true)
  581.       self:tryAdd(center("Time:"..alignR(textutils.formatTime(os.time()),8), self.dim[1]), theme.extra, false, true, true)
  582.       self:tryAdd(center("Current Day: "..str(os.day()), self.dim[1]), theme.extra, false, false, true)
  583.       self:tryAdd("Used Inventory Slots: "..alignR(str(16-message.openSlots),self.dim[1]-22), theme.extra, false, true, true)
  584.       self:tryAdd("Blocks Mined: "..alignR(str(message.mined),self.dim[1]-14), theme.extra, false, true, true)
  585.       self:tryAdd("Blocks Moved: "..alignR(str(message.moved),self.dim[1]-14), theme.extra, false, true, true)
  586.       self:tryAdd("Distance to Turtle: "..alignR(str(message.distance), self.dim[1]-20), theme.extra, false, false, true)
  587.       self:tryAdd("Actual Y Pos (Not Layer): "..alignR(str(message.yPos), self.dim[1]-26), theme.extra, false, false, true)
  588.      
  589.       if message.chestFull then
  590.         self:tryAdd("Dropoff is Full, Please Fix", theme.error, false, true, true)
  591.       end
  592.       if message.foundBedrock then
  593.         self:tryAdd("Found Bedrock! Please Check!!", theme.error, false, true, true)
  594.       end
  595.       if message.isAtChest then
  596.         self:tryAdd("Turtle is at home chest", theme.info, false, true, true)
  597.       end
  598.       if message.isGoingToNextLayer then
  599.         self:tryAdd("Turtle is going to next layer", theme.info, false, true, true)
  600.       end
  601.     end
  602.   else --If is done
  603.     if self.size[1] == 1 then --Special case for small monitors
  604.       self:tryAdd("Done", theme.title, true)
  605.       self:tryAdd("Dug"..alignR(str(message.mined),4), theme.pos, true)
  606.       self:tryAdd("Fuel"..alignR(str(message.fuel),3), theme.pos, true)
  607.       self:tryAdd("-------", theme.subtitle, false,true,true)
  608.       self:tryAdd("Turtle", theme.subtitle, false, true, true)
  609.       self:tryAdd(center("is", self.dim[1]), theme.subtitle, false, true, true)
  610.       self:tryAdd(center("Done!", self.dim[1]), theme.subtitle, false, true, true)
  611.     else
  612.       self:tryAdd("Done!", theme.title, true)
  613.       self:tryAdd("Blocks Dug: "..str(message.mined), theme.inverse, true)
  614.       self:tryAdd("Cobble Dug: "..str(message.cobble), theme.pos, false, true, true)
  615.       self:tryAdd("Fuel Dug: "..str(message.fuelblocks), theme.pos, false, true, true)
  616.       self:tryAdd("Others Dug: "..str(message.other), theme.pos, false, true, true)
  617.       self:tryAdd("Curr Fuel: "..str(message.fuel), theme.inverse, true)
  618.     end
  619.   end
  620. end
  621. screenClass.updateHandshake = function(self)
  622.   self.toPrint = {}
  623.   local half = math.ceil(self.dim[2]/2)
  624.   if self.size[1] == 1 then --Not relying on the parameter system because less calls
  625.     self:tryAddRaw(half-2, "Waiting", self.theme.error, true)
  626.     self:tryAddRaw(half-1, "For Msg", self.theme.error, true)
  627.     self:tryAddRaw(half, "On Chnl", self.theme.error, true)
  628.     self:tryAddRaw(half+1, tostring(self.receive), self.theme.error, true)
  629.   else
  630.     local str = "for"
  631.     if self.size[1] == 2 then str = "4" end--Just a small grammar change
  632.     self:tryAddRaw(half-2, "", self.theme.error, true) --Filler
  633.     self:tryAddRaw(half-1, center("Waiting "..str.." Message", self.dim[1]), self.theme.error, true)
  634.     self:tryAddRaw(half, center("On Channel "..tostring(self.receive), self.dim[1]), self.theme.error, true)
  635.     self:tryAddRaw(half+1, "",self.theme.error, true)
  636.   end
  637. end
  638. screenClass.updateBroken = function(self) --If screen needs channel
  639.   self.toPrint = {}
  640.   if self.size[1] == 1 then
  641.     self:tryAddC("No Rec", self.theme.pos, false, true, true)
  642.     self:tryAddC("Channel", self.theme.pos, false, true, true)
  643.     self:tryAddC("-------", self.theme.title, false, true, true)
  644.     self:tryAddC("On Comp", self.theme.info, true)
  645.     self:tryAddC("Type:", self.theme.info, true)
  646.     self:tryAddC("RECEIVE", self.theme.command, true)
  647.     if not self:tryAddC(self.side:upper(), self.theme.command, true) then --If we can't print the full side
  648.       self:tryAddC("[side]",self.theme.command, true)
  649.     end
  650.     self:tryAddC("[Chnl]", self.theme.command, true)
  651.   else
  652.     self:tryAddC("No receiving", self.theme.pos, false, true, true)
  653.     self:tryAddC("channel for", self.theme.pos, false, true, true)
  654.     self:tryAddC("this screen", self.theme.pos, false, true, true)
  655.     self:tryAddC("-----------------", self.theme.title, false, true, true)
  656.     self:tryAddC("On main computer,", self.theme.info, true)
  657.     self:tryAddC("Type:", self.theme.info, true)
  658.     self:tryAdd("", self.theme.command, false, true, true)
  659.     self:tryAddC('"""', self.theme.command, false, true, true)
  660.     self:tryAddC("RECEIVE", self.theme.command, true)
  661.     if not self:tryAddC(self.side:upper(), self.theme.command, true) then --If we can't print the full side
  662.       self:tryAddC("[side]",self.theme.command, true)
  663.     end
  664.     self:tryAddC("[desired channel]", self.theme.command, true)
  665.     self:tryAddC('"""', self.theme.command, false, true, true)
  666.   end
  667. end
  668.  
  669. screenClass.updateDisplay = screenClass.updateNormal --Update screen method is normally this one
  670.  
  671. --Misc
  672. screenClass.init = function(self) --Currently used by computer screen to replace its original method
  673.   self.updateDisplay = self.updateNormal --This defaults to super if doesn't exist
  674. end
  675. screenClass.setHandshakeDisplay = function(self)
  676.   self.updateDisplay = self.updateHandshake --Sets update to handshake version, defaults to super if doesn't exist
  677. end
  678. screenClass.setBrokenDisplay = function(self)
  679.   self.updateDisplay = self.updateBroken
  680. end
  681.  
  682.  
  683. local function wrapPrompt(prefix, str, dim) --Used to wrap the commandString
  684.   return prefix..str:sub(roundNegative(#str+#prefix-computer.dim[1]+2), -1).."_" --it is str + 2 because we add in the "_"
  685. end
  686.  
  687. local function updateAllScreens()
  688.   for a, b in pairs(screenClass.sides) do
  689.     b:updateDisplay()
  690.     b:reset()
  691.     b:pushScreenUpdates()
  692.   end
  693. end
  694. --Rednet
  695. local function newMessageID()
  696.   return math.random(1,2000000000) --1 through 2 billion. Good enough solution
  697. end
  698. local function transmit(send, receive, message, legacy, fingerprint)
  699.   fingerprint = fingerprint or replyFingerprint
  700.   if legacy then
  701.     modem.transmit(send, receive, message)
  702.   else
  703.     modem.transmit(send, receive, {message = message, id = newMessageID(), fingerprint = fingerprint})
  704.   end
  705. end
  706.  
  707. --==SET UP==
  708. clearScreen()
  709. print("Welcome to Quarry Receiver!")
  710. sleep(1)
  711.  
  712. while not initModem() do
  713.   clearScreen()
  714.   print("No modem is connected, please attach one")
  715.   if not peripheral.find then
  716.     print("What side was that on?")
  717.     modemSide = read()
  718.   else
  719.     os.pullEvent("peripheral")
  720.   end
  721. end
  722. debug("Modem successfully connected!")
  723.  
  724. --==ARGUMENTS==
  725.  
  726. --[[
  727. Parameters:
  728.   -help/-?/help/?
  729.   -receiveChannel [channel] --For only the main screen
  730.   -theme --Sets a default theme
  731.   -screen [side] [channel] [theme]
  732.   -station
  733.   -auto --Prompts for all sides, or you can supply a list of receive channels for random assignment!
  734.   -colorEditor
  735. ]]
  736.  
  737. --tArgs and peripheral list init
  738. local tArgs = {...}
  739. local parameters = {} --Each command is stored with arguments
  740. local parameterIndex = 0 --So we can add new commands to the right table
  741. for a,b in ipairs(tArgs) do
  742.   val = b:lower()
  743.   if val == "help" or val == "-help" or val == "?" or val == "-?" then
  744.     displayHelp() --To make
  745.     error("The End of Help",0)
  746.   end
  747.   if val:match("^%-") then
  748.     parameterIndex = parameterIndex + 1
  749.     parameters[parameterIndex] = {val:sub(2)} --Starts a chain with the command. Can be unpacked later
  750.     parameters[val:sub(2)] = {} --Needed for force/before/after parameters
  751.   elseif parameterIndex ~= 0 then
  752.     table.insert(parameters[parameterIndex], b) --b because arguments should be case sensitive for filenames
  753.     table.insert(parameters[parameters[parameterIndex][1]], b) --Needed for force/after parameters
  754.   end
  755. end
  756.  
  757. for i=1,#parameters do
  758.   debug("Parameter: ",parameters[i][1])
  759. end
  760.  
  761. --Options before screen loads
  762. if parameters.theme then
  763.   screenClass:setTheme(parameters.theme[1])
  764. end
  765.  
  766. --Init Computer Screen Object (was defined at top)
  767. computer = screenClass.new("computer", parameters.receivechannel and parameters.receivechannel[1])--This sets channel, checking if parameter exists
  768.  
  769.  
  770. computer.displayCommand = function(self)
  771.   local sideString = ((defaultSide and " (") or "")..(defaultSide or "")..((defaultSide and ")") or "")
  772.   if self.size == 1 then
  773.     self:tryAddRaw(self.dim[2], wrapPrompt("Cmd"..sideString:sub(2,-2)..": ", commandString, self.dim[1]), self.theme.command, true)
  774.   else
  775.     self:tryAddRaw(self.dim[2], wrapPrompt("Command"..sideString..": ",commandString, self.dim[1]), self.theme.command, true) --This displays the last part of a string.
  776.   end
  777. end
  778. --Technically, you could have any screen be the station, but oh well.
  779. --Initializing the computer screen
  780. if parameters.station then --This will set the screen update to display stats on all other monitors. For now it does little
  781.   if computer.receive then
  782.     screenClass.receiveChannels[computer.receive] = nil --Because it doesn't have a channel
  783.   end
  784.   computer.receive = nil --So it doesn't receive messages
  785.   computer.send = nil
  786.   computer.isStation = true --For updating
  787.    
  788.   computer.updateNormal = function(self)--This gets set in setSize
  789.     self.toPrint = {}
  790.     local part = math.floor(self.dim[1]/4)-1
  791.     self:tryAdd(alignL(" ID",part).."| "..alignL("Side",part).."| "..alignL("Channel",part).."| "..alignL("Theme",part), self.theme.title, false, true, true) --Headings
  792.     local line = ""
  793.     for i=1, self.dim[1] do line = line.."-" end
  794.     self:tryAdd(line, self.theme.title, false, true, true)
  795.     for a,b in ipairs(screenClass.screens) do
  796.       self:tryAdd(" "..alignL(b.id,part-1).."| "..alignL(b.side,part).."| "..alignL(b.receive, part).."| "..alignL(b.theme.name,part), self.theme.info, false, true, true) --Prints info about all screens
  797.     end
  798.     self:displayCommand()
  799.   end
  800.   computer.setHandshakeDisplay = computer.init --Handshake is same as regular
  801.   computer.setBrokenDisplay = computer.init
  802. elseif parameters.coloreditor then
  803.  
  804.   if computer.receive then --This part copied from above
  805.     screenClass.receiveChannels[computer.receive] = nil --Because it doesn't have a channel
  806.   end
  807.   computer.receive = nil --So it doesn't receive messages
  808.   computer.send = nil
  809.   computer.isStation = true --So we can't assign a channel
  810.  
  811.   computer.updateNormal = function(self) --This is only for editing colors
  812.     self.toPrint = {}
  813.     for a,b in pairs(self.theme) do
  814.       if type(b) == "table" then
  815.         self:tryAdd(a, b, true)
  816.       end
  817.     end
  818.     self:displayCommand()
  819.   end
  820.   computer.updateHandshake = computer.updateNormal
  821.   computer.updateBroken = computer.updateNormal
  822. else --If computer is a regular screen
  823.   computer.updateNormal = function(self)
  824.     screenClass.updateDisplay(self)
  825.     computer:displayCommand()
  826.   end
  827.   computer.updateHandshake = function(self) --Not in setHandshake because that func checks object updateHandshake
  828.     screenClass.updateHandshake(self)
  829.     computer:displayCommand()
  830.   end
  831.   computer.updateBroken = function(self)
  832.     screenClass.updateBroken(self)
  833.     computer:displayCommand()
  834.   end
  835. end
  836. computer:setSize() --Update changes made to display functions
  837.  
  838.  
  839. for i=1, #parameters do --Do actions for parameters that can be used multiple times
  840.   local command, args = parameters[i][1], parameters[i] --For ease
  841.   if command == "screen" then
  842.     local a = screenClass.new(args[2], args[3], args[4])
  843.     debug(type(a))
  844.   end
  845.  
  846. end
  847.  
  848. for a,b in pairs(screenClass.sides) do debug(a) end
  849.  
  850. local function autoDetect(channels)
  851.   if type(channels) ~= "table" then channels = {} end
  852.   local tab = peripheral.getNames()
  853.   local index = 1
  854.   for i=1, #tab do
  855.     if peripheral.getType(tab[i]) == "monitor" and not screenClass.sides[tab[i]] then
  856.       screenClass.new(tab[i], channels[index]) --You can specify a list of channels in "auto" parameter
  857.       index = index+1
  858.     end
  859.   end
  860. end
  861. if parameters.auto then autoDetect(parameters.auto) end
  862.  
  863.  
  864. --==FINAL CHECKS==
  865.  
  866. --Updating all screen for first time and making sure channels are open
  867. for a, b in pairs(screenClass.sides) do
  868.   if b.receive then --Because may not have channel
  869.     if not modem.isOpen(b.receive) then modem.open(b.receive) end
  870.   end
  871.   b:updateDisplay()--Finish initialization process
  872.   b:reset()
  873.   b:pushScreenUpdates()
  874. end
  875.  
  876. --Handshake will be handled in main loop
  877.  
  878. --[[Workflow
  879.   Wait for events
  880.   modem_message
  881.     if valid channel and valid message, update appropriate screen
  882.   key
  883.     if any letter, add to command string if room.
  884.     if enter key
  885.       if valid self command, execute command. Commands:
  886.         command [side] [command] --If only one screen, then don't need channel. Send a command to a turtle
  887.         screen [side] [channel] [theme] --Links a new screen to use.
  888.         remove [side] --Removes a screen
  889.         theme [themeName] --Sets the default theme
  890.         theme [side] [themeName] --Changes this screen's theme
  891.         savetheme [new name] [themeName]
  892.         color [side/theme] [colorName] [textColor] [backgroundColor]
  893.         side [side] --Sets a default side, added to prompts
  894.         set [string] --Sets a default command, added to display immediately
  895.         receive [side] [newChannel] --Changes the channel of the selected screen
  896.         send [side] [newChannel]
  897.         auto --Automatically adds screens not connected
  898.         exit/quit/end
  899.   peripheral_detach
  900.     check what was lost, if modem, set to nil. If screen side, do screen:setSize()
  901.   peripheral
  902.     check if screen side already added
  903.       reset screen size
  904.   monitor_resize
  905.     resize proper screen
  906.   monitor_touch
  907.     if screen already added
  908.       select screen on main computer
  909.     else
  910.       add screen
  911.  
  912. ]]
  913.  
  914. --Modes: 1 - Sided, 2 - Not Sided, 3 - Both sided and not
  915. local validCommands = {command = 1, screen = 2, remove = 1, theme = 3, exit = 2, quit = 2, ["end"] = 2, color = 3, side = 2, set = 2, receive = 1, send = 1, savetheme = 2, auto = 2}
  916. while continue do
  917.   local event, par1, par2, par3, par4, par5 = os.pullEvent()
  918.   ----MESSAGE HANDLING----
  919.   if event == "modem_message" and screenClass.channels[par2] then --If we got a message for a screen that exists
  920.     local screen = screenClass.channels[par2] --For convenience
  921.     if not screen.send then --This is the handshake
  922.       debug("\nChecking handshake. Received: ",par4)
  923.       local flag = false
  924.       if par4 == expectedMessage then
  925.         screen.legacy = true --Accepts serialized tables
  926.         flag = true
  927.       elseif type(par4) == "table" and par4.message == expectedMessage and par4.fingerprint == expectedFingerprint then
  928.         screen.legacy = false
  929.         flag = true
  930.       end
  931.      
  932.       if flag then
  933.         debug("Screen ",screen.side," received a handshake")
  934.         screen.send = par3
  935.         screen:setSize() --Resets update method to proper since channel is set
  936.         debug("Sending back on ",screen.send)
  937.         transmit(screen.send,screen.receive, replyMessage, screen.legacy)
  938.       end
  939.    
  940.     else --Everything else is for regular messages
  941.      
  942.       local rec
  943.       if screen.legacy then --We expect strings here
  944.         if type(par4) == "string" then --Otherwise its not ours
  945.           if par4 == "stop" then --This is the stop message. All other messages will be ending ones
  946.             screen.isDone = true
  947.           elseif par4 == expectedMessage then --We support dropping in mid-run
  948.             debug("Screen ",screen.side," received mid-run handshake")
  949.             transmit(screen.send,screen.receive, replyMessage, screen.legacy)
  950.           elseif textutils.unserialize(par4) then
  951.             rec = textutils.unserialize(par4)
  952.             rec.distance = par5
  953.           end
  954.         end
  955.       elseif type(par4) == "table" and par4.fingerprint == expectedFingerprint then --Otherwise, we check if it is valid message
  956.        
  957.         if type(par4.message) == "table" then
  958.           rec = par4.message
  959.           if not par4.distance then --This is cool because it can add distances from the repeaters
  960.             rec.distance = par5
  961.           else
  962.             rec.distance = par4.distance + par5
  963.           end
  964.           if rec.isDone then
  965.             screen.isDone = true
  966.           end
  967.         elseif par4.message == expectedMessage then
  968.           debug("Screen ",screen.side," received mid-run handshake")
  969.           transmit(screen.send,screen.receive, replyMessage, screen.legacy)
  970.         else
  971.           debug("Message received did not contain table")
  972.         end
  973.       end
  974.        
  975.       if rec then
  976.         rec.distance = math.floor(rec.distance)
  977.         rec.label = rec.label or "Quarry!"
  978.         screen.rec = rec --Set the table
  979.         --Updating screen occurs outside of the if
  980.         local toSend
  981.         if queuedMessage then
  982.           toSend = queuedMessage
  983.           queuedMessage = nil
  984.         else
  985.           toSend = replyMessage
  986.         end
  987.         transmit(screen.send,screen.receive, toSend, screen.legacy) --Send reply message for turtle
  988.       end
  989.      
  990.     end
  991.    
  992.     screen:updateDisplay() --isDone is queried inside this
  993.     screen:reset(screen.theme.background)
  994.     screen:pushScreenUpdates() --Actually write things to screen
  995.    
  996.  
  997.   ----KEY HANDLING----
  998.   elseif event == "key" and keyMap[par1] then
  999.     local key = par1
  1000.     if key ~= keys.enter then --If we aren't submitting a command
  1001.       if key == keys.backspace then
  1002.         if #commandString > 0 then
  1003.           commandString = commandString:sub(1,-2)
  1004.         end
  1005.       else
  1006.         commandString = commandString..keyMap[key]
  1007.       end
  1008.     else --If we are submitting a command
  1009.       local args = {}
  1010.       for a in commandString:gmatch("%S+") do
  1011.         args[#args+1] = a:lower()
  1012.       end
  1013.       local command = args[1]
  1014.       if validCommands[command] then --If it is a valid command...
  1015.         local commandType = validCommands[command]
  1016.         if commandType == 1 or commandType == 3 then --If the command requires a "side" like transmitting commands, versus setting a default
  1017.           if defaultSide then table.insert(args, 2, defaultSide) end
  1018.           local screen = screenClass.sides[args[2]]
  1019.           if screen then --If the side exists
  1020.             if command == "command" and screen.send then --If sending command to the turtle
  1021.               queuedMessage = table.concat(args," ", 3) --Tells message handler to send appropriate message
  1022.               --transmit(screen.send, screen.receive, table.concat(args," ", 3), screen.legacy) --This transmits all text in the command with spaces. Duh this is handled when we get message
  1023.             end
  1024.  
  1025.             if command == "color" then
  1026.               screen.theme:addColor(args[3],colors[args[4] or ""],colors[args[5] or ""])
  1027.               updateAllScreens() --Because we are changing a theme color which others may have
  1028.             end
  1029.             if command == "theme" then
  1030.               screen:setTheme(args[3])
  1031.             end
  1032.             if command == "send" then --This changes a send channel, and can also revert to handshake
  1033.               local chan = checkChannel(tonumber(args[3]) or -1)
  1034.               if chan then screen.send = chan else screen.send = nil end
  1035.               screen:setSize() --If on handshake, resets screen
  1036.             end
  1037.             if command == "receive" and not screen.isStation then
  1038.               local chan = checkChannel(tonumber(args[3]) or -1)
  1039.               if chan and not screenClass.channels[chan] then
  1040.                 if screen.receive then --Computer may not have a channel yet
  1041.                   modem.close(screen.receive)
  1042.                   screenClass.channels[screen.receive] = nil
  1043.                 end
  1044.                 modem.open(chan)
  1045.                 screen.receive = chan
  1046.                 screenClass.channels[chan] = screen
  1047.                 screen:setSize() --Update broken status
  1048.               end
  1049.             end
  1050.            
  1051.             if command == "remove" and screen.side ~= "computer" then --We don't want to remove the main display!
  1052.               print()
  1053.               screen:remove()
  1054.             else --Because if removed it does stupid things
  1055.               screen:reset()
  1056.               screen:updateDisplay()
  1057.               screen:pushScreenUpdates()
  1058.             end
  1059.           end
  1060.         end
  1061.         if commandType == 2 or commandType == 3 then--Does not require a screen side
  1062.           if command == "screen" and peripheral.getType(args[2]) == "monitor" then  --Makes sure there is a monitor on the screen side
  1063.             if not args[3] or not screenClass.channels[tonumber(args[3])] then --Make sure the channel doesn't already exist
  1064.               local mon = screenClass.new(args[2], args[3], args[4])
  1065.                 --args[3] is the channel  and will set broken display if it doesn't exist
  1066.                 --args[4] is the theme, and will default if doesn't exists.
  1067.               mon:updateDisplay()
  1068.               mon:reset()
  1069.               mon:pushScreenUpdates()
  1070.             end
  1071.           end
  1072.           if command == "theme" then
  1073.             screenClass:setTheme(args[2], true) --Otherwise this would set base theme to nil, erroring
  1074.             updateAllScreens()
  1075.           end
  1076.           if command == "color" and themes[args[2]] then
  1077.             themes[args[2]]:addColor(args[3],colors[args[4]],colors[args[5]])
  1078.             updateAllScreens() --Because any screen could have this theme
  1079.           end
  1080.           if command == "side" then
  1081.             if screenClass.sides[args[2]] then
  1082.               defaultSide = args[2]
  1083.             else
  1084.               defaultSide = nil
  1085.             end
  1086.           end
  1087.           if command == "set" then
  1088.             if args[2] then
  1089.               defaultCommand = table.concat(args," ",2)
  1090.               defaultCommand = defaultCommand:upper()
  1091.             else
  1092.               defaultCommand = nil
  1093.             end
  1094.           end
  1095.           if command == "savetheme" then
  1096.             if saveTheme(themes[args[2]], args[3]) then
  1097.               computer:tryAddRaw(computer.dim[2]-1, "Save Theme Succeeded!", computer.theme.inverse, true)
  1098.             else
  1099.               computer:tryAddRaw(computer.dim[2]-1, "Save Theme Failed!", computer.theme.inverse, true)
  1100.             end
  1101.             computer:reset()
  1102.             computer:pushScreenUpdates()
  1103.             sleep(1)
  1104.           end
  1105.           if command == "auto" then
  1106.             autoDetect()
  1107.             updateAllScreens()
  1108.           end
  1109.           if command == "quit" or command == "exit" or command == "end" then
  1110.             continue = false
  1111.           end
  1112.         end
  1113.       else
  1114.         debug("\nInvalid Command")
  1115.       end
  1116.       if defaultCommand then commandString = defaultCommand.." " else commandString = "" end --Reset command string because it was sent
  1117.     end
  1118.    
  1119.    
  1120.     --Update computer display (computer is only one that displays command string
  1121.     computer:updateDisplay() --Note: Computer's method automatically adds commandString to last line
  1122.     if not continue then computer:tryAddRaw(computer.dim[2]-1,"Program Exiting", computer.theme.inverse, false, true, true) end
  1123.     computer:reset()
  1124.     computer:pushScreenUpdates()
  1125.    
  1126.   elseif event == "monitor_resize" then
  1127.     local screen = screenClass.sides[par1]
  1128.     if screen then
  1129.       screen:setSize()
  1130.       screen:updateDisplay()
  1131.       screen:reset()
  1132.       screen:pushScreenUpdates()
  1133.     end
  1134.   elseif event == "monitor_touch" then
  1135.     local screen = screenClass.sides[par1]
  1136.     debug("Side: ",par1," touched")
  1137.     if screen then --This part is copied from the "side" command
  1138.       if defaultSide ~= par1 then
  1139.         defaultSide = par1
  1140.       else
  1141.         defaultSide = nil
  1142.       end
  1143.     else
  1144.       debug("Adding Screen")
  1145.       local mon = screenClass.new(par1)
  1146.       mon:reset()
  1147.       mon:updateDisplay()
  1148.       mon:pushScreenUpdates()
  1149.      
  1150.     end
  1151.  
  1152.   elseif event == "peripheral_detach" then
  1153.     local screen = screenClass.sides[par1]
  1154.     if screen then
  1155.       screen:setSize()
  1156.     end
  1157.     --if screen then
  1158.     --  screen:remove()
  1159.     --end
  1160.    
  1161.   elseif event == "peripheral" then
  1162.     local screen = screenClass.sides[par1]
  1163.     if screen then
  1164.       screen:setSize()
  1165.     end
  1166.     --Maybe prompt to add a new screen? I don't know
  1167.  
  1168.   end
  1169.  
  1170.   local flag = false --Saying all screens are done, must disprove
  1171.   local count = 0 --We want it to wait if no screens have channels
  1172.   for a,b in pairs(screenClass.channels) do
  1173.     count = count + 1
  1174.     if not b.isDone then
  1175.       flag = true
  1176.     end
  1177.   end
  1178.   if continue and count > 0 then --If its not already false from something else
  1179.     continue = flag
  1180.   end
  1181.  
  1182.   if computer.isStation and event ~= "key" then --So screen is properly updated
  1183.     computer:reset()
  1184.     computer:updateDisplay()
  1185.     computer:pushScreenUpdates()
  1186.   end
  1187.  
  1188.  
  1189. end
  1190.  
  1191. sleep(1.5)
  1192. for a in pairs(screenClass.channels) do
  1193.   modem.close(a)
  1194. end
  1195. for a, b in pairs(screenClass.sides) do
  1196.   if not b.isDone then --Otherwise we want it display the ending stats
  1197.     b:setTextColor(colors.white)
  1198.     b:setBackgroundColor(colors.black)
  1199.     b.term.clear()
  1200.     b.term.setCursorPos(1,1)
  1201.   end
  1202. end
  1203.  
  1204. local text --Fun :D
  1205. if computer.isComputer then text = "SUPER COMPUTER OS 9000"
  1206. elseif computer.isTurtle then text = "SUPER DIAMOND-MINING OS XXX"
  1207. elseif computer.isPocket then text = "PoCkEt OOS AMAYZE 65"
  1208. end
  1209. if text and not computer.isDone then
  1210.   computer:say(text, computer.theme.title,1)
  1211. else
  1212.   computer.term.setCursorPos(1,computer.dim[2])
  1213.   computer.term.clearLine()
  1214. end
  1215. --Down here shut down all the channels, remove the saved file, other cleanup stuff
  1216.  
Add Comment
Please, Sign In to add comment